diff options
author | Kees Cook <keescook@chromium.org> | 2024-05-01 16:32:02 -0700 |
---|---|---|
committer | Kees Cook <keescook@chromium.org> | 2024-05-01 16:35:13 -0700 |
commit | 450331b7338133ff77aa3908b53fed23db6d9d91 (patch) | |
tree | 1aecb02f0765cf372003aa7875f0f08d6ba91ada | |
parent | 74df22453c51392476117d7330bf02cee6e987cf (diff) | |
download | linux-next-history-450331b7338133ff77aa3908b53fed23db6d9d91.tar.gz |
string: Add additional __realloc_size() annotations for "dup" helpers
Notice: this object is not reachable from any branch.
Several other "dup"-style interfaces could use the __realloc_size()
attribute. (As a reminder to myself and others: "realloc" is used here
instead of "alloc" because the "alloc_size" attribute implies that the
memory contents are uninitialized. Since we're copying contents into the
resulting allocation, it must use "realloc_size" to avoid confusing the
compiler's optimization passes.)
Add KUnit test coverage where possible. (KUnit still does not have the
ability to manipulate userspace memory.)
Link: https://lore.kernel.org/r/20240501233201.work.732-kees@kernel.org
Signed-off-by: Kees Cook <keescook@chromium.org>
Notice: this object is not reachable from any branch.
-rw-r--r-- | include/linux/string.h | 13 | ||||
-rw-r--r-- | lib/fortify_kunit.c | 26 |
2 files changed, 34 insertions, 5 deletions
diff --git a/include/linux/string.h b/include/linux/string.h index 86aa6cd351675..10e5177bb49c0 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -14,8 +14,8 @@ #include <uapi/linux/string.h> extern char *strndup_user(const char __user *, long); -extern void *memdup_user(const void __user *, size_t); -extern void *vmemdup_user(const void __user *, size_t); +extern void *memdup_user(const void __user *, size_t) __realloc_size(2); +extern void *vmemdup_user(const void __user *, size_t) __realloc_size(2); extern void *memdup_user_nul(const void __user *, size_t); /** @@ -27,7 +27,8 @@ extern void *memdup_user_nul(const void __user *, size_t); * Return: an ERR_PTR() on failure. Result is physically * contiguous, to be freed by kfree(). */ -static inline void *memdup_array_user(const void __user *src, size_t n, size_t size) +static inline __realloc_size(2, 3) +void *memdup_array_user(const void __user *src, size_t n, size_t size) { size_t nbytes; @@ -46,7 +47,8 @@ static inline void *memdup_array_user(const void __user *src, size_t n, size_t s * Return: an ERR_PTR() on failure. Result may be not * physically contiguous. Use kvfree() to free. */ -static inline void *vmemdup_array_user(const void __user *src, size_t n, size_t size) +static inline __realloc_size(2, 3) +void *vmemdup_array_user(const void __user *src, size_t n, size_t size) { size_t nbytes; @@ -285,7 +287,8 @@ extern char *kstrndup(const char *s, size_t len, gfp_t gfp); extern void *kmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2); extern void *kvmemdup(const void *src, size_t len, gfp_t gfp) __realloc_size(2); extern char *kmemdup_nul(const char *s, size_t len, gfp_t gfp); -extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp); +extern void *kmemdup_array(const void *src, size_t element_size, size_t count, gfp_t gfp) + __realloc_size(2, 3); /* lib/argv_split.c */ extern char **argv_split(gfp_t gfp, const char *str, int *argcp); diff --git a/lib/fortify_kunit.c b/lib/fortify_kunit.c index 306522fd0aa2f..87b873108350c 100644 --- a/lib/fortify_kunit.c +++ b/lib/fortify_kunit.c @@ -363,6 +363,31 @@ DEFINE_ALLOC_SIZE_TEST_PAIR(kvmalloc) } while (0) DEFINE_ALLOC_SIZE_TEST_PAIR(devm_kmalloc) +static const char * const test_phrases[] = { + "", + "Hello there", + "A longer string, just for variety", +}; + +#define TEST_realloc(checker) do { \ + gfp_t gfp = GFP_KERNEL; \ + size_t len; \ + int idx; \ + \ + for (idx = 0; idx < ARRAY_SIZE(test_phrases); idx++) { \ + len = strlen(test_phrases[idx]); \ + KUNIT_EXPECT_EQ(test, __builtin_constant_p(len), 0); \ + checker(len, kmemdup_array(test_phrases[idx], len, 1, \ + gfp), kfree(p)); \ + checker(len, kmemdup(test_phrases[idx], len, gfp), \ + kfree(p)); \ + } \ +} while (0) +static void fortify_test_realloc_size(struct kunit *test) +{ + TEST_realloc(check_dynamic); +} + /* * We can't have an array at the end of a structure or else * builds without -fstrict-flex-arrays=3 will report them as @@ -1046,6 +1071,7 @@ static struct kunit_case fortify_test_cases[] = { KUNIT_CASE(fortify_test_alloc_size_kvmalloc_dynamic), KUNIT_CASE(fortify_test_alloc_size_devm_kmalloc_const), KUNIT_CASE(fortify_test_alloc_size_devm_kmalloc_dynamic), + KUNIT_CASE(fortify_test_realloc_size), KUNIT_CASE(fortify_test_strlen), KUNIT_CASE(fortify_test_strnlen), KUNIT_CASE(fortify_test_strcpy), |