string: Check for "nonstring" attribute on strscpy() arguments
Subsystems (2)
Kees Cook
maintainerPATCH 1/1 string: Check for "nonstring" attribute on strscpy() arguments
GCC already checks for arguments that are marked with the "nonstring"[1] attribute when used on standard C String API functions (e.g. strcpy). Gain this compile-time checking also for the kernel's primary string copying function, strscpy().
Note that Clang has neither "nonstring" nor __builtin_has_attribute().
---
Cc: Andy Shevchenko <[email protected]>
Cc: Justin Stitt <[email protected]>
Cc: Luc Van Oostenryck <[email protected]>
Cc: Nick Desaulniers <[email protected]>
Cc: Miguel Ojeda <[email protected]>
Cc: Marco Elver <[email protected]>
Cc: Nathan Chancellor <[email protected]>
Cc: Hao Luo <[email protected]>
Cc: Przemek Kitszel <[email protected]>
Cc: [email protected]
Cc: [email protected]
--- include/linux/compiler.h | 3 +++ include/linux/compiler_types.h | 7 +++++++ include/linux/string.h | 12 ++++++++---- 3 files changed, 18 insertions(+), 4 deletions(-)
include/linux/compiler.h +3 -0
@@ -242,6 +242,9 @@ static inline void *offset_to_ptr(const int *off)/* &a[0] degrades to a pointer: a different type from an array */ #define __must_be_array (a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) +/* Require C Strings (i.e. NUL-terminated) lack the "nonstring" attribute. */ +#define __must_be_cstr (p) BUILD_BUG_ON_ZERO(__annotated(p, nonstring)) +/* * This returns a constant expression while determining if an argument is * a constant expression, most importantly without evaluating the argument.
include/linux/compiler_types.h +7 -0
@@ -421,6 +421,13 @@ struct ftrace_likely_data {#define __member_size (p) __builtin_object_size(p, 1)#endif +/* Determine if an attribute has been applied to a variable. */ +#if __has_builtin (__builtin_has_attribute) +#define __annotated (var, attr) __builtin_has_attribute(var, attr) +#else +#define __annotated (var, attr) (false) +#endif +/* * Some versions of gcc do not mark 'asm goto' volatile: *
include/linux/string.h +8 -4
@@ -76,12 +76,16 @@ ssize_t sized_strscpy(char *, const char *, size_t);* known size. */ #define __strscpy0 (dst, src, ...) \ - sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy1 (dst, src, size) sized_strscpy(dst, src, size) + sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst) + \ + __must_be_cstr(dst) + __must_be_cstr(src)) +#define __strscpy1 (dst, src, size) \ + sized_strscpy(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))#define __strscpy_pad0 (dst, src, ...) \ - sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy_pad1 (dst, src, size) sized_strscpy_pad(dst, src, size) + sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst) + \ + __must_be_cstr(dst) + __must_be_cstr(src)) +#define __strscpy_pad1 (dst, src, size) \ + sized_strscpy_pad(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))/** * strscpy - Copy a C-string into a sized buffer
Signature · 1 line
2.34.1
Quoted 24 lines · Kees Cook
GCC already checks for arguments that are marked with the "nonstring"[1] attribute when used on standard C String API functions (e.g. strcpy). Gain this compile-time checking also for the kernel's primary string copying function,
strscpy().Note that Clang has neither "nonstring" nor
__builtin_has_attribute().Signed-off-by Kees Cook <[email protected]>include/linux/string.h +2
-2@@ -76,12 +76,16 @@ ssize_t sized_strscpy(char *, const char *, size_t);* known size. */ #define __strscpy0 (dst, src, ...) \ - sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy1 (dst, src, size) sized_strscpy(dst, src, size) + sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst) + \ + __must_be_cstr(dst) + __must_be_cstr(src))
include/linux/string.h ssize_t sized_strscpy(char *, const char *, size_t); · line 88
Quoted 10 lines
include/linux/string.h +6
-2+#define __strscpy1 (dst, src, size) \ + sized_strscpy(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))#define __strscpy_pad0 (dst, src, ...) \ - sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy_pad1 (dst, src, size) sized_strscpy_pad(dst, src, size) + sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst) + \ + __must_be_cstr(dst) + __must_be_cstr(src)) +#define __strscpy_pad1 (dst, src, size) \ + sized_strscpy_pad(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))
any way to avoid the usual caveat of repeating macro argument?
a variant of BUILD_BUG that is checking argument and otherwise pasting it would nail it, but I didn't pondered how to implement such
Kees Cook
maintainerQuoted 37 lines · Przemek Kitszel
Quoted 23 lines · Kees Cook
GCC already checks for arguments that are marked with the "nonstring"[1] attribute when used on standard C String API functions (e.g. strcpy). Gain this compile-time checking also for the kernel's primary string copying function,
strscpy().Note that Clang has neither "nonstring" nor
__builtin_has_attribute().Signed-off-by Kees Cook <[email protected]>include/linux/string.h +1
-2@@ -76,12 +76,16 @@ ssize_t sized_strscpy(char *, const char *, size_t);* known size. */ #define __strscpy0 (dst, src, ...) \ - sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy1 (dst, src, size) sized_strscpy(dst, src, size) + sized_strscpy(dst, src, sizeof(dst) + __must_be_array(dst) + \include/linux/string.h ssize_t sized_strscpy(char *, const char *, size_t); · line 87
Quoted 10 lines
include/linux/string.h +7
-2+ __must_be_cstr(dst) + __must_be_cstr(src)) +#define __strscpy1 (dst, src, size) \ + sized_strscpy(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))#define __strscpy_pad0 (dst, src, ...) \ - sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst)) -#define __strscpy_pad1 (dst, src, size) sized_strscpy_pad(dst, src, size) + sized_strscpy_pad(dst, src, sizeof(dst) + __must_be_array(dst) + \ + __must_be_cstr(dst) + __must_be_cstr(src)) +#define __strscpy_pad1 (dst, src, size) \ + sized_strscpy_pad(dst, src, size + __must_be_cstr(dst) + __must_be_cstr(src))any way to avoid the usual caveat of repeating macro argument?
Quoted 2 lines
a variant of
BUILD_BUGthat is checking argument and otherwise pasting it would nail it, but I didn't pondered how to implement such
The use of __must_be_cstr() shouldn't cause side-effects, so from what I can tell this is all okay. And since BUILD_BUG_ON_ZERO() resolves to a constant expression, it shouldn't change the processing of the "size" argument in the strscpy internals...
Signature · 1 line
Kees Cook
include/linux/compiler_types.h struct ftrace_likely_data { · line 429
Quoted 7 lines · Kees Cook
include/linux/compiler_types.h +6
-0+/* Determine if an attribute has been applied to a variable. */ +#if __has_builtin (__builtin_has_attribute) +#define __annotated (var, attr) __builtin_has_attribute(var, attr) +#else +#define __annotated (var, attr) (false) +#endif
__annotated is obviously best-effort given this definition, and we do similar things elsewhere, and it has a double-underscore. However, I wonder if this being a "query" (vs. something like an attribute) may imply that it has a greater risk of someone thinking it will always reply with the right answer... (if e.g. they copy-paste another use). Perhaps there is a more explicit name to let users recall that.
Anyway, it looks sensible to me: more compile-time checking seldomly hurts (apart from complexity in these definitions :). So:
I also introduced a mistake on purpose and I got the expected build error, so:
Cheers,
Miguel
Quoted 8 lines · Kees Cook
GCC already checks for arguments that are marked with the "nonstring"[1] attribute when used on standard C String API functions (e.g. strcpy). Gain this compile-time checking also for the kernel's primary string copying function,
strscpy().Note that Clang has neither "nonstring" nor
__builtin_has_attribute().[...]
Applied to for-next/hardening, thanks!
[1/1] string: Check for "nonstring" attribute on strscpy() arguments
https://git.kernel.org/kees/c/559048d156ff
Take care,
Signature · 1 line
Kees Cook