fortify-headers

standalone fortify-source implementation
git clone git://git.2f30.org/fortify-headers
Log | Files | Refs | README | LICENSE

fortify-headers.h (5686B)


      1 /*
      2  * Copyright (C) 2015-2016 Dimitris Papastamos <sin@2f30.org>
      3  * Copyright (C) 2022 q66 <q66@chimera-linux.org>
      4  *
      5  * Permission to use, copy, modify, and/or distribute this software for any
      6  * purpose with or without fee is hereby granted.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #ifndef _FORTIFY_HEADERS_H
     18 #define _FORTIFY_HEADERS_H
     19 
     20 #if !defined __has_builtin
     21 #error a compiler with __has_builtin support is required
     22 #endif
     23 
     24 // https://clang.llvm.org/docs/LanguageExtensions.html#has-builtin
     25 // > __has_builtin should not be used to detect support for a builtin macro; use #ifdef instead.
     26 #define __fh_has_builtin(x) (__has_builtin(x) || defined(x))
     27 
     28 #if ! __fh_has_builtin(__builtin_trap)
     29 #define __builtin_trap abort
     30 #endif
     31 
     32 #if _FORTIFY_SOURCE > 3
     33 #warning _FORTIFY_SOURCE > 3 is treated as 3
     34 #endif
     35 
     36 #ifdef __clang__
     37 
     38 #if _FORTIFY_SOURCE  > 2 && __fh_has_builtin (__builtin_dynamic_object_size) && __has_attribute(pass_dynamic_object_size)
     39 #define _FORTIFY_POSN(n) const __attribute__((pass_dynamic_object_size(n)))
     40 #else
     41 #define _FORTIFY_POSN(n) const __attribute__((pass_object_size(n)))
     42 #endif /* __builtin_dynamic_object_size && pass_dynamic_object_size */
     43 
     44 /* clang uses overloads; see https://github.com/llvm/llvm-project/issues/53516 */
     45 /* we can't use extern inline with overloads without making them external */
     46 #ifdef __cplusplus
     47 #define _FORTIFY_INLINE __inline__ \
     48         __attribute__((__always_inline__,__artificial__,__overloadable__))
     49 #else
     50 #define _FORTIFY_INLINE static __inline__ \
     51 	__attribute__((__always_inline__,__artificial__,__overloadable__))
     52 #endif
     53 
     54 #else /* !__clang__ */
     55 
     56 #define _FORTIFY_POSN(n)
     57 #define _FORTIFY_INLINE extern __inline__ \
     58 	__attribute__((__always_inline__,__gnu_inline__,__artificial__))
     59 
     60 #endif /* __clang__ */
     61 
     62 /* https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html */
     63 #define _FORTIFY_POS0 _FORTIFY_POSN(0)
     64 #define _FORTIFY_POS1 _FORTIFY_POSN(1)
     65 #define _FORTIFY_POS2 _FORTIFY_POSN(2)
     66 
     67 #define _FORTIFY_STR(s) #s
     68 #define _FORTIFY_ORIG(p,fn) __typeof__(fn) __orig_##fn __asm__(_FORTIFY_STR(p) #fn)
     69 #define _FORTIFY_FNB(fn) _FORTIFY_ORIG(__USER_LABEL_PREFIX__,fn)
     70 #define _FORTIFY_FN(fn) _FORTIFY_FNB(fn); _FORTIFY_INLINE
     71 
     72 /* Use __builtin_dynamic_object_size with _FORTIFY_SOURCE>2, if available.  */
     73 #if _FORTIFY_SOURCE  > 2 && __fh_has_builtin (__builtin_dynamic_object_size)
     74 /* 
     75  * See:
     76  * - https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html
     77  */
     78 #define __fh_bos(ptr, type) __builtin_dynamic_object_size (ptr, type)
     79 #else
     80 #define __fh_bos(ptr, type) __builtin_object_size (ptr, type)
     81 #endif
     82 
     83 #if defined __has_attribute
     84 #if __has_attribute (access)
     85 #define __fh_access(...) __attribute__ ((access (__VA_ARGS__)))
     86 #else
     87 #define __fh_access(...)
     88 #endif
     89 
     90 #if __has_attribute (format)
     91 #define __fh_format(...) __attribute__ ((format (__VA_ARGS__)))
     92 #else
     93 #define __fh_format(...)
     94 #endif
     95 
     96 #if __has_attribute (malloc)
     97 #ifdef __clang__
     98 #define __fh_malloc(...) __attribute__ ((malloc))
     99 #else
    100 #define __fh_malloc(...) __attribute__ ((malloc, __VA_ARGS__))
    101 #endif /* __clang__ */
    102 #else
    103 #define __fh_malloc(...)
    104 #endif
    105 
    106 #if __has_attribute (alloc_size) && !defined(__fh_alloc_size)
    107 #define __fh_alloc_size(...) __attribute__ ((alloc_size (__VA_ARGS__)))
    108 #else
    109 #define __fh_alloc_size(...)
    110 #endif
    111 
    112 #if __has_attribute (diagnose_as_builtin)
    113 #define __diagnose_as_builtin(...) __attribute__ ((diagnose_as_builtin (__VA_ARGS__)))
    114 #else
    115 #define __diagnose_as_builtin(...)
    116 #endif
    117 
    118 #if __has_attribute (diagnose_if)
    119 #define __warning_if(cond, msg) __attribute__ ((diagnose_if (cond, msg, "warning")))
    120 #define __error_if(cond, msg) __attribute__ ((diagnose_if (cond, msg, "error")))
    121 #else
    122 #define __warning_if(cond, msg)
    123 #define __error_if(cond, msg)
    124 #endif
    125 
    126 #if __has_attribute (warn_unused_result)
    127 #define __warn_unused_result __attribute__ ((warn_unused_result))
    128 #else
    129 #define __warn_unused_result
    130 #endif
    131 
    132 
    133 #endif /* __has_attribute */
    134 
    135 // Since we're not allow to include anything.
    136 // https://awesomekling.github.io/How-SerenityOS-declares-ssize_t/
    137 #define __fh_size_t __typeof__(sizeof(char))
    138 
    139 //TODO(jvoisin) Add a check for overflows
    140 /* check if pointers are overlapping but not if dst == src,
    141  * since gcc seems to like to generate code that relies on dst == src */
    142 #define __fh_overlap(a, len_a, b, len_b) \
    143 	( \
    144 		((char*)(a) < (char*)(b) && (char*)(b) < ((char*)(a) + (__fh_size_t)(len_a))) \
    145 	     || ((char*)(b) < (char*)(a) && (char*)(a) < ((char*)(b) + (__fh_size_t)(len_b))) \
    146         )
    147 
    148 /*
    149  * We're not making use of C23's <stdckdint.h> since:
    150  *   - there is no elegant way to make it ignore the results.
    151  *   - it's tricky to make it type-agnostic when we don't care about the result.
    152  * We're not making use of __builtin_mul_overflow for the same reasons.
    153  *
    154  * See:
    155  * - https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html
    156  * - https://clang.llvm.org/docs/LanguageExtensions.html#checked-arithmetic-builtins
    157  */
    158 #if __fh_has_builtin (__builtin_mul_overflow_p)
    159 #define __bmo(x, y) (x != 0 && __builtin_mul_overflow_p(x, y, (__typeof__ ((x) + (y))) 0))
    160 #else /* !__builtin_mul_overflow_p */
    161 #define __bmo(x, y) (x != 0 && (x * y) / x != y)
    162 #endif /* __builtin_mul_overflow_p */
    163 
    164 #endif /* _FORTIFY_HEADERS_H */