Loading include/linux/fortify-string.h +46 −8 Original line number Diff line number Diff line Loading @@ -200,16 +200,55 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) return p; } __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, const size_t p_size, const size_t p_size_field) { size_t p_size = __builtin_object_size(p, 0); if (__builtin_constant_p(size)) { /* * Length argument is a constant expression, so we * can perform compile-time bounds checking where * buffer sizes are known. */ if (__builtin_constant_p(size) && p_size < size) /* Error when size is larger than enclosing struct. */ if (p_size > p_size_field && p_size < size) __write_overflow(); if (p_size < size) fortify_panic(__func__); return __underlying_memset(p, c, size); /* Warn when write size is larger than dest field. */ if (p_size_field < size) __write_overflow_field(p_size_field, size); } /* * At this point, length argument may not be a constant expression, * so run-time bounds checking can be done where buffer sizes are * known. (This is not an "else" because the above checks may only * be compile-time warnings, and we want to still warn for run-time * overflows.) */ /* * Always stop accesses beyond the struct that contains the * field, when the buffer's remaining size is known. * (The -1 test is to optimize away checks where the buffer * lengths are unknown.) */ if (p_size != (size_t)(-1) && p_size < size) fortify_panic("memset"); } #define __fortify_memset_chk(p, c, size, p_size, p_size_field) ({ \ size_t __fortify_size = (size_t)(size); \ fortify_memset_chk(__fortify_size, p_size, p_size_field), \ __underlying_memset(p, c, __fortify_size); \ }) /* * __builtin_object_size() must be captured here to avoid evaluating argument * side-effects further into the macro layers. */ #define memset(p, c, s) __fortify_memset_chk(p, c, s, \ __builtin_object_size(p, 0), __builtin_object_size(p, 1)) /* * To make sure the compiler can enforce protection against buffer overflows, Loading Loading @@ -401,7 +440,6 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q) /* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr #undef __underlying_memcmp #undef __underlying_memset #undef __underlying_strcat #undef __underlying_strcpy #undef __underlying_strlen Loading lib/test_fortify/write_overflow_field-memset.c 0 → 100644 +5 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only #define TEST \ memset(instance.buf, 0x42, sizeof(instance.buf) + 1) #include "test_fortify.h" Loading
include/linux/fortify-string.h +46 −8 Original line number Diff line number Diff line Loading @@ -200,16 +200,55 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) return p; } __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) __FORTIFY_INLINE void fortify_memset_chk(__kernel_size_t size, const size_t p_size, const size_t p_size_field) { size_t p_size = __builtin_object_size(p, 0); if (__builtin_constant_p(size)) { /* * Length argument is a constant expression, so we * can perform compile-time bounds checking where * buffer sizes are known. */ if (__builtin_constant_p(size) && p_size < size) /* Error when size is larger than enclosing struct. */ if (p_size > p_size_field && p_size < size) __write_overflow(); if (p_size < size) fortify_panic(__func__); return __underlying_memset(p, c, size); /* Warn when write size is larger than dest field. */ if (p_size_field < size) __write_overflow_field(p_size_field, size); } /* * At this point, length argument may not be a constant expression, * so run-time bounds checking can be done where buffer sizes are * known. (This is not an "else" because the above checks may only * be compile-time warnings, and we want to still warn for run-time * overflows.) */ /* * Always stop accesses beyond the struct that contains the * field, when the buffer's remaining size is known. * (The -1 test is to optimize away checks where the buffer * lengths are unknown.) */ if (p_size != (size_t)(-1) && p_size < size) fortify_panic("memset"); } #define __fortify_memset_chk(p, c, size, p_size, p_size_field) ({ \ size_t __fortify_size = (size_t)(size); \ fortify_memset_chk(__fortify_size, p_size, p_size_field), \ __underlying_memset(p, c, __fortify_size); \ }) /* * __builtin_object_size() must be captured here to avoid evaluating argument * side-effects further into the macro layers. */ #define memset(p, c, s) __fortify_memset_chk(p, c, s, \ __builtin_object_size(p, 0), __builtin_object_size(p, 1)) /* * To make sure the compiler can enforce protection against buffer overflows, Loading Loading @@ -401,7 +440,6 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q) /* Don't use these outside the FORITFY_SOURCE implementation */ #undef __underlying_memchr #undef __underlying_memcmp #undef __underlying_memset #undef __underlying_strcat #undef __underlying_strcpy #undef __underlying_strlen Loading
lib/test_fortify/write_overflow_field-memset.c 0 → 100644 +5 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only #define TEST \ memset(instance.buf, 0x42, sizeof(instance.buf) + 1) #include "test_fortify.h"