/* * Copyright (C) 2015-2016 Dimitris Papastamos * Copyright (C) 2022 q66 * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef _FORTIFY_STDIO_H #define _FORTIFY_STDIO_H #if !defined(__cplusplus) && !defined(__clang__) __extension__ #endif #include_next #if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE > 0 && defined(__OPTIMIZE__) && __OPTIMIZE__ > 0 #include "fortify-headers.h" #ifdef __cplusplus extern "C" { #endif #undef fgets #undef fopen #undef fread #undef fwrite #undef vsnprintf #undef vsprintf #if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \ || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \ || defined(_BSD_SOURCE) #undef fdopen #undef fmemopen #undef popen __fh_access(read_only, 2) #if __has_builtin(__builtin_fdopen) __diagnose_as_builtin(__builtin_fdopen, 1, 2) #endif _FORTIFY_FN(fdopen) FILE *fdopen(int __f, const char* _FORTIFY_POS0 __m) { return __orig_fdopen(__f, __m); } __fh_malloc(malloc (fclose, 1)) #if __has_builtin(__builtin_fmemopen) __diagnose_as_builtin(__builtin_fmemopen, 1, 2, 3) #endif _FORTIFY_FN(fmemopen) FILE *fmemopen(void* _FORTIFY_POS0 __b, size_t __s, const char* _FORTIFY_POS0 __m) { return __orig_fmemopen(__b, __s, __m); } __fh_access(read_only, 1) __fh_access(read_only, 2) __fh_malloc(malloc (pclose, 1)) #if __has_builtin(__builtin_popen) __diagnose_as_builtin(__builtin_popen, 1, 2) #endif _FORTIFY_FN(popen) FILE *popen(const char* _FORTIFY_POS0 __c, const char* _FORTIFY_POS0 __t) { return __orig_popen(__c, __t); } #endif /* _POSIX_SOURCE || _POSIX_C_SOURCE || _XOPEN_SOURCE || _GNU_SOURCE || _BSD_SOURCE */ __fh_access(write_only, 1, 2) #if __has_builtin(__builtin_fgets) __diagnose_as_builtin(__builtin_fgets, 1, 2, 3) #endif _FORTIFY_FN(fgets) char *fgets(char * _FORTIFY_POS0 __s, int __n, FILE *__f) { __fh_size_t __b = __fh_bos(__s, 0); if ((__fh_size_t)__n > __b) __builtin_trap(); return __orig_fgets(__s, __n, __f); } __fh_access(read_only, 1) __fh_access(read_only, 2) __fh_malloc(malloc (fclose, 1)) #if __has_builtin(__builtin_fopen) __diagnose_as_builtin(__builtin_fopen, 1, 2) #endif _FORTIFY_FN(fopen) FILE *fopen(const char* _FORTIFY_POS0 __p, const char* _FORTIFY_POS0 __m) { return __orig_fopen(__p, __m); } __fh_access(write_only, 1) #if __has_builtin(__builtin_fread) __diagnose_as_builtin(__builtin_fread, 1, 2, 3, 4) #endif _FORTIFY_FN(fread) size_t fread(void * _FORTIFY_POS0 __d, size_t __n, size_t __m, FILE *__f) { __fh_size_t __b = __fh_bos(__d, 0); if (__bmo(__n, __m)) __builtin_trap(); if (__n * __m > __b) __builtin_trap(); return __orig_fread(__d, __n, __m, __f); } __fh_access(read_only, 1) #if __has_builtin(__builtin_fwrite) __diagnose_as_builtin(__builtin_fwrite, 1, 2, 3, 4) #endif _FORTIFY_FN(fwrite) size_t fwrite(const void * _FORTIFY_POS0 __d, size_t __n, size_t __m, FILE *__f) { __fh_size_t __b = __fh_bos(__d, 0); if (__bmo(__n, __m)) __builtin_trap(); if (__n * __m > __b) __builtin_trap(); return __orig_fwrite(__d, __n, __m, __f); } #ifndef __clang__ /* FIXME */ #undef tmpfile __fh_malloc(malloc (fclose, 1)) #if __has_builtin(__builtin_tmpfile) __diagnose_as_builtin(__builtin_tmpfile) #endif _FORTIFY_FN(tmpfile) FILE *tmpfile(void) { return __orig_tmpfile(); } #endif __fh_access(write_only, 1, 2) __fh_access(read_only, 3) __fh_format(printf, 3, 0) #if __has_builtin(__builtin_vsnprintf) __diagnose_as_builtin(__builtin_vsnprintf, 1, 2, 3, 4) #endif _FORTIFY_FN(vsnprintf) int vsnprintf(char * _FORTIFY_POS0 __s, size_t __n, const char *__f, __builtin_va_list __v) { #if __has_builtin(__builtin___vsnprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___vsnprintf_chk(__s, __n, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __v); #else __fh_size_t __b = __fh_bos(__s, 0); if (__n > __b) __builtin_trap(); return __orig_vsnprintf(__s, __n, __f, __v); #endif } __fh_format(printf, 2, 0) __fh_access(write_only, 1) __fh_access(read_only, 2) #if __has_builtin(__builtin_vsprintf) __diagnose_as_builtin(__builtin_vsprintf, 1, 2, 3) #endif _FORTIFY_FN(vsprintf) int vsprintf(char * _FORTIFY_POS0 __s, const char *__f, __builtin_va_list __v) { #if __has_builtin(__builtin___vsprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___vsprintf_chk(__s, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __v); #else __fh_size_t __b = __fh_bos(__s, 0); int __r; if (__b != (__fh_size_t)-1) { __r = __orig_vsnprintf(__s, __b, __f, __v); if (__r != -1 && (__fh_size_t)__r >= __b) __builtin_trap(); } else { __r = __orig_vsprintf(__s, __f, __v); } return __r; #endif } #ifndef __clang__ /* FIXME */ #undef vfprintf #undef vprintf __fh_access(read_only, 2) __fh_format(printf, 2, 0) #if __has_builtin(__builtin_vfprintf) __diagnose_as_builtin(__builtin_vfprintf, 2, 3) #endif _FORTIFY_FN(vfprintf) int vfprintf(FILE * __s, const char *__f, __builtin_va_list __v) { #if __has_builtin(__builtin___vfprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___vfprintf_chk(__s, _FORTIFY_SOURCE, __f, __v); #else return __orig_vfprintf(__s, __f, __v); #endif } __fh_access(read_only, 1) __fh_format(printf, 1, 0) #if __has_builtin(__builtin_vprintf) __diagnose_as_builtin(__builtin_vprintf, 1, 2) #endif _FORTIFY_FN(vprintf) int vprintf(const char *__f, __builtin_va_list __v) { #if __has_builtin(__builtin___vprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___vprintf_chk(_FORTIFY_SOURCE, __f, __v); #else return __orig_vprintf(__f, __v); #endif } #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) #undef vasprintf #if __has_builtin(__builtin_vasprintf) __diagnose_as_builtin(__builtin_vasprintf, 1, 2, 3) #endif _FORTIFY_FN(vasprintf) int vasprintf(char **strp, const char *fmt, __builtin_va_list ap) { #if __has_builtin(__builtin___vasprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___vasprintf_chk(_FORTIFY_SOURCE, strp, fmt, ap); #else int ret = __orig_vasprintf(strp, fmt, ap); if (ret < 0) *strp = NULL; return ret; #endif } #endif // defined(_GNU_SOURCE) || defined(_BSD_SOURCE) #endif // __clang__ #if 0 #if __has_builtin(__builtin_va_arg_pack) /* clang is missing __builtin_va_arg_pack, so we cannot use these impls * outside of gcc; we then have a few options: * * 1) using va_start/end and implementing these functions as static inline, * with inlining never happening; that means extra symbols with internal * linkage, which is not ideal * 2) using macros; this is incompatible with c++ and since musl does not * have the __chk variants, we'd need to implement a body with intermediate * variables within the macro, which means more non-portable mess * 3) not implementing these under clang, which is what we do for now * * TODO: add __diagnose_as_builtin */ // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110834 #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #undef snprintf #undef sprintf #undef printf #undef fprintf __fh_access(write_only, 1, 2) __fh_access(read_only, 3) __fh_format(printf, 3, 4) _FORTIFY_FN(snprintf) int snprintf(char *__s, size_t __n, const char *__f, ...) { #if __has_builtin(__builtin___snprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___snprintf_chk(__s, __n, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __builtin_va_arg_pack()); #else __fh_size_t __b = __fh_bos(__s, 0); if (__n > __b) __builtin_trap(); return __orig_snprintf(__s, __n, __f, __builtin_va_arg_pack()); #endif } __fh_format(printf, 2, 3) //__fh_access(write_only, 1) __fh_access(read_only, 2) _FORTIFY_FN(sprintf) int sprintf(char *__s, const char *__f, ...) { #if __has_builtin(__builtin___sprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___sprintf_chk(__s, _FORTIFY_SOURCE, __fh_bos(__s, 0), __f, __builtin_va_arg_pack()); #else __fh_size_t __b = __fh_bos(__s, 0); int __r; if (__b == (__fh_size_t)-1) { return __orig_sprintf(__s, __f, __builtin_va_arg_pack()); } __r = __orig_snprintf(__s, __b, __f, __builtin_va_arg_pack()); if (__r != -1 && (__fh_size_t)__r >= __b) __builtin_trap(); return __r; #endif } __fh_format(printf, 1, 2) __fh_access(read_only, 1) _FORTIFY_FN(printf) int printf(const char *__f, ...) { #if __has_builtin(__builtin___printf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___printf_chk(_FORTIFY_SOURCE, __f, __builtin_va_arg_pack()); #else return __orig_printf(__f, __builtin_va_arg_pack()); #endif } __fh_access(read_only, 2) __fh_format(printf, 2, 0) #if __has_builtin(__builtin_fprintf) __diagnose_as_builtin(__builtin_fprintf, 2, 3) #endif _FORTIFY_FN(fprintf) int fprintf(FILE *__s, const char *__f, ...) { #if __has_builtin(__builtin___fprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___fprintf_chk(_FORTIFY_SOURCE, __s, __f, __builtin_va_arg_pack()); #else return __orig_fprintf(__s, __f, __builtin_va_arg_pack()); #endif } #if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) #ifndef __clang__ #undef asprintf __fh_access(read_only, 2) __fh_format(printf, 2, 0) #if __has_builtin(__builtin_asprintf) __diagnose_as_builtin(__builtin_asprintf, 2, 3) #endif _FORTIFY_FN(asprintf) int asprintf(char **strp, const char *fmt, ...) { #if __has_builtin(__builtin___asprintf_chk) && defined(FORTIFY_USE_NATIVE_CHK) return __builtin___asprintf_chk(_FORTIFY_SOURCE, strp, fmt, __builtin_va_arg_pack()); #else int ret = __orig_asprintf(strp, fmt, __builtin_va_arg_pack()); if (ret<0) *strp = NULL; return ret; #endif } #endif // __clang__ #endif #pragma GCC diagnostic pop #endif /* __has_builtin(__builtin_va_arg_pack) */ #endif #ifdef __cplusplus } #endif #endif #endif