From 6bbaac1165529625b0f87dfab34240062121299a Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 26 Jul 2016 22:41:43 +0200 Subject: initify: Mark functions with the __nocapture attribute The nocapture gcc attribute can be on functions only. The attribute takes zero or more signed integer constants as parameters that specify the function parameters to initify when the passed arguments are of const char* type. A negative attribute parameter value means that the corresponding function parameter is returned by the function and the passed argument will only be initified if the data flow of the returned value is not captured in the caller. If no values are passed to the attribute then all function parameters are treated as nocapture. If the marked parameter is a vararg then the plugin initifies all vararg arguments. Signed-off-by: Emese Revfy [kees: updated markings, thanks to Arnd] Signed-off-by: Kees Cook --- lib/string.c | 3 ++- lib/vsprintf.c | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/string.c b/lib/string.c index ed83562a53ae..b3c22a285a78 100644 --- a/lib/string.c +++ b/lib/string.c @@ -870,7 +870,8 @@ void *memchr(const void *s, int c, size_t n) EXPORT_SYMBOL(memchr); #endif -static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) +static __nocapture(1) +void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) { while (bytes) { if (*start != value) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0967771d8f7f..a192761d338a 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -118,7 +118,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) } EXPORT_SYMBOL(simple_strtoll); -static noinline_for_stack +static noinline_for_stack __nocapture(1) int skip_atoi(const char **s) { int i = 0; @@ -1570,7 +1570,7 @@ int kptr_restrict __read_mostly; * function pointers are really function descriptors, which contain a * pointer to the real address. */ -static noinline_for_stack +static noinline_for_stack __nocapture(1) char *pointer(const char *fmt, char *buf, char *end, void *ptr, struct printf_spec spec) { @@ -1749,7 +1749,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, * @precision: precision of a number * @qualifier: qualifier of a number (long, size_t, ...) */ -static noinline_for_stack +static noinline_for_stack __nocapture(1) int format_decode(const char *fmt, struct printf_spec *spec) { const char *start = fmt; -- cgit v1.2.3 From 968375b64840da571ecdbeb61e1da087a4f85e1c Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Tue, 26 Jul 2016 22:43:27 +0200 Subject: initify: Mark functions with the __unverified_nocapture attribute The initify plugin attempts to analyze function arguments that have been marked correctly with the __nocapture attribute. However, due to code complexity, this is not always possible to verify. As a result, some __nocapture attributes need to be marked as excluded from the automatic verification. To do this, the __unverified_nocapture attribute is added. It is intedned to only be used on function parameters that are difficult for the plugin to analyze. Signed-off-by: Emese Revfy [kees: updated markings, thanks to Arnd] Signed-off-by: Kees Cook --- include/linux/compiler-gcc.h | 8 ++++++++ include/linux/compiler.h | 4 ++++ include/linux/string.h | 2 +- lib/vsprintf.c | 4 ++-- mm/kasan/kasan.c | 2 ++ 5 files changed, 17 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index cd4e9ffb00a7..fc0495e849ff 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -204,9 +204,17 @@ * been unmapped from memory. In order to identify functions that are confirmed * to not capture their arguments, the __nocapture() attribute is used so that * initify can better identify candidate variables. + * + * Arguments marked in this way are verified by the plugin, but sometimes + * code complexity and other limitiations will cause initify to not be able + * to check it correctly. For these cases, the __unverified_nocapture + * attribute can be added to disable this checking, overriding the plugin + * logic for cases that have been manually verified. This should not need + * to be used very often. */ #ifdef INITIFY_PLUGIN #define __nocapture(...) __attribute__((nocapture(__VA_ARGS__))) +#define __unverified_nocapture(...) __attribute__((unverified_nocapture(__VA_ARGS__))) #endif /* diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 8b3dcc790bb6..1bde420f07bb 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -437,6 +437,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s # define __nocapture(...) #endif +#ifndef __unverified_nocapture +# define __unverified_nocapture(...) +#endif + /* * Tell gcc if a function is cold. The compiler will assume any path * directly leading to the call is unlikely. diff --git a/include/linux/string.h b/include/linux/string.h index 8b3b97e7b2b0..040eab355533 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -76,7 +76,7 @@ static inline __must_check char *strstrip(char *str) extern char * strstr(const char *, const char *) __nocapture(-1, 2); #endif #ifndef __HAVE_ARCH_STRNSTR -extern char * strnstr(const char *, const char *, size_t) __nocapture(-1, 2); +extern char * strnstr(const char *, const char *, size_t) __nocapture(-1, 2) __unverified_nocapture(2); #endif #ifndef __HAVE_ARCH_STRLEN extern __kernel_size_t strlen(const char *) __nocapture(1); diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a192761d338a..cb964b51f9f8 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -118,7 +118,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) } EXPORT_SYMBOL(simple_strtoll); -static noinline_for_stack __nocapture(1) +static noinline_for_stack __nocapture(1) __unverified_nocapture(1) int skip_atoi(const char **s) { int i = 0; @@ -1570,7 +1570,7 @@ int kptr_restrict __read_mostly; * function pointers are really function descriptors, which contain a * pointer to the real address. */ -static noinline_for_stack __nocapture(1) +static noinline_for_stack __nocapture(1) __unverified_nocapture(1) char *pointer(const char *fmt, char *buf, char *end, void *ptr, struct printf_spec spec) { diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index b2a0cff2bb35..82e27d52d67a 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -343,6 +343,7 @@ void *memset(void *addr, int c, size_t len) } #undef memmove +__unverified_nocapture(2) void *memmove(void *dest, const void *src, size_t len) { check_memory_region((unsigned long)src, len, false, _RET_IP_); @@ -352,6 +353,7 @@ void *memmove(void *dest, const void *src, size_t len) } #undef memcpy +__unverified_nocapture(2) void *memcpy(void *dest, const void *src, size_t len) { check_memory_region((unsigned long)src, len, false, _RET_IP_); -- cgit v1.2.3