Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751548AbdGZDuk (ORCPT ); Tue, 25 Jul 2017 23:50:40 -0400 Received: from mail-pg0-f42.google.com ([74.125.83.42]:37645 "EHLO mail-pg0-f42.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750908AbdGZDuj (ORCPT ); Tue, 25 Jul 2017 23:50:39 -0400 Date: Tue, 25 Jul 2017 20:50:36 -0700 From: Kees Cook To: Andrew Morton Cc: Linus Torvalds , Daniel Micay , Dan Williams , Mika Westerberg , Al Viro , David Howells , Heikki Krogerus , Bjorn Helgaas , Arnd Bergmann , Greg Kroah-Hartman , Mauro Carvalho Chehab , linux-kernel@vger.kernel.org Subject: [PATCH] fortify: Use WARN instead of BUG for now Message-ID: <20170726035036.GA76341@beast> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6943 Lines: 210 While CONFIG_FORTIFY_SOURCE continues to shake out, don't unconditionally use BUG(), opting instead for WARN(). At the same time, expand the runtime detection to provide a better hint about what went wrong. Cc: Daniel Micay Suggested-by: Linus Torvalds Signed-off-by: Kees Cook --- Sending to akpm, since fortify went through -mm originally. --- include/linux/string.h | 48 ++++++++++++++++++++++++++++++------------------ lib/string.c | 19 +++++++++++++++---- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/include/linux/string.h b/include/linux/string.h index a467e617eeb0..97468047b965 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -197,7 +197,10 @@ static inline const char *kbasename(const char *path) #define __FORTIFY_INLINE extern __always_inline __attribute__((gnu_inline)) #define __RENAME(x) __asm__(#x) -void fortify_panic(const char *name) __noreturn __cold; +void fortify_read_overflow(const char *func) __cold; +void fortify_read_overflow2(const char *func) __cold; +void fortify_write_overflow(const char *func) __cold; + void __read_overflow(void) __compiletime_error("detected read beyond size of object passed as 1st parameter"); void __read_overflow2(void) __compiletime_error("detected read beyond size of object passed as 2nd parameter"); void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter"); @@ -209,7 +212,7 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) if (__builtin_constant_p(size) && p_size < size) __write_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_write_overflow(__func__); return __builtin_strncpy(p, q, size); } @@ -219,7 +222,7 @@ __FORTIFY_INLINE char *strcat(char *p, const char *q) if (p_size == (size_t)-1) return __builtin_strcat(p, q); if (strlcat(p, q, p_size) >= p_size) - fortify_panic(__func__); + fortify_write_overflow(__func__); return p; } @@ -231,7 +234,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p) return __builtin_strlen(p); ret = strnlen(p, p_size); if (p_size <= ret) - fortify_panic(__func__); + fortify_read_overflow(__func__); return ret; } @@ -241,7 +244,7 @@ __FORTIFY_INLINE __kernel_size_t strnlen(const char *p, __kernel_size_t maxlen) size_t p_size = __builtin_object_size(p, 0); __kernel_size_t ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size); if (p_size <= ret && maxlen != ret) - fortify_panic(__func__); + fortify_read_overflow(__func__); return ret; } @@ -260,7 +263,7 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size) if (__builtin_constant_p(len) && len >= p_size) __write_overflow(); if (len >= p_size) - fortify_panic(__func__); + fortify_write_overflow(__func__); __builtin_memcpy(p, q, len); p[len] = '\0'; } @@ -278,7 +281,7 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count) p_len = strlen(p); copy_len = strnlen(q, count); if (p_size < p_len + copy_len + 1) - fortify_panic(__func__); + fortify_write_overflow(__func__); __builtin_memcpy(p + p_len, q, copy_len); p[p_len + copy_len] = '\0'; return p; @@ -290,7 +293,7 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size) if (__builtin_constant_p(size) && p_size < size) __write_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_write_overflow(__func__); return __builtin_memset(p, c, size); } @@ -303,9 +306,12 @@ __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) __write_overflow(); if (q_size < size) __read_overflow2(); + } else { + if (p_size < size) + fortify_write_overflow(__func__); + if (q_size < size) + fortify_read_overflow2(__func__); } - if (p_size < size || q_size < size) - fortify_panic(__func__); return __builtin_memcpy(p, q, size); } @@ -318,9 +324,12 @@ __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) __write_overflow(); if (q_size < size) __read_overflow2(); + } else { + if (p_size < size) + fortify_write_overflow(__func__); + if (q_size < size) + fortify_read_overflow2(__func__); } - if (p_size < size || q_size < size) - fortify_panic(__func__); return __builtin_memmove(p, q, size); } @@ -331,7 +340,7 @@ __FORTIFY_INLINE void *memscan(void *p, int c, __kernel_size_t size) if (__builtin_constant_p(size) && p_size < size) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_read_overflow(__func__); return __real_memscan(p, c, size); } @@ -344,9 +353,12 @@ __FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) __read_overflow(); if (q_size < size) __read_overflow2(); + } else { + if (p_size < size) + fortify_read_overflow(__func__); + if (q_size < size) + fortify_read_overflow2(__func__); } - if (p_size < size || q_size < size) - fortify_panic(__func__); return __builtin_memcmp(p, q, size); } @@ -356,7 +368,7 @@ __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size) if (__builtin_constant_p(size) && p_size < size) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_read_overflow(__func__); return __builtin_memchr(p, c, size); } @@ -367,7 +379,7 @@ __FORTIFY_INLINE void *memchr_inv(const void *p, int c, size_t size) if (__builtin_constant_p(size) && p_size < size) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_read_overflow(__func__); return __real_memchr_inv(p, c, size); } @@ -378,7 +390,7 @@ __FORTIFY_INLINE void *kmemdup(const void *p, size_t size, gfp_t gfp) if (__builtin_constant_p(size) && p_size < size) __read_overflow(); if (p_size < size) - fortify_panic(__func__); + fortify_read_overflow(__func__); return __real_kmemdup(p, size, gfp); } diff --git a/lib/string.c b/lib/string.c index ebbb99c775bd..0fb68ec9a455 100644 --- a/lib/string.c +++ b/lib/string.c @@ -979,9 +979,20 @@ char *strreplace(char *s, char old, char new) } EXPORT_SYMBOL(strreplace); -void fortify_panic(const char *name) +void fortify_read_overflow(const char *func) { - pr_emerg("detected buffer overflow in %s\n", name); - BUG(); + WARN(1, "detected read beyond size of object passed as 1st parameter in %s\n", func); } -EXPORT_SYMBOL(fortify_panic); +EXPORT_SYMBOL(fortify_read_overflow); + +void fortify_read_overflow2(const char *func) +{ + WARN(1, "detected read beyond size of object passed as 2nd parameter in %s\n", func); +} +EXPORT_SYMBOL(fortify_read_overflow2); + +void fortify_write_overflow(const char *func) +{ + WARN(1, "detected write beyond size of object passed as 1st parameter in %s\n", func); +} +EXPORT_SYMBOL(fortify_write_overflow); -- 2.7.4 -- Kees Cook Pixel Security