Message ID | 20220202003033.704951-5-keescook@chromium.org (mailing list archive) |
---|---|
State | Superseded |
Commit | 0b27a15c23f17d6ca9a01505f38b477178fabb52 |
Headers | show |
Series | fortify: Add Clang support | expand |
On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > --- a/security/Kconfig > +++ b/security/Kconfig > @@ -179,7 +179,7 @@ config FORTIFY_SOURCE > depends on ARCH_HAS_FORTIFY_SOURCE > # https://bugs.llvm.org/show_bug.cgi?id=50322 > # https://bugs.llvm.org/show_bug.cgi?id=41459 > - depends on !CC_IS_CLANG > + depends on !CC_IS_CLANG || CLANG_VERSION >= 130000 Are these comments still relevant, and is the clang version still correct? In https://lore.kernel.org/llvm/CANiq72n1d7ouKNi+pbsy7chsg0DfCXxez27qqtS9XE1n3m5=8Q@mail.gmail.com/ Miguel notes that diagnose_as only exists in clang-14+. If this series relies on diagnose_as, then should this version check be for clang-14+ rather than clang-13+? https://bugs.llvm.org/show_bug.cgi?id=50322 is still open, but doesn't signify why there's a version check. It makes sense if there's no version check, but I'm not sure it's still relevant to this Kconfig option after your series. https://bugs.llvm.org/show_bug.cgi?id=41459 was fixed in clang-13, but it was also backported to the clang 12.0.1 release. Is it still relevant if we're gated on diagnose_as from clang-14? Perhaps a single comment, about the diagnose_as attribute or a link to https://reviews.llvm.org/rGbc5f2d12cadce765620efc56a1ca815221db47af or whatever, and updating the version check to be against clang-14 would be more precise?
On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > +#define BOS const __pass_object_size(1) > +#define BOS0 const __pass_object_size(0) A dumb bikeshed, but would you mind naming these BOS1 and BOS0, and perhaps consider adding a comment or pointer or link to something that describes why we use the two different modes? I recognize that the code already uses the two different modes already without comments, but this might be a nice place to point folks like myself to so that in a month or so when I forget what the difference is between modes (again), we have a shorter trail of breadcrumbs.
On Wed, Feb 02, 2022 at 01:22:09PM -0800, Nick Desaulniers wrote: > On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > > > --- a/security/Kconfig > > +++ b/security/Kconfig > > @@ -179,7 +179,7 @@ config FORTIFY_SOURCE > > depends on ARCH_HAS_FORTIFY_SOURCE > > # https://bugs.llvm.org/show_bug.cgi?id=50322 > > # https://bugs.llvm.org/show_bug.cgi?id=41459 > > - depends on !CC_IS_CLANG > > + depends on !CC_IS_CLANG || CLANG_VERSION >= 130000 > > Are these comments still relevant, and is the clang version still correct? Oh, good call. I thought the version was still correct (more below), but yes, the comments need adjusting. > In https://lore.kernel.org/llvm/CANiq72n1d7ouKNi+pbsy7chsg0DfCXxez27qqtS9XE1n3m5=8Q@mail.gmail.com/ > Miguel notes that diagnose_as only exists in clang-14+. If this > series relies on diagnose_as, then should this version check be for > clang-14+ rather than clang-13+? It doesn't rely on it; this is just taking advantage of an improvement. > https://bugs.llvm.org/show_bug.cgi?id=50322 is still open, but doesn't > signify why there's a version check. It makes sense if there's no > version check, but I'm not sure it's still relevant to this Kconfig > option after your series. With __overloadable, this probably ended up going away. > https://bugs.llvm.org/show_bug.cgi?id=41459 was fixed in clang-13, but > it was also backported to the clang 12.0.1 release. Is it still > relevant if we're gated on diagnose_as from clang-14? Ah-ha! I missed that this got backported. Looks like 12.0.1 and later have this fixed. That's excellent! > Perhaps a single comment, about the diagnose_as attribute or a link to > https://reviews.llvm.org/rGbc5f2d12cadce765620efc56a1ca815221db47af or > whatever, and updating the version check to be against clang-14 would > be more precise? Yup, I will rework this after double-checking 12.0.1 builds. Thanks!
On Wed, Feb 02, 2022 at 01:27:11PM -0800, Nick Desaulniers wrote: > On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > > > +#define BOS const __pass_object_size(1) > > +#define BOS0 const __pass_object_size(0) > > A dumb bikeshed, but would you mind naming these BOS1 and BOS0, and > perhaps consider adding a comment or pointer or link to something that > describes why we use the two different modes? I recognize that the > code already uses the two different modes already without comments, > but this might be a nice place to point folks like myself to so that > in a month or so when I forget what the difference is between modes > (again), we have a shorter trail of breadcrumbs. Sure, I can do that. My expectation was to entirely eliminate mode 0 usage in the future. Though now that things are so close, I'll just do some builds with the last few users switched over. But maybe memcmp() was a pain? I'll go check...
On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h > index c45159dbdaa1..5482536d3197 100644 > --- a/include/linux/fortify-string.h > +++ b/include/linux/fortify-string.h > @@ -2,7 +2,9 @@ > #ifndef _LINUX_FORTIFY_STRING_H_ > #define _LINUX_FORTIFY_STRING_H_ > > -#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) > +#include <linux/const.h> > + > +#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) __overloadable Sorry, I just noticed this line (already) uses a mix of open coding __attribute__ and not. Would you mind also please changing the open coded gnu_inline to simply __gnu_inline to make the entire line consistent?
On Thu, Feb 3, 2022 at 11:13 PM Nick Desaulniers <ndesaulniers@google.com> wrote: > > Sorry, I just noticed this line (already) uses a mix of open coding > __attribute__ and not. Would you mind also please changing the open > coded gnu_inline to simply __gnu_inline to make the entire line > consistent? +1 Cheers, Miguel
On Thu, Feb 03, 2022 at 02:13:33PM -0800, Nick Desaulniers wrote: > On Tue, Feb 1, 2022 at 4:30 PM Kees Cook <keescook@chromium.org> wrote: > > > > diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h > > index c45159dbdaa1..5482536d3197 100644 > > --- a/include/linux/fortify-string.h > > +++ b/include/linux/fortify-string.h > > @@ -2,7 +2,9 @@ > > #ifndef _LINUX_FORTIFY_STRING_H_ > > #define _LINUX_FORTIFY_STRING_H_ > > > > -#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) > > +#include <linux/const.h> > > + > > +#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) __overloadable > > Sorry, I just noticed this line (already) uses a mix of open coding > __attribute__ and not. Would you mind also please changing the open > coded gnu_inline to simply __gnu_inline to make the entire line > consistent? Ah yeah, thanks. Fixed.
diff --git a/include/linux/fortify-string.h b/include/linux/fortify-string.h index c45159dbdaa1..5482536d3197 100644 --- a/include/linux/fortify-string.h +++ b/include/linux/fortify-string.h @@ -2,7 +2,9 @@ #ifndef _LINUX_FORTIFY_STRING_H_ #define _LINUX_FORTIFY_STRING_H_ -#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) +#include <linux/const.h> + +#define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) __overloadable #define __RENAME(x) __asm__(#x) void fortify_panic(const char *name) __noreturn __cold; @@ -50,7 +52,11 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) #define __underlying_strncpy __builtin_strncpy #endif -__FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) +#define BOS const __pass_object_size(1) +#define BOS0 const __pass_object_size(0) + +__FORTIFY_INLINE __diagnose_as(__builtin_strncpy, 1, 2, 3) +char *strncpy(char * BOS p, const char *q, __kernel_size_t size) { size_t p_size = __builtin_object_size(p, 1); @@ -61,7 +67,8 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) return __underlying_strncpy(p, q, size); } -__FORTIFY_INLINE char *strcat(char *p, const char *q) +__FORTIFY_INLINE __diagnose_as(__builtin_strcat, 1, 2) +char *strcat(char * BOS p, const char *q) { size_t p_size = __builtin_object_size(p, 1); @@ -73,7 +80,7 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q) } extern __kernel_size_t __real_strnlen(const char *, __kernel_size_t) __RENAME(strnlen); -__FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) +__FORTIFY_INLINE __kernel_size_t strnlen(const char * BOS p, __kernel_size_t maxlen) { size_t p_size = __builtin_object_size(p, 1); size_t p_len = __compiletime_strlen(p); @@ -93,8 +100,16 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) return ret; } -/* defined after fortified strnlen to reuse it. */ -__FORTIFY_INLINE __kernel_size_t strlen(const char *p) +/* + * Defined after fortified strnlen to reuse it. However, it must still be + * possible for strlen() to be used on compile-time strings for use in + * static initializers (i.e. as a constant expression). + */ +#define strlen(p) \ + __builtin_choose_expr(__is_constexpr(__builtin_strlen(p)), \ + __builtin_strlen(p), __fortify_strlen(p)) +__FORTIFY_INLINE __diagnose_as(__builtin_strlen, 1) +__kernel_size_t __fortify_strlen(const char * BOS p) { __kernel_size_t ret; size_t p_size = __builtin_object_size(p, 1); @@ -110,7 +125,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) /* defined after fortified strlen to reuse it */ extern size_t __real_strlcpy(char *, const char *, size_t) __RENAME(strlcpy); -__FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) +__FORTIFY_INLINE size_t strlcpy(char * BOS p, const char * BOS q, size_t size) { size_t p_size = __builtin_object_size(p, 1); size_t q_size = __builtin_object_size(q, 1); @@ -137,7 +152,7 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) /* defined after fortified strnlen to reuse it */ extern ssize_t __real_strscpy(char *, const char *, size_t) __RENAME(strscpy); -__FORTIFY_INLINE ssize_t strscpy(char *p, const char *q, size_t size) +__FORTIFY_INLINE ssize_t strscpy(char * BOS p, const char * BOS q, size_t size) { size_t len; /* Use string size rather than possible enclosing struct size. */ @@ -183,7 +198,8 @@ __FORTIFY_INLINE ssize_t strscpy(char *p, const char *q, size_t size) } /* defined after fortified strlen and strnlen to reuse them */ -__FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) +__FORTIFY_INLINE __diagnose_as(__builtin_strncat, 1, 2, 3) +char *strncat(char * BOS p, const char * BOS q, __kernel_size_t count) { size_t p_len, copy_len; size_t p_size = __builtin_object_size(p, 1); @@ -354,7 +370,7 @@ __FORTIFY_INLINE void fortify_memcpy_chk(__kernel_size_t size, memmove) extern void *__real_memscan(void *, int, __kernel_size_t) __RENAME(memscan); -__FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size) +__FORTIFY_INLINE void *memscan(void * BOS0 p, int c, __kernel_size_t size) { size_t p_size = __builtin_object_size(p, 0); @@ -365,7 +381,8 @@ __FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size) return __real_memscan(p, c, size); } -__FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) +__FORTIFY_INLINE __diagnose_as(__builtin_memcmp, 1, 2, 3) +int memcmp(const void * BOS0 p, const void * BOS0 q, __kernel_size_t size) { size_t p_size = __builtin_object_size(p, 0); size_t q_size = __builtin_object_size(q, 0); @@ -381,7 +398,8 @@ __FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) return __underlying_memcmp(p, q, size); } -__FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) +__FORTIFY_INLINE __diagnose_as(__builtin_memchr, 1, 2, 3) +void *memchr(const void * BOS0 p, int c, __kernel_size_t size) { size_t p_size = __builtin_object_size(p, 0); @@ -393,7 +411,7 @@ __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) } void *__real_memchr_inv(const void *s, int c, size_t n) __RENAME(memchr_inv); -__FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size) +__FORTIFY_INLINE void *memchr_inv(const void * BOS0 p, int c, size_t size) { size_t p_size = __builtin_object_size(p, 0); @@ -405,7 +423,7 @@ __FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size) } extern void *__real_kmemdup(const void *src, size_t len, gfp_t gfp) __RENAME(kmemdup); -__FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) +__FORTIFY_INLINE void *kmemdup(const void * BOS0 p, size_t size, gfp_t gfp) { size_t p_size = __builtin_object_size(p, 0); @@ -417,7 +435,8 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) } /* Defined after fortified strlen to reuse it. */ -__FORTIFY_INLINE char *strcpy(char *p, const char *q) +__FORTIFY_INLINE __diagnose_as(__builtin_strcpy, 1, 2) +char *strcpy(char * BOS p, const char * BOS q) { size_t p_size = __builtin_object_size(p, 1); size_t q_size = __builtin_object_size(q, 1); @@ -446,4 +465,7 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q) #undef __underlying_strncat #undef __underlying_strncpy +#undef BOS0 +#undef BOS + #endif /* _LINUX_FORTIFY_STRING_H_ */ diff --git a/security/Kconfig b/security/Kconfig index 0b847f435beb..1a25a567965f 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -179,7 +179,7 @@ config FORTIFY_SOURCE depends on ARCH_HAS_FORTIFY_SOURCE # https://bugs.llvm.org/show_bug.cgi?id=50322 # https://bugs.llvm.org/show_bug.cgi?id=41459 - depends on !CC_IS_CLANG + depends on !CC_IS_CLANG || CLANG_VERSION >= 130000 help Detect overflows of buffers in common string and memory functions where the compiler can determine and validate the buffer sizes.
Enable FORTIFY_SOURCE support for Clang: Use the new __pass_object_size and __overloadable attributes so that Clang will have appropriate visibility into argument types such that __builtin_object_size(p, 1) will behave correctly. Additional details here: https://github.com/llvm/llvm-project/issues/53516 https://github.com/ClangBuiltLinux/linux/issues/1401 Use the new __diagnose_as attribute to make sure no compile-time diagnostic warnings are lost due to the effectively renamed string functions. Redefine strlen() as a macro that tests for being a constant expression so that strlen() can still be used in static initializers, which was lost when adding __pass_object_size and __overloadable. Finally, a bug with __builtin_constant_p() of globally defined variables was fixed in Clang 13, so FORTIFY support must depend on that version or later. Additional details here: https://bugs.llvm.org/show_bug.cgi?id=41459 commit a52f8a59aef4 ("fortify: Explicitly disable Clang support") Cc: Miguel Ojeda <ojeda@kernel.org> Cc: Nick Desaulniers <ndesaulniers@google.com> Cc: Nathan Chancellor <nathan@kernel.org> Cc: George Burgess IV <gbiv@google.com> Cc: llvm@lists.linux.dev Signed-off-by: Kees Cook <keescook@chromium.org> --- include/linux/fortify-string.h | 52 ++++++++++++++++++++++++---------- security/Kconfig | 2 +- 2 files changed, 38 insertions(+), 16 deletions(-)