* [PATCH v2 0/6] Provide saturating helpers for allocation @ 2018-05-09 20:02 Kees Cook 2018-05-09 20:02 ` [PATCH v2 1/6] compiler.h: enable builtin overflow checkers and add fallback code Kees Cook ` (6 more replies) 0 siblings, 7 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening This is a stab at providing three new helpers for allocation size calculation: struct_size(), array_size(), and array3_size(). These are implemented on top of Rasmus's overflow checking functions. The existing allocators are adjusted to use the more efficient overflow checks as well. I have left out the 8 tree-wide conversion patches of open-coded multiplications into the new helpers, as those are largely unchanged from v1. Everything can be seen here, though: https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=kspp/overflow/array_size The question remains for what to do with the *calloc() and *_array*() API. They could be entirely removed in favor of using the new helpers: kcalloc(n, size, gfp) -> kzalloc(array_size(n, size), gfp) kmalloc_array(n, size, gfp) -> kmalloc(array_size(n, size), gfp) Changes from v1: - use explicit overflow helpers instead of array_size() helpers. - drop early-checks for SIZE_MAX. - protect devm_kmalloc()-family from addition overflow. - added missing overflow.h includes. - fixed 0-day issues in a few treewide manual conversions -Kees ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/6] compiler.h: enable builtin overflow checkers and add fallback code 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-09 20:02 ` [PATCH v2 2/6] lib: add runtime test of check_*_overflow functions Kees Cook ` (5 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening From: Rasmus Villemoes <linux@rasmusvillemoes.dk> This adds wrappers for the __builtin overflow checkers present in gcc 5.1+ as well as fallback implementations for earlier compilers. It's not that easy to implement the fully generic __builtin_X_overflow(T1 a, T2 b, T3 *d) in macros, so the fallback code assumes that T1, T2 and T3 are the same. We obviously don't want the wrappers to have different semantics depending on $GCC_VERSION, so we also insist on that even when using the builtins. There are a few problems with the 'a+b < a' idiom for checking for overflow: For signed types, it relies on undefined behaviour and is not actually complete (it doesn't check underflow; e.g. INT_MIN+INT_MIN == 0 isn't caught). Due to type promotion it is wrong for all types (signed and unsigned) narrower than int. Similarly, when a and b does not have the same type, there are subtle cases like u32 a; if (a + sizeof(foo) < a) return -EOVERFLOW; a += sizeof(foo); where the test is always false on 64 bit platforms. Add to that that it is not always possible to determine the types involved at a glance. The new overflow.h is somewhat bulky, but that's mostly a result of trying to be type-generic, complete (e.g. catching not only overflow but also signed underflow) and not relying on undefined behaviour. Linus is of course right [1] that for unsigned subtraction a-b, the right way to check for overflow (underflow) is "b > a" and not "__builtin_sub_overflow(a, b, &d)", but that's just one out of six cases covered here, and included mostly for completeness. So is it worth it? I think it is, if nothing else for the documentation value of seeing if (check_add_overflow(a, b, &d)) return -EGOAWAY; do_stuff_with(d); instead of the open-coded (and possibly wrong and/or incomplete and/or UBsan-tickling) if (a+b < a) return -EGOAWAY; do_stuff_with(a+b); While gcc does recognize the 'a+b < a' idiom for testing unsigned add overflow, it doesn't do nearly as good for unsigned multiplication (there's also no single well-established idiom). So using check_mul_overflow in kcalloc and friends may also make gcc generate slightly better code. [1] https://lkml.org/lkml/2015/11/2/658 Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Kees Cook <keescook@chromium.org> --- include/linux/compiler-clang.h | 14 +++ include/linux/compiler-gcc.h | 4 + include/linux/compiler-intel.h | 4 + include/linux/overflow.h | 205 +++++++++++++++++++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 include/linux/overflow.h diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index 7d98e263e048..7087446c24c8 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -32,3 +32,17 @@ #ifdef __noretpoline #undef __noretpoline #endif + +/* + * Not all versions of clang implement the the type-generic versions + * of the builtin overflow checkers. Fortunately, clang implements + * __has_builtin allowing us to avoid awkward version + * checks. Unfortunately, we don't know which version of gcc clang + * pretends to be, so the macro may or may not be defined. + */ +#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +#if __has_builtin(__builtin_mul_overflow) && \ + __has_builtin(__builtin_add_overflow) && \ + __has_builtin(__builtin_sub_overflow) +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 +#endif diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index b4bf73f5e38f..f1a7492a5cc8 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -343,3 +343,7 @@ * code */ #define uninitialized_var(x) x = x + +#if GCC_VERSION >= 50100 +#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1 +#endif diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index bfa08160db3a..547cdc920a3c 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -44,3 +44,7 @@ #define __builtin_bswap16 _bswap16 #endif +/* + * icc defines __GNUC__, but does not implement the builtin overflow checkers. + */ +#undef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW diff --git a/include/linux/overflow.h b/include/linux/overflow.h new file mode 100644 index 000000000000..c8890ec358a7 --- /dev/null +++ b/include/linux/overflow.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +#ifndef __LINUX_OVERFLOW_H +#define __LINUX_OVERFLOW_H + +#include <linux/compiler.h> + +/* + * In the fallback code below, we need to compute the minimum and + * maximum values representable in a given type. These macros may also + * be useful elsewhere, so we provide them outside the + * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block. + * + * It would seem more obvious to do something like + * + * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0) + * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0) + * + * Unfortunately, the middle expressions, strictly speaking, have + * undefined behaviour, and at least some versions of gcc warn about + * the type_max expression (but not if -fsanitize=undefined is in + * effect; in that case, the warning is deferred to runtime...). + * + * The slightly excessive casting in type_min is to make sure the + * macros also produce sensible values for the exotic type _Bool. [The + * overflow checkers only almost work for _Bool, but that's + * a-feature-not-a-bug, since people shouldn't be doing arithmetic on + * _Bools. Besides, the gcc builtins don't allow _Bool* as third + * argument.] + * + * Idea stolen from + * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html - + * credit to Christian Biere. + */ +#define is_signed_type(type) (((type)(-1)) < (type)1) +#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type))) +#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T))) +#define type_min(T) ((T)((T)-type_max(T)-(T)1)) + + +#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW +/* + * For simplicity and code hygiene, the fallback code below insists on + * a, b and *d having the same type (similar to the min() and max() + * macros), whereas gcc's type-generic overflow checkers accept + * different types. Hence we don't just make check_add_overflow an + * alias for __builtin_add_overflow, but add type checks similar to + * below. + */ +#define check_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_add_overflow(__a, __b, __d); \ +}) + +#define check_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_sub_overflow(__a, __b, __d); \ +}) + +#define check_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + __builtin_mul_overflow(__a, __b, __d); \ +}) + +#else + + +/* Checking for unsigned overflow is relatively easy without causing UB. */ +#define __unsigned_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a + __b; \ + *__d < __a; \ +}) +#define __unsigned_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a - __b; \ + __a < __b; \ +}) +/* + * If one of a or b is a compile-time constant, this avoids a division. + */ +#define __unsigned_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = __a * __b; \ + __builtin_constant_p(__b) ? \ + __b > 0 && __a > type_max(typeof(__a)) / __b : \ + __a > 0 && __b > type_max(typeof(__b)) / __a; \ +}) + +/* + * For signed types, detecting overflow is much harder, especially if + * we want to avoid UB. But the interface of these macros is such that + * we must provide a result in *d, and in fact we must produce the + * result promised by gcc's builtins, which is simply the possibly + * wrapped-around value. Fortunately, we can just formally do the + * operations in the widest relevant unsigned type (u64) and then + * truncate the result - gcc is smart enough to generate the same code + * with and without the (u64) casts. + */ + +/* + * Adding two signed integers can overflow only if they have the same + * sign, and overflow has happened iff the result has the opposite + * sign. + */ +#define __signed_add_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a + (u64)__b; \ + (((~(__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Subtraction is similar, except that overflow can now happen only + * when the signs are opposite. In this case, overflow has happened if + * the result has the opposite sign of a. + */ +#define __signed_sub_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a - (u64)__b; \ + ((((__a ^ __b)) & (*__d ^ __a)) \ + & type_min(typeof(__a))) != 0; \ +}) + +/* + * Signed multiplication is rather hard. gcc always follows C99, so + * division is truncated towards 0. This means that we can write the + * overflow check like this: + * + * (a > 0 && (b > MAX/a || b < MIN/a)) || + * (a < -1 && (b > MIN/a || b < MAX/a) || + * (a == -1 && b == MIN) + * + * The redundant casts of -1 are to silence an annoying -Wtype-limits + * (included in -Wextra) warning: When the type is u8 or u16, the + * __b_c_e in check_mul_overflow obviously selects + * __unsigned_mul_overflow, but unfortunately gcc still parses this + * code and warns about the limited range of __b. + */ + +#define __signed_mul_overflow(a, b, d) ({ \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + typeof(d) __d = (d); \ + typeof(a) __tmax = type_max(typeof(a)); \ + typeof(a) __tmin = type_min(typeof(a)); \ + (void) (&__a == &__b); \ + (void) (&__a == __d); \ + *__d = (u64)__a * (u64)__b; \ + (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \ + (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \ + (__b == (typeof(__b))-1 && __a == __tmin); \ +}) + + +#define check_add_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_add_overflow(a, b, d), \ + __unsigned_add_overflow(a, b, d)) + +#define check_sub_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_sub_overflow(a, b, d), \ + __unsigned_sub_overflow(a, b, d)) + +#define check_mul_overflow(a, b, d) \ + __builtin_choose_expr(is_signed_type(typeof(a)), \ + __signed_mul_overflow(a, b, d), \ + __unsigned_mul_overflow(a, b, d)) + + +#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ + +#endif /* __LINUX_OVERFLOW_H */ -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 2/6] lib: add runtime test of check_*_overflow functions 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook 2018-05-09 20:02 ` [PATCH v2 1/6] compiler.h: enable builtin overflow checkers and add fallback code Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-09 20:02 ` [PATCH v2 3/6] overflow.h: Add allocation size calculation helpers Kees Cook ` (4 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening From: Rasmus Villemoes <linux@rasmusvillemoes.dk> This adds a small module for testing that the check_*_overflow functions work as expected, whether implemented in C or using gcc builtins. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Signed-off-by: Kees Cook <keescook@chromium.org> --- lib/Kconfig.debug | 3 + lib/Makefile | 1 + lib/test_overflow.c | 285 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 lib/test_overflow.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index c40c7b734cd1..d9fe912afed5 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1785,6 +1785,9 @@ config TEST_BITMAP config TEST_UUID tristate "Test functions located in the uuid module at runtime" +config TEST_OVERFLOW + tristate "Test check_*_overflow() functions at runtime" + config TEST_RHASHTABLE tristate "Perform selftest on resizable hash table" default n diff --git a/lib/Makefile b/lib/Makefile index ce20696d5a92..eb762ad52ccf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -59,6 +59,7 @@ UBSAN_SANITIZE_test_ubsan.o := y obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o obj-$(CONFIG_TEST_LKM) += test_module.o +obj-$(CONFIG_TEST_OVERFLOW) += test_overflow.o obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o obj-$(CONFIG_TEST_SORT) += test_sort.o obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o diff --git a/lib/test_overflow.c b/lib/test_overflow.c new file mode 100644 index 000000000000..e1e45ba17ff0 --- /dev/null +++ b/lib/test_overflow.c @@ -0,0 +1,285 @@ +/* SPDX-License-Identifier: GPL-2.0 OR MIT */ +/* + * Test cases for arithmetic overflow checks. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/overflow.h> +#include <linux/types.h> + +#define DEFINE_TEST_ARRAY(t) \ + static const struct test_ ## t { \ + t a, b; \ + t sum, diff, prod; \ + bool s_of, d_of, p_of; \ + } t ## _tests[] __initconst + +DEFINE_TEST_ARRAY(u8) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U8_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U8_MAX, U8_MAX, 1, 0, false, true, false}, + {U8_MAX, 0, U8_MAX, U8_MAX, 0, false, false, false}, + {1, U8_MAX, 0, 2, U8_MAX, true, true, false}, + {U8_MAX, 1, 0, U8_MAX-1, U8_MAX, true, false, false}, + {U8_MAX, U8_MAX, U8_MAX-1, 0, 1, true, false, true}, + + {U8_MAX, U8_MAX-1, U8_MAX-2, 1, 2, true, false, true}, + {U8_MAX-1, U8_MAX, U8_MAX-2, U8_MAX, 2, true, true, true}, + + {1U << 3, 1U << 3, 1U << 4, 0, 1U << 6, false, false, false}, + {1U << 4, 1U << 4, 1U << 5, 0, 0, false, false, true}, + {1U << 4, 1U << 3, 3*(1U << 3), 1U << 3, 1U << 7, false, false, false}, + {1U << 7, 1U << 7, 0, 0, 0, true, false, true}, + + {48, 32, 80, 16, 0, false, false, true}, + {128, 128, 0, 0, 0, true, false, true}, + {123, 234, 101, 145, 110, true, true, true}, +}; +DEFINE_TEST_ARRAY(u16) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U16_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U16_MAX, U16_MAX, 1, 0, false, true, false}, + {U16_MAX, 0, U16_MAX, U16_MAX, 0, false, false, false}, + {1, U16_MAX, 0, 2, U16_MAX, true, true, false}, + {U16_MAX, 1, 0, U16_MAX-1, U16_MAX, true, false, false}, + {U16_MAX, U16_MAX, U16_MAX-1, 0, 1, true, false, true}, + + {U16_MAX, U16_MAX-1, U16_MAX-2, 1, 2, true, false, true}, + {U16_MAX-1, U16_MAX, U16_MAX-2, U16_MAX, 2, true, true, true}, + + {1U << 7, 1U << 7, 1U << 8, 0, 1U << 14, false, false, false}, + {1U << 8, 1U << 8, 1U << 9, 0, 0, false, false, true}, + {1U << 8, 1U << 7, 3*(1U << 7), 1U << 7, 1U << 15, false, false, false}, + {1U << 15, 1U << 15, 0, 0, 0, true, false, true}, + + {123, 234, 357, 65425, 28782, false, true, false}, + {1234, 2345, 3579, 64425, 10146, false, true, true}, +}; +DEFINE_TEST_ARRAY(u32) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U32_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U32_MAX, U32_MAX, 1, 0, false, true, false}, + {U32_MAX, 0, U32_MAX, U32_MAX, 0, false, false, false}, + {1, U32_MAX, 0, 2, U32_MAX, true, true, false}, + {U32_MAX, 1, 0, U32_MAX-1, U32_MAX, true, false, false}, + {U32_MAX, U32_MAX, U32_MAX-1, 0, 1, true, false, true}, + + {U32_MAX, U32_MAX-1, U32_MAX-2, 1, 2, true, false, true}, + {U32_MAX-1, U32_MAX, U32_MAX-2, U32_MAX, 2, true, true, true}, + + {1U << 15, 1U << 15, 1U << 16, 0, 1U << 30, false, false, false}, + {1U << 16, 1U << 16, 1U << 17, 0, 0, false, false, true}, + {1U << 16, 1U << 15, 3*(1U << 15), 1U << 15, 1U << 31, false, false, false}, + {1U << 31, 1U << 31, 0, 0, 0, true, false, true}, + + {-2U, 1U, -1U, -3U, -2U, false, false, false}, + {-4U, 5U, 1U, -9U, -20U, true, false, true}, +}; + +DEFINE_TEST_ARRAY(u64) = { + {0, 0, 0, 0, 0, false, false, false}, + {1, 1, 2, 0, 1, false, false, false}, + {0, 1, 1, U64_MAX, 0, false, true, false}, + {1, 0, 1, 1, 0, false, false, false}, + {0, U64_MAX, U64_MAX, 1, 0, false, true, false}, + {U64_MAX, 0, U64_MAX, U64_MAX, 0, false, false, false}, + {1, U64_MAX, 0, 2, U64_MAX, true, true, false}, + {U64_MAX, 1, 0, U64_MAX-1, U64_MAX, true, false, false}, + {U64_MAX, U64_MAX, U64_MAX-1, 0, 1, true, false, true}, + + {U64_MAX, U64_MAX-1, U64_MAX-2, 1, 2, true, false, true}, + {U64_MAX-1, U64_MAX, U64_MAX-2, U64_MAX, 2, true, true, true}, + + {1ULL << 31, 1ULL << 31, 1ULL << 32, 0, 1ULL << 62, false, false, false}, + {1ULL << 32, 1ULL << 32, 1ULL << 33, 0, 0, false, false, true}, + {1ULL << 32, 1ULL << 31, 3*(1ULL << 31), 1ULL << 31, 1ULL << 63, false, false, false}, + {1ULL << 63, 1ULL << 63, 0, 0, 0, true, false, true}, + {1000000000ULL /* 10^9 */, 10000000000ULL /* 10^10 */, + 11000000000ULL, 18446744064709551616ULL, 10000000000000000000ULL, + false, true, false}, + {-15ULL, 10ULL, -5ULL, -25ULL, -150ULL, false, false, true}, +}; + +DEFINE_TEST_ARRAY(s8) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S8_MAX, S8_MAX, -S8_MAX, 0, false, false, false}, + {S8_MAX, 0, S8_MAX, S8_MAX, 0, false, false, false}, + {0, S8_MIN, S8_MIN, S8_MIN, 0, false, true, false}, + {S8_MIN, 0, S8_MIN, S8_MIN, 0, false, false, false}, + + {-1, S8_MIN, S8_MAX, S8_MAX, S8_MIN, true, false, true}, + {S8_MIN, -1, S8_MAX, -S8_MAX, S8_MIN, true, false, true}, + {-1, S8_MAX, S8_MAX-1, S8_MIN, -S8_MAX, false, false, false}, + {S8_MAX, -1, S8_MAX-1, S8_MIN, -S8_MAX, false, true, false}, + {-1, -S8_MAX, S8_MIN, S8_MAX-1, S8_MAX, false, false, false}, + {-S8_MAX, -1, S8_MIN, S8_MIN+2, S8_MAX, false, false, false}, + + {1, S8_MIN, -S8_MAX, -S8_MAX, S8_MIN, false, true, false}, + {S8_MIN, 1, -S8_MAX, S8_MAX, S8_MIN, false, true, false}, + {1, S8_MAX, S8_MIN, S8_MIN+2, S8_MAX, true, false, false}, + {S8_MAX, 1, S8_MIN, S8_MAX-1, S8_MAX, true, false, false}, + + {S8_MIN, S8_MIN, 0, 0, 0, true, false, true}, + {S8_MAX, S8_MAX, -2, 0, 1, true, false, true}, + + {-4, -32, -36, 28, -128, false, false, true}, + {-4, 32, 28, -36, -128, false, false, false}, +}; + +DEFINE_TEST_ARRAY(s16) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S16_MAX, S16_MAX, -S16_MAX, 0, false, false, false}, + {S16_MAX, 0, S16_MAX, S16_MAX, 0, false, false, false}, + {0, S16_MIN, S16_MIN, S16_MIN, 0, false, true, false}, + {S16_MIN, 0, S16_MIN, S16_MIN, 0, false, false, false}, + + {-1, S16_MIN, S16_MAX, S16_MAX, S16_MIN, true, false, true}, + {S16_MIN, -1, S16_MAX, -S16_MAX, S16_MIN, true, false, true}, + {-1, S16_MAX, S16_MAX-1, S16_MIN, -S16_MAX, false, false, false}, + {S16_MAX, -1, S16_MAX-1, S16_MIN, -S16_MAX, false, true, false}, + {-1, -S16_MAX, S16_MIN, S16_MAX-1, S16_MAX, false, false, false}, + {-S16_MAX, -1, S16_MIN, S16_MIN+2, S16_MAX, false, false, false}, + + {1, S16_MIN, -S16_MAX, -S16_MAX, S16_MIN, false, true, false}, + {S16_MIN, 1, -S16_MAX, S16_MAX, S16_MIN, false, true, false}, + {1, S16_MAX, S16_MIN, S16_MIN+2, S16_MAX, true, false, false}, + {S16_MAX, 1, S16_MIN, S16_MAX-1, S16_MAX, true, false, false}, + + {S16_MIN, S16_MIN, 0, 0, 0, true, false, true}, + {S16_MAX, S16_MAX, -2, 0, 1, true, false, true}, +}; +DEFINE_TEST_ARRAY(s32) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S32_MAX, S32_MAX, -S32_MAX, 0, false, false, false}, + {S32_MAX, 0, S32_MAX, S32_MAX, 0, false, false, false}, + {0, S32_MIN, S32_MIN, S32_MIN, 0, false, true, false}, + {S32_MIN, 0, S32_MIN, S32_MIN, 0, false, false, false}, + + {-1, S32_MIN, S32_MAX, S32_MAX, S32_MIN, true, false, true}, + {S32_MIN, -1, S32_MAX, -S32_MAX, S32_MIN, true, false, true}, + {-1, S32_MAX, S32_MAX-1, S32_MIN, -S32_MAX, false, false, false}, + {S32_MAX, -1, S32_MAX-1, S32_MIN, -S32_MAX, false, true, false}, + {-1, -S32_MAX, S32_MIN, S32_MAX-1, S32_MAX, false, false, false}, + {-S32_MAX, -1, S32_MIN, S32_MIN+2, S32_MAX, false, false, false}, + + {1, S32_MIN, -S32_MAX, -S32_MAX, S32_MIN, false, true, false}, + {S32_MIN, 1, -S32_MAX, S32_MAX, S32_MIN, false, true, false}, + {1, S32_MAX, S32_MIN, S32_MIN+2, S32_MAX, true, false, false}, + {S32_MAX, 1, S32_MIN, S32_MAX-1, S32_MAX, true, false, false}, + + {S32_MIN, S32_MIN, 0, 0, 0, true, false, true}, + {S32_MAX, S32_MAX, -2, 0, 1, true, false, true}, +}; +DEFINE_TEST_ARRAY(s64) = { + {0, 0, 0, 0, 0, false, false, false}, + + {0, S64_MAX, S64_MAX, -S64_MAX, 0, false, false, false}, + {S64_MAX, 0, S64_MAX, S64_MAX, 0, false, false, false}, + {0, S64_MIN, S64_MIN, S64_MIN, 0, false, true, false}, + {S64_MIN, 0, S64_MIN, S64_MIN, 0, false, false, false}, + + {-1, S64_MIN, S64_MAX, S64_MAX, S64_MIN, true, false, true}, + {S64_MIN, -1, S64_MAX, -S64_MAX, S64_MIN, true, false, true}, + {-1, S64_MAX, S64_MAX-1, S64_MIN, -S64_MAX, false, false, false}, + {S64_MAX, -1, S64_MAX-1, S64_MIN, -S64_MAX, false, true, false}, + {-1, -S64_MAX, S64_MIN, S64_MAX-1, S64_MAX, false, false, false}, + {-S64_MAX, -1, S64_MIN, S64_MIN+2, S64_MAX, false, false, false}, + + {1, S64_MIN, -S64_MAX, -S64_MAX, S64_MIN, false, true, false}, + {S64_MIN, 1, -S64_MAX, S64_MAX, S64_MIN, false, true, false}, + {1, S64_MAX, S64_MIN, S64_MIN+2, S64_MAX, true, false, false}, + {S64_MAX, 1, S64_MIN, S64_MAX-1, S64_MAX, true, false, false}, + + {S64_MIN, S64_MIN, 0, 0, 0, true, false, true}, + {S64_MAX, S64_MAX, -2, 0, 1, true, false, true}, + + {-1, -1, -2, 0, 1, false, false, false}, + {-1, -128, -129, 127, 128, false, false, false}, + {-128, -1, -129, -127, 128, false, false, false}, + {0, -S64_MAX, -S64_MAX, S64_MAX, 0, false, false, false}, +}; + +#define DEFINE_TEST_FUNC(t, fmt) \ +static void __init do_test_ ## t(const struct test_ ## t *p) \ +{ \ + t r; \ + bool of; \ + \ + of = check_add_overflow(p->a, p->b, &r); \ + if (of != p->s_of) \ + pr_warn("expected "fmt" + "fmt" to%s overflow (type %s)\n", \ + p->a, p->b, p->s_of ? "" : " not", #t); \ + if (r != p->sum) \ + pr_warn("expected "fmt" + "fmt" == "fmt", got "fmt" (type %s)\n", \ + p->a, p->b, p->sum, r, #t); \ + \ + of = check_sub_overflow(p->a, p->b, &r); \ + if (of != p->d_of) \ + pr_warn("expected "fmt" - "fmt" to%s overflow (type %s)\n", \ + p->a, p->b, p->s_of ? "" : " not", #t); \ + if (r != p->diff) \ + pr_warn("expected "fmt" - "fmt" == "fmt", got "fmt" (type %s)\n", \ + p->a, p->b, p->diff, r, #t); \ + \ + of = check_mul_overflow(p->a, p->b, &r); \ + if (of != p->p_of) \ + pr_warn("expected "fmt" * "fmt" to%s overflow (type %s)\n", \ + p->a, p->b, p->p_of ? "" : " not", #t); \ + if (r != p->prod) \ + pr_warn("expected "fmt" * "fmt" == "fmt", got "fmt" (type %s)\n", \ + p->a, p->b, p->prod, r, #t); \ +} \ + \ +static void __init test_ ## t ## _overflow(void) { \ + unsigned i; \ + \ + pr_info("%-3s: %zu tests\n", #t, ARRAY_SIZE(t ## _tests)); \ + for (i = 0; i < ARRAY_SIZE(t ## _tests); ++i) \ + do_test_ ## t(&t ## _tests[i]); \ +} + +DEFINE_TEST_FUNC(u8, "%d"); +DEFINE_TEST_FUNC(u16, "%d"); +DEFINE_TEST_FUNC(u32, "%u"); +DEFINE_TEST_FUNC(u64, "%llu"); + +DEFINE_TEST_FUNC(s8, "%d"); +DEFINE_TEST_FUNC(s16, "%d"); +DEFINE_TEST_FUNC(s32, "%d"); +DEFINE_TEST_FUNC(s64, "%lld"); + +static int __init test_overflow(void) +{ + test_u8_overflow(); + test_u16_overflow(); + test_u32_overflow(); + test_u64_overflow(); + + test_s8_overflow(); + test_s16_overflow(); + test_s32_overflow(); + test_s64_overflow(); + + pr_info("done\n"); + + return 0; +} + +static void __exit test_module_exit(void) +{ } + +module_init(test_overflow); +module_exit(test_module_exit); +MODULE_LICENSE("Dual MIT/GPL"); -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 3/6] overflow.h: Add allocation size calculation helpers 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook 2018-05-09 20:02 ` [PATCH v2 1/6] compiler.h: enable builtin overflow checkers and add fallback code Kees Cook 2018-05-09 20:02 ` [PATCH v2 2/6] lib: add runtime test of check_*_overflow functions Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-09 20:02 ` [PATCH v2 4/6] mm: Use overflow helpers in kmalloc_array*() Kees Cook ` (3 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening In preparation for replacing unchecked overflows for memory allocations, this creates helpers for the 3 most common calculations: array_size(a, b): 2-dimensional array array3_size(a, b, c): 3-dimensional array struct_size(ptr, member, n): struct followed by n-many trailing members Each of these return SIZE_MAX on overflow instead of wrapping around. (Additionally renames a variable named "array_size" to avoid future collision.) Co-developed-by: Matthew Wilcox <mawilcox@microsoft.com> Signed-off-by: Kees Cook <keescook@chromium.org> --- drivers/md/dm-table.c | 10 +++--- include/linux/overflow.h | 73 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 0589a4da12bb..caa51dd351b6 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -548,14 +548,14 @@ static int adjoin(struct dm_table *table, struct dm_target *ti) * On the other hand, dm-switch needs to process bulk data using messages and * excessive use of GFP_NOIO could cause trouble. */ -static char **realloc_argv(unsigned *array_size, char **old_argv) +static char **realloc_argv(unsigned *size, char **old_argv) { char **argv; unsigned new_size; gfp_t gfp; - if (*array_size) { - new_size = *array_size * 2; + if (*size) { + new_size = *size * 2; gfp = GFP_KERNEL; } else { new_size = 8; @@ -563,8 +563,8 @@ static char **realloc_argv(unsigned *array_size, char **old_argv) } argv = kmalloc(new_size * sizeof(*argv), gfp); if (argv) { - memcpy(argv, old_argv, *array_size * sizeof(*argv)); - *array_size = new_size; + memcpy(argv, old_argv, *size * sizeof(*argv)); + *size = new_size; } kfree(old_argv); diff --git a/include/linux/overflow.h b/include/linux/overflow.h index c8890ec358a7..8712ff70995f 100644 --- a/include/linux/overflow.h +++ b/include/linux/overflow.h @@ -202,4 +202,77 @@ #endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */ +/** + * array_size() - Calculate size of 2-dimensional array. + * + * @a: dimension one + * @b: dimension two + * + * Calculates size of 2-dimensional array: @a * @b. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array_size(size_t a, size_t b) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * array3_size() - Calculate size of 3-dimensional array. + * + * @a: dimension one + * @b: dimension two + * @c: dimension three + * + * Calculates size of 3-dimensional array: @a * @b * @c. + * + * Returns: number of bytes needed to represent the array or SIZE_MAX on + * overflow. + */ +static inline __must_check size_t array3_size(size_t a, size_t b, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(a, b, &bytes)) + return SIZE_MAX; + if (check_mul_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c) +{ + size_t bytes; + + if (check_mul_overflow(n, size, &bytes)) + return SIZE_MAX; + if (check_add_overflow(bytes, c, &bytes)) + return SIZE_MAX; + + return bytes; +} + +/** + * struct_size() - Calculate size of structure with trailing array. + * @p: Pointer to the structure. + * @member: Name of the array member. + * @n: Number of elements in the array. + * + * Calculates size of memory needed for structure @p followed by an + * array of @n @member elements. + * + * Return: number of bytes needed or SIZE_MAX on overflow. + */ +#define struct_size(p, member, n) \ + __ab_c_size(n, \ + sizeof(*(p)->member) + __must_be_array((p)->member),\ + sizeof(*(p))) + #endif /* __LINUX_OVERFLOW_H */ -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 4/6] mm: Use overflow helpers in kmalloc_array*() 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook ` (2 preceding siblings ...) 2018-05-09 20:02 ` [PATCH v2 3/6] overflow.h: Add allocation size calculation helpers Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-09 20:02 ` [PATCH v2 5/6] mm: Use overflow helpers in kvmalloc() Kees Cook ` (2 subsequent siblings) 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening Instead of open-coded multiplication and bounds checking, use the new overflow helper. Signed-off-by: Kees Cook <keescook@chromium.org> --- include/linux/slab.h | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/slab.h b/include/linux/slab.h index 81ebd71f8c03..4d759e1ddc33 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -13,6 +13,7 @@ #define _LINUX_SLAB_H #include <linux/gfp.h> +#include <linux/overflow.h> #include <linux/types.h> #include <linux/workqueue.h> @@ -624,11 +625,13 @@ int memcg_update_all_caches(int num_memcgs); */ static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc(n * size, flags); - return __kmalloc(n * size, flags); + return kmalloc(bytes, flags); + return __kmalloc(bytes, flags); } /** @@ -657,11 +660,13 @@ extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); static inline void *kmalloc_array_node(size_t n, size_t size, gfp_t flags, int node) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc_node(n * size, flags, node); - return __kmalloc_node(n * size, flags, node); + return kmalloc_node(bytes, flags, node); + return __kmalloc_node(bytes, flags, node); } static inline void *kcalloc_node(size_t n, size_t size, gfp_t flags, int node) -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 5/6] mm: Use overflow helpers in kvmalloc() 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook ` (3 preceding siblings ...) 2018-05-09 20:02 ` [PATCH v2 4/6] mm: Use overflow helpers in kmalloc_array*() Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-09 20:02 ` [PATCH v2 6/6] device: Use overflow helpers for devm_kmalloc() Kees Cook 2018-05-11 0:02 ` [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening Instead of open-coded multiplication and bounds checking, use the new overflow helper. Additionally prepare for vmalloc() users to add array_size()-family helpers in the future. Signed-off-by: Kees Cook <keescook@chromium.org> --- include/linux/mm.h | 7 +++++-- include/linux/vmalloc.h | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 1ac1f06a4be6..7cb1c6a6bf82 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -25,6 +25,7 @@ #include <linux/err.h> #include <linux/page_ref.h> #include <linux/memremap.h> +#include <linux/overflow.h> struct mempolicy; struct anon_vma; @@ -560,10 +561,12 @@ static inline void *kvzalloc(size_t size, gfp_t flags) static inline void *kvmalloc_array(size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return kvmalloc(n * size, flags); + return kvmalloc(bytes, flags); } extern void kvfree(const void *addr); diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 1e5d8c392f15..398e9c95cd61 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -8,6 +8,7 @@ #include <linux/llist.h> #include <asm/page.h> /* pgprot_t */ #include <linux/rbtree.h> +#include <linux/overflow.h> struct vm_area_struct; /* vma defining user mapping in mm_types.h */ struct notifier_block; /* in notifier.h */ -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v2 6/6] device: Use overflow helpers for devm_kmalloc() 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook ` (4 preceding siblings ...) 2018-05-09 20:02 ` [PATCH v2 5/6] mm: Use overflow helpers in kvmalloc() Kees Cook @ 2018-05-09 20:02 ` Kees Cook 2018-05-11 0:02 ` [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-09 20:02 UTC (permalink / raw) To: Matthew Wilcox Cc: Kees Cook, Rasmus Villemoes, Matthew Wilcox, LKML, Linux-MM, Kernel Hardening Use the overflow helpers both in existing multiplication-using inlines as well as the addition-overflow case in the core allocation routine. Signed-off-by: Kees Cook <keescook@chromium.org> --- drivers/base/devres.c | 7 ++++++- include/linux/device.h | 8 ++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/base/devres.c b/drivers/base/devres.c index 95b67281cd2a..f98a097e73f2 100644 --- a/drivers/base/devres.c +++ b/drivers/base/devres.c @@ -84,9 +84,14 @@ static struct devres_group * node_to_group(struct devres_node *node) static __always_inline struct devres * alloc_dr(dr_release_t release, size_t size, gfp_t gfp, int nid) { - size_t tot_size = sizeof(struct devres) + size; + size_t tot_size; struct devres *dr; + /* We must catch any near-SIZE_MAX cases that could overflow. */ + if (unlikely(check_add_overflow(sizeof(struct devres), size, + &tot_size))) + return NULL; + dr = kmalloc_node_track_caller(tot_size, gfp, nid); if (unlikely(!dr)) return NULL; diff --git a/include/linux/device.h b/include/linux/device.h index 0059b99e1f25..e78a050d6e7e 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -25,6 +25,7 @@ #include <linux/ratelimit.h> #include <linux/uidgid.h> #include <linux/gfp.h> +#include <linux/overflow.h> #include <asm/device.h> struct device; @@ -666,9 +667,12 @@ static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) static inline void *devm_kmalloc_array(struct device *dev, size_t n, size_t size, gfp_t flags) { - if (size != 0 && n > SIZE_MAX / size) + size_t bytes; + + if (unlikely(check_mul_overflow(n, size, &bytes))) return NULL; - return devm_kmalloc(dev, n * size, flags); + + return devm_kmalloc(dev, bytes, flags); } static inline void *devm_kcalloc(struct device *dev, size_t n, size_t size, gfp_t flags) -- 2.17.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/6] Provide saturating helpers for allocation 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook ` (5 preceding siblings ...) 2018-05-09 20:02 ` [PATCH v2 6/6] device: Use overflow helpers for devm_kmalloc() Kees Cook @ 2018-05-11 0:02 ` Kees Cook 6 siblings, 0 replies; 8+ messages in thread From: Kees Cook @ 2018-05-11 0:02 UTC (permalink / raw) To: Linux-MM Cc: Rasmus Villemoes, Matthew Wilcox, Matthew Wilcox, LKML, Kernel Hardening On Wed, May 9, 2018 at 1:02 PM, Kees Cook <keescook@chromium.org> wrote: > This is a stab at providing three new helpers for allocation size > calculation: > > struct_size(), array_size(), and array3_size(). > > These are implemented on top of Rasmus's overflow checking functions. The > existing allocators are adjusted to use the more efficient overflow > checks as well. > > I have left out the 8 tree-wide conversion patches of open-coded > multiplications into the new helpers, as those are largely > unchanged from v1. Everything can be seen here, though: > https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/log/?h=kspp/overflow/array_size > > The question remains for what to do with the *calloc() and *_array*() > API. They could be entirely removed in favor of using the new helpers: > > kcalloc(n, size, gfp) -> kzalloc(array_size(n, size), gfp) > kmalloc_array(n, size, gfp) -> kmalloc(array_size(n, size), gfp) > > Changes from v1: > - use explicit overflow helpers instead of array_size() helpers. > - drop early-checks for SIZE_MAX. > - protect devm_kmalloc()-family from addition overflow. > - added missing overflow.h includes. > - fixed 0-day issues in a few treewide manual conversions I've added an allocation overflow addition to lib/test_overflow now, so I'll send a v3 soon. Does anyone want to provide an Ack or Reviewed for these? Also, any thoughts on *calloc() and *_array*() removal? -Kees -- Kees Cook Pixel Security ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2018-05-11 0:02 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2018-05-09 20:02 [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook 2018-05-09 20:02 ` [PATCH v2 1/6] compiler.h: enable builtin overflow checkers and add fallback code Kees Cook 2018-05-09 20:02 ` [PATCH v2 2/6] lib: add runtime test of check_*_overflow functions Kees Cook 2018-05-09 20:02 ` [PATCH v2 3/6] overflow.h: Add allocation size calculation helpers Kees Cook 2018-05-09 20:02 ` [PATCH v2 4/6] mm: Use overflow helpers in kmalloc_array*() Kees Cook 2018-05-09 20:02 ` [PATCH v2 5/6] mm: Use overflow helpers in kvmalloc() Kees Cook 2018-05-09 20:02 ` [PATCH v2 6/6] device: Use overflow helpers for devm_kmalloc() Kees Cook 2018-05-11 0:02 ` [PATCH v2 0/6] Provide saturating helpers for allocation Kees Cook
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).