From 3d82a0771b5dfebb82bf03b2828f3337686803e9 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Thu, 15 Jun 2023 10:25:23 -0400 Subject: [PATCH] Fixes for 5.10 Signed-off-by: Sasha Levin --- ...ut-kstrtox-and-simple_strtox-to-a-se.patch | 457 ++++++++++++++++++ queue-5.10/lib-cleanup-kstrto-usage.patch | 125 +++++ queue-5.10/series | 5 + ...e-fix-a-memory-leak-with-reqs-buffer.patch | 72 +++ ...event-race-conditions-by-a-correct-i.patch | 259 ++++++++++ ...-use-kstrtobool-instead-of-strtobool.patch | 51 ++ 6 files changed, 969 insertions(+) create mode 100644 queue-5.10/kernel.h-split-out-kstrtox-and-simple_strtox-to-a-se.patch create mode 100644 queue-5.10/lib-cleanup-kstrto-usage.patch create mode 100644 queue-5.10/series create mode 100644 queue-5.10/test_firmware-fix-a-memory-leak-with-reqs-buffer.patch create mode 100644 queue-5.10/test_firmware-prevent-race-conditions-by-a-correct-i.patch create mode 100644 queue-5.10/test_firmware-use-kstrtobool-instead-of-strtobool.patch diff --git a/queue-5.10/kernel.h-split-out-kstrtox-and-simple_strtox-to-a-se.patch b/queue-5.10/kernel.h-split-out-kstrtox-and-simple_strtox-to-a-se.patch new file mode 100644 index 00000000000..b4a60dc6d83 --- /dev/null +++ b/queue-5.10/kernel.h-split-out-kstrtox-and-simple_strtox-to-a-se.patch @@ -0,0 +1,457 @@ +From 45c605128dd1ec7d7e77597b8273cae0a620968f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Jun 2021 18:56:10 -0700 +Subject: kernel.h: split out kstrtox() and simple_strtox() to a separate + header + +From: Andy Shevchenko + +[ Upstream commit 4c52729377eab025b238caeed48994a39c3b73f2 ] + +kernel.h is being used as a dump for all kinds of stuff for a long time. +Here is the attempt to start cleaning it up by splitting out kstrtox() and +simple_strtox() helpers. + +At the same time convert users in header and lib folders to use new +header. Though for time being include new header back to kernel.h to +avoid twisted indirected includes for existing users. + +[andy.shevchenko@gmail.com: fix documentation references] + Link: https://lkml.kernel.org/r/20210615220003.377901-1-andy.shevchenko@gmail.com + +Link: https://lkml.kernel.org/r/20210611185815.44103-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Andy Shevchenko +Acked-by: Jonathan Cameron +Cc: Francis Laniel +Cc: Randy Dunlap +Cc: Kars Mulder +Cc: Trond Myklebust +Cc: Anna Schumaker +Cc: "J. Bruce Fields" +Cc: Chuck Lever +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: 4acfe3dfde68 ("test_firmware: prevent race conditions by a correct implementation of locking") +Signed-off-by: Sasha Levin +--- + Documentation/core-api/kernel-api.rst | 7 +- + include/linux/kernel.h | 143 +----------------------- + include/linux/kstrtox.h | 155 ++++++++++++++++++++++++++ + include/linux/string.h | 7 -- + include/linux/sunrpc/cache.h | 1 + + lib/kstrtox.c | 5 +- + lib/parser.c | 1 + + 7 files changed, 163 insertions(+), 156 deletions(-) + create mode 100644 include/linux/kstrtox.h + +diff --git a/Documentation/core-api/kernel-api.rst b/Documentation/core-api/kernel-api.rst +index 741aa37dc1819..2a7444e3a4c21 100644 +--- a/Documentation/core-api/kernel-api.rst ++++ b/Documentation/core-api/kernel-api.rst +@@ -24,11 +24,8 @@ String Conversions + .. kernel-doc:: lib/vsprintf.c + :export: + +-.. kernel-doc:: include/linux/kernel.h +- :functions: kstrtol +- +-.. kernel-doc:: include/linux/kernel.h +- :functions: kstrtoul ++.. kernel-doc:: include/linux/kstrtox.h ++ :functions: kstrtol kstrtoul + + .. kernel-doc:: lib/kstrtox.c + :export: +diff --git a/include/linux/kernel.h b/include/linux/kernel.h +index 66948e1bf4fa6..cdd6ed5bbcf20 100644 +--- a/include/linux/kernel.h ++++ b/include/linux/kernel.h +@@ -10,6 +10,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -329,148 +330,6 @@ extern bool oops_may_print(void); + void do_exit(long error_code) __noreturn; + void complete_and_exit(struct completion *, long) __noreturn; + +-/* Internal, do not use. */ +-int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); +-int __must_check _kstrtol(const char *s, unsigned int base, long *res); +- +-int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res); +-int __must_check kstrtoll(const char *s, unsigned int base, long long *res); +- +-/** +- * kstrtoul - convert a string to an unsigned long +- * @s: The start of the string. The string must be null-terminated, and may also +- * include a single newline before its terminating null. The first character +- * may also be a plus sign, but not a minus sign. +- * @base: The number base to use. The maximum supported base is 16. If base is +- * given as 0, then the base of the string is automatically detected with the +- * conventional semantics - If it begins with 0x the number will be parsed as a +- * hexadecimal (case insensitive), if it otherwise begins with 0, it will be +- * parsed as an octal number. Otherwise it will be parsed as a decimal. +- * @res: Where to write the result of the conversion on success. +- * +- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. +- * Preferred over simple_strtoul(). Return code must be checked. +-*/ +-static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) +-{ +- /* +- * We want to shortcut function call, but +- * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0. +- */ +- if (sizeof(unsigned long) == sizeof(unsigned long long) && +- __alignof__(unsigned long) == __alignof__(unsigned long long)) +- return kstrtoull(s, base, (unsigned long long *)res); +- else +- return _kstrtoul(s, base, res); +-} +- +-/** +- * kstrtol - convert a string to a long +- * @s: The start of the string. The string must be null-terminated, and may also +- * include a single newline before its terminating null. The first character +- * may also be a plus sign or a minus sign. +- * @base: The number base to use. The maximum supported base is 16. If base is +- * given as 0, then the base of the string is automatically detected with the +- * conventional semantics - If it begins with 0x the number will be parsed as a +- * hexadecimal (case insensitive), if it otherwise begins with 0, it will be +- * parsed as an octal number. Otherwise it will be parsed as a decimal. +- * @res: Where to write the result of the conversion on success. +- * +- * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. +- * Preferred over simple_strtol(). Return code must be checked. +- */ +-static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) +-{ +- /* +- * We want to shortcut function call, but +- * __builtin_types_compatible_p(long, long long) = 0. +- */ +- if (sizeof(long) == sizeof(long long) && +- __alignof__(long) == __alignof__(long long)) +- return kstrtoll(s, base, (long long *)res); +- else +- return _kstrtol(s, base, res); +-} +- +-int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res); +-int __must_check kstrtoint(const char *s, unsigned int base, int *res); +- +-static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) +-{ +- return kstrtoull(s, base, res); +-} +- +-static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) +-{ +- return kstrtoll(s, base, res); +-} +- +-static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) +-{ +- return kstrtouint(s, base, res); +-} +- +-static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) +-{ +- return kstrtoint(s, base, res); +-} +- +-int __must_check kstrtou16(const char *s, unsigned int base, u16 *res); +-int __must_check kstrtos16(const char *s, unsigned int base, s16 *res); +-int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); +-int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); +-int __must_check kstrtobool(const char *s, bool *res); +- +-int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); +-int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); +-int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); +-int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); +-int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); +-int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); +-int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); +-int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); +-int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); +-int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); +-int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res); +- +-static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) +-{ +- return kstrtoull_from_user(s, count, base, res); +-} +- +-static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) +-{ +- return kstrtoll_from_user(s, count, base, res); +-} +- +-static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) +-{ +- return kstrtouint_from_user(s, count, base, res); +-} +- +-static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) +-{ +- return kstrtoint_from_user(s, count, base, res); +-} +- +-/* +- * Use kstrto instead. +- * +- * NOTE: simple_strto does not check for the range overflow and, +- * depending on the input, may give interesting results. +- * +- * Use these functions if and only if you cannot use kstrto, because +- * the conversion ends on the first non-digit character, which may be far +- * beyond the supported range. It might be useful to parse the strings like +- * 10x50 or 12:21 without altering original string or temporary buffer in use. +- * Keep in mind above caveat. +- */ +- +-extern unsigned long simple_strtoul(const char *,char **,unsigned int); +-extern long simple_strtol(const char *,char **,unsigned int); +-extern unsigned long long simple_strtoull(const char *,char **,unsigned int); +-extern long long simple_strtoll(const char *,char **,unsigned int); +- + extern int num_to_str(char *buf, int size, + unsigned long long num, unsigned int width); + +diff --git a/include/linux/kstrtox.h b/include/linux/kstrtox.h +new file mode 100644 +index 0000000000000..529974e22ea79 +--- /dev/null ++++ b/include/linux/kstrtox.h +@@ -0,0 +1,155 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef _LINUX_KSTRTOX_H ++#define _LINUX_KSTRTOX_H ++ ++#include ++#include ++ ++/* Internal, do not use. */ ++int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); ++int __must_check _kstrtol(const char *s, unsigned int base, long *res); ++ ++int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res); ++int __must_check kstrtoll(const char *s, unsigned int base, long long *res); ++ ++/** ++ * kstrtoul - convert a string to an unsigned long ++ * @s: The start of the string. The string must be null-terminated, and may also ++ * include a single newline before its terminating null. The first character ++ * may also be a plus sign, but not a minus sign. ++ * @base: The number base to use. The maximum supported base is 16. If base is ++ * given as 0, then the base of the string is automatically detected with the ++ * conventional semantics - If it begins with 0x the number will be parsed as a ++ * hexadecimal (case insensitive), if it otherwise begins with 0, it will be ++ * parsed as an octal number. Otherwise it will be parsed as a decimal. ++ * @res: Where to write the result of the conversion on success. ++ * ++ * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. ++ * Preferred over simple_strtoul(). Return code must be checked. ++*/ ++static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) ++{ ++ /* ++ * We want to shortcut function call, but ++ * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0. ++ */ ++ if (sizeof(unsigned long) == sizeof(unsigned long long) && ++ __alignof__(unsigned long) == __alignof__(unsigned long long)) ++ return kstrtoull(s, base, (unsigned long long *)res); ++ else ++ return _kstrtoul(s, base, res); ++} ++ ++/** ++ * kstrtol - convert a string to a long ++ * @s: The start of the string. The string must be null-terminated, and may also ++ * include a single newline before its terminating null. The first character ++ * may also be a plus sign or a minus sign. ++ * @base: The number base to use. The maximum supported base is 16. If base is ++ * given as 0, then the base of the string is automatically detected with the ++ * conventional semantics - If it begins with 0x the number will be parsed as a ++ * hexadecimal (case insensitive), if it otherwise begins with 0, it will be ++ * parsed as an octal number. Otherwise it will be parsed as a decimal. ++ * @res: Where to write the result of the conversion on success. ++ * ++ * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. ++ * Preferred over simple_strtol(). Return code must be checked. ++ */ ++static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) ++{ ++ /* ++ * We want to shortcut function call, but ++ * __builtin_types_compatible_p(long, long long) = 0. ++ */ ++ if (sizeof(long) == sizeof(long long) && ++ __alignof__(long) == __alignof__(long long)) ++ return kstrtoll(s, base, (long long *)res); ++ else ++ return _kstrtol(s, base, res); ++} ++ ++int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res); ++int __must_check kstrtoint(const char *s, unsigned int base, int *res); ++ ++static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) ++{ ++ return kstrtoull(s, base, res); ++} ++ ++static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) ++{ ++ return kstrtoll(s, base, res); ++} ++ ++static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) ++{ ++ return kstrtouint(s, base, res); ++} ++ ++static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) ++{ ++ return kstrtoint(s, base, res); ++} ++ ++int __must_check kstrtou16(const char *s, unsigned int base, u16 *res); ++int __must_check kstrtos16(const char *s, unsigned int base, s16 *res); ++int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); ++int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); ++int __must_check kstrtobool(const char *s, bool *res); ++ ++int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); ++int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); ++int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); ++int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); ++int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); ++int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); ++int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); ++int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); ++int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); ++int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); ++int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res); ++ ++static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) ++{ ++ return kstrtoull_from_user(s, count, base, res); ++} ++ ++static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) ++{ ++ return kstrtoll_from_user(s, count, base, res); ++} ++ ++static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) ++{ ++ return kstrtouint_from_user(s, count, base, res); ++} ++ ++static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) ++{ ++ return kstrtoint_from_user(s, count, base, res); ++} ++ ++/* ++ * Use kstrto instead. ++ * ++ * NOTE: simple_strto does not check for the range overflow and, ++ * depending on the input, may give interesting results. ++ * ++ * Use these functions if and only if you cannot use kstrto, because ++ * the conversion ends on the first non-digit character, which may be far ++ * beyond the supported range. It might be useful to parse the strings like ++ * 10x50 or 12:21 without altering original string or temporary buffer in use. ++ * Keep in mind above caveat. ++ */ ++ ++extern unsigned long simple_strtoul(const char *,char **,unsigned int); ++extern long simple_strtol(const char *,char **,unsigned int); ++extern unsigned long long simple_strtoull(const char *,char **,unsigned int); ++extern long long simple_strtoll(const char *,char **,unsigned int); ++ ++static inline int strtobool(const char *s, bool *res) ++{ ++ return kstrtobool(s, res); ++} ++ ++#endif /* _LINUX_KSTRTOX_H */ +diff --git a/include/linux/string.h b/include/linux/string.h +index b1f3894a0a3e4..0cef345a6e87a 100644 +--- a/include/linux/string.h ++++ b/include/linux/string.h +@@ -2,7 +2,6 @@ + #ifndef _LINUX_STRING_H_ + #define _LINUX_STRING_H_ + +- + #include /* for inline */ + #include /* for size_t */ + #include /* for NULL */ +@@ -183,12 +182,6 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp); + extern void argv_free(char **argv); + + extern bool sysfs_streq(const char *s1, const char *s2); +-extern int kstrtobool(const char *s, bool *res); +-static inline int strtobool(const char *s, bool *res) +-{ +- return kstrtobool(s, res); +-} +- + int match_string(const char * const *array, size_t n, const char *string); + int __sysfs_match_string(const char * const *array, size_t n, const char *s); + +diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h +index d0965e2997b09..b134b2b3371cf 100644 +--- a/include/linux/sunrpc/cache.h ++++ b/include/linux/sunrpc/cache.h +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + #include + + /* +diff --git a/lib/kstrtox.c b/lib/kstrtox.c +index 8504526541c13..53fa01fb75092 100644 +--- a/lib/kstrtox.c ++++ b/lib/kstrtox.c +@@ -14,11 +14,12 @@ + */ + #include + #include +-#include +-#include + #include ++#include ++#include + #include + #include ++ + #include "kstrtox.h" + + const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) +diff --git a/lib/parser.c b/lib/parser.c +index f5b3e5d7a7f95..5c37d6345cb0a 100644 +--- a/lib/parser.c ++++ b/lib/parser.c +@@ -6,6 +6,7 @@ + #include + #include + #include ++#include + #include + #include + #include +-- +2.39.2 + diff --git a/queue-5.10/lib-cleanup-kstrto-usage.patch b/queue-5.10/lib-cleanup-kstrto-usage.patch new file mode 100644 index 00000000000..b6a213e59f7 --- /dev/null +++ b/queue-5.10/lib-cleanup-kstrto-usage.patch @@ -0,0 +1,125 @@ +From d2d1c875055c41dbc34b80a0354c70d481b1face Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 15 Dec 2020 20:44:00 -0800 +Subject: lib: cleanup kstrto*() usage + +From: Alexey Dobriyan + +[ Upstream commit 506dfc9906e5cbf453bbcd5eb627689435583558 ] + +Use proper conversion functions. kstrto*() variants exist for all +standard types. + +Link: https://lkml.kernel.org/r/20201122123410.GB92364@localhost.localdomain +Signed-off-by: Alexey Dobriyan +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Stable-dep-of: 4acfe3dfde68 ("test_firmware: prevent race conditions by a correct implementation of locking") +Signed-off-by: Sasha Levin +--- + lib/test_firmware.c | 9 +++------ + lib/test_kmod.c | 26 ++++++++++---------------- + 2 files changed, 13 insertions(+), 22 deletions(-) + +diff --git a/lib/test_firmware.c b/lib/test_firmware.c +index 581ee3fcdd5c2..3edbc17d92db5 100644 +--- a/lib/test_firmware.c ++++ b/lib/test_firmware.c +@@ -371,18 +371,15 @@ static ssize_t test_dev_config_show_int(char *buf, int val) + + static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) + { ++ u8 val; + int ret; +- long new; + +- ret = kstrtol(buf, 10, &new); ++ ret = kstrtou8(buf, 10, &val); + if (ret) + return ret; + +- if (new > U8_MAX) +- return -EINVAL; +- + mutex_lock(&test_fw_mutex); +- *(u8 *)cfg = new; ++ *(u8 *)cfg = val; + mutex_unlock(&test_fw_mutex); + + /* Always return full write size even if we didn't consume all */ +diff --git a/lib/test_kmod.c b/lib/test_kmod.c +index c637f6b5053a9..c282728de3af0 100644 +--- a/lib/test_kmod.c ++++ b/lib/test_kmod.c +@@ -877,20 +877,17 @@ static int test_dev_config_update_uint_sync(struct kmod_test_device *test_dev, + int (*test_sync)(struct kmod_test_device *test_dev)) + { + int ret; +- unsigned long new; ++ unsigned int val; + unsigned int old_val; + +- ret = kstrtoul(buf, 10, &new); ++ ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + +- if (new > UINT_MAX) +- return -EINVAL; +- + mutex_lock(&test_dev->config_mutex); + + old_val = *config; +- *(unsigned int *)config = new; ++ *(unsigned int *)config = val; + + ret = test_sync(test_dev); + if (ret) { +@@ -914,18 +911,18 @@ static int test_dev_config_update_uint_range(struct kmod_test_device *test_dev, + unsigned int min, + unsigned int max) + { ++ unsigned int val; + int ret; +- unsigned long new; + +- ret = kstrtoul(buf, 10, &new); ++ ret = kstrtouint(buf, 10, &val); + if (ret) + return ret; + +- if (new < min || new > max) ++ if (val < min || val > max) + return -EINVAL; + + mutex_lock(&test_dev->config_mutex); +- *config = new; ++ *config = val; + mutex_unlock(&test_dev->config_mutex); + + /* Always return full write size even if we didn't consume all */ +@@ -936,18 +933,15 @@ static int test_dev_config_update_int(struct kmod_test_device *test_dev, + const char *buf, size_t size, + int *config) + { ++ int val; + int ret; +- long new; + +- ret = kstrtol(buf, 10, &new); ++ ret = kstrtoint(buf, 10, &val); + if (ret) + return ret; + +- if (new < INT_MIN || new > INT_MAX) +- return -EINVAL; +- + mutex_lock(&test_dev->config_mutex); +- *config = new; ++ *config = val; + mutex_unlock(&test_dev->config_mutex); + /* Always return full write size even if we didn't consume all */ + return size; +-- +2.39.2 + diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 00000000000..88fbd7f1a0a --- /dev/null +++ b/queue-5.10/series @@ -0,0 +1,5 @@ +lib-cleanup-kstrto-usage.patch +kernel.h-split-out-kstrtox-and-simple_strtox-to-a-se.patch +test_firmware-use-kstrtobool-instead-of-strtobool.patch +test_firmware-prevent-race-conditions-by-a-correct-i.patch +test_firmware-fix-a-memory-leak-with-reqs-buffer.patch diff --git a/queue-5.10/test_firmware-fix-a-memory-leak-with-reqs-buffer.patch b/queue-5.10/test_firmware-fix-a-memory-leak-with-reqs-buffer.patch new file mode 100644 index 00000000000..6ad09e43fde --- /dev/null +++ b/queue-5.10/test_firmware-fix-a-memory-leak-with-reqs-buffer.patch @@ -0,0 +1,72 @@ +From 594fce489a5f007448138bf3a876c96ab468a680 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 May 2023 10:47:47 +0200 +Subject: test_firmware: fix a memory leak with reqs buffer + +From: Mirsad Goran Todorovac + +[ Upstream commit be37bed754ed90b2655382f93f9724b3c1aae847 ] + +Dan Carpenter spotted that test_fw_config->reqs will be leaked if +trigger_batched_requests_store() is called two or more times. +The same appears with trigger_batched_requests_async_store(). + +This bug wasn't trigger by the tests, but observed by Dan's visual +inspection of the code. + +The recommended workaround was to return -EBUSY if test_fw_config->reqs +is already allocated. + +Fixes: 7feebfa487b92 ("test_firmware: add support for request_firmware_into_buf") +Cc: Luis Chamberlain +Cc: Greg Kroah-Hartman +Cc: Russ Weight +Cc: Tianfei Zhang +Cc: Shuah Khan +Cc: Colin Ian King +Cc: Randy Dunlap +Cc: linux-kselftest@vger.kernel.org +Cc: stable@vger.kernel.org # v5.4 +Suggested-by: Dan Carpenter +Suggested-by: Takashi Iwai +Signed-off-by: Mirsad Goran Todorovac +Reviewed-by: Dan Carpenter +Acked-by: Luis Chamberlain +Link: https://lore.kernel.org/r/20230509084746.48259-2-mirsad.todorovac@alu.unizg.hr +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + lib/test_firmware.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/lib/test_firmware.c b/lib/test_firmware.c +index 4884057eb53f0..ed0455a9ded87 100644 +--- a/lib/test_firmware.c ++++ b/lib/test_firmware.c +@@ -863,6 +863,11 @@ static ssize_t trigger_batched_requests_store(struct device *dev, + + mutex_lock(&test_fw_mutex); + ++ if (test_fw_config->reqs) { ++ rc = -EBUSY; ++ goto out_bail; ++ } ++ + test_fw_config->reqs = + vzalloc(array3_size(sizeof(struct test_batched_req), + test_fw_config->num_requests, 2)); +@@ -962,6 +967,11 @@ ssize_t trigger_batched_requests_async_store(struct device *dev, + + mutex_lock(&test_fw_mutex); + ++ if (test_fw_config->reqs) { ++ rc = -EBUSY; ++ goto out_bail; ++ } ++ + test_fw_config->reqs = + vzalloc(array3_size(sizeof(struct test_batched_req), + test_fw_config->num_requests, 2)); +-- +2.39.2 + diff --git a/queue-5.10/test_firmware-prevent-race-conditions-by-a-correct-i.patch b/queue-5.10/test_firmware-prevent-race-conditions-by-a-correct-i.patch new file mode 100644 index 00000000000..ac56d6e647a --- /dev/null +++ b/queue-5.10/test_firmware-prevent-race-conditions-by-a-correct-i.patch @@ -0,0 +1,259 @@ +From 6ae01c473c618ec38a072781a00dbb5938f2cb74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 9 May 2023 10:47:45 +0200 +Subject: test_firmware: prevent race conditions by a correct implementation of + locking + +From: Mirsad Goran Todorovac + +[ Upstream commit 4acfe3dfde685a5a9eaec5555351918e2d7266a1 ] + +Dan Carpenter spotted a race condition in a couple of situations like +these in the test_firmware driver: + +static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) +{ + u8 val; + int ret; + + ret = kstrtou8(buf, 10, &val); + if (ret) + return ret; + + mutex_lock(&test_fw_mutex); + *(u8 *)cfg = val; + mutex_unlock(&test_fw_mutex); + + /* Always return full write size even if we didn't consume all */ + return size; +} + +static ssize_t config_num_requests_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + + mutex_lock(&test_fw_mutex); + if (test_fw_config->reqs) { + pr_err("Must call release_all_firmware prior to changing config\n"); + rc = -EINVAL; + mutex_unlock(&test_fw_mutex); + goto out; + } + mutex_unlock(&test_fw_mutex); + + rc = test_dev_config_update_u8(buf, count, + &test_fw_config->num_requests); + +out: + return rc; +} + +static ssize_t config_read_fw_idx_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + return test_dev_config_update_u8(buf, count, + &test_fw_config->read_fw_idx); +} + +The function test_dev_config_update_u8() is called from both the locked +and the unlocked context, function config_num_requests_store() and +config_read_fw_idx_store() which can both be called asynchronously as +they are driver's methods, while test_dev_config_update_u8() and siblings +change their argument pointed to by u8 *cfg or similar pointer. + +To avoid deadlock on test_fw_mutex, the lock is dropped before calling +test_dev_config_update_u8() and re-acquired within test_dev_config_update_u8() +itself, but alas this creates a race condition. + +Having two locks wouldn't assure a race-proof mutual exclusion. + +This situation is best avoided by the introduction of a new, unlocked +function __test_dev_config_update_u8() which can be called from the locked +context and reducing test_dev_config_update_u8() to: + +static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) +{ + int ret; + + mutex_lock(&test_fw_mutex); + ret = __test_dev_config_update_u8(buf, size, cfg); + mutex_unlock(&test_fw_mutex); + + return ret; +} + +doing the locking and calling the unlocked primitive, which enables both +locked and unlocked versions without duplication of code. + +The similar approach was applied to all functions called from the locked +and the unlocked context, which safely mitigates both deadlocks and race +conditions in the driver. + +__test_dev_config_update_bool(), __test_dev_config_update_u8() and +__test_dev_config_update_size_t() unlocked versions of the functions +were introduced to be called from the locked contexts as a workaround +without releasing the main driver's lock and thereof causing a race +condition. + +The test_dev_config_update_bool(), test_dev_config_update_u8() and +test_dev_config_update_size_t() locked versions of the functions +are being called from driver methods without the unnecessary multiplying +of the locking and unlocking code for each method, and complicating +the code with saving of the return value across lock. + +Fixes: 7feebfa487b92 ("test_firmware: add support for request_firmware_into_buf") +Cc: Luis Chamberlain +Cc: Greg Kroah-Hartman +Cc: Russ Weight +Cc: Takashi Iwai +Cc: Tianfei Zhang +Cc: Shuah Khan +Cc: Colin Ian King +Cc: Randy Dunlap +Cc: linux-kselftest@vger.kernel.org +Cc: stable@vger.kernel.org # v5.4 +Suggested-by: Dan Carpenter +Signed-off-by: Mirsad Goran Todorovac +Link: https://lore.kernel.org/r/20230509084746.48259-1-mirsad.todorovac@alu.unizg.hr +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Sasha Levin +--- + lib/test_firmware.c | 52 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 35 insertions(+), 17 deletions(-) + +diff --git a/lib/test_firmware.c b/lib/test_firmware.c +index b99cf0a50a698..4884057eb53f0 100644 +--- a/lib/test_firmware.c ++++ b/lib/test_firmware.c +@@ -321,16 +321,26 @@ static ssize_t config_test_show_str(char *dst, + return len; + } + +-static int test_dev_config_update_bool(const char *buf, size_t size, ++static inline int __test_dev_config_update_bool(const char *buf, size_t size, + bool *cfg) + { + int ret; + +- mutex_lock(&test_fw_mutex); + if (kstrtobool(buf, cfg) < 0) + ret = -EINVAL; + else + ret = size; ++ ++ return ret; ++} ++ ++static int test_dev_config_update_bool(const char *buf, size_t size, ++ bool *cfg) ++{ ++ int ret; ++ ++ mutex_lock(&test_fw_mutex); ++ ret = __test_dev_config_update_bool(buf, size, cfg); + mutex_unlock(&test_fw_mutex); + + return ret; +@@ -341,7 +351,8 @@ static ssize_t test_dev_config_show_bool(char *buf, bool val) + return snprintf(buf, PAGE_SIZE, "%d\n", val); + } + +-static int test_dev_config_update_size_t(const char *buf, ++static int __test_dev_config_update_size_t( ++ const char *buf, + size_t size, + size_t *cfg) + { +@@ -352,9 +363,7 @@ static int test_dev_config_update_size_t(const char *buf, + if (ret) + return ret; + +- mutex_lock(&test_fw_mutex); + *(size_t *)cfg = new; +- mutex_unlock(&test_fw_mutex); + + /* Always return full write size even if we didn't consume all */ + return size; +@@ -370,7 +379,7 @@ static ssize_t test_dev_config_show_int(char *buf, int val) + return snprintf(buf, PAGE_SIZE, "%d\n", val); + } + +-static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) ++static int __test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) + { + u8 val; + int ret; +@@ -379,14 +388,23 @@ static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) + if (ret) + return ret; + +- mutex_lock(&test_fw_mutex); + *(u8 *)cfg = val; +- mutex_unlock(&test_fw_mutex); + + /* Always return full write size even if we didn't consume all */ + return size; + } + ++static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg) ++{ ++ int ret; ++ ++ mutex_lock(&test_fw_mutex); ++ ret = __test_dev_config_update_u8(buf, size, cfg); ++ mutex_unlock(&test_fw_mutex); ++ ++ return ret; ++} ++ + static ssize_t test_dev_config_show_u8(char *buf, u8 val) + { + return snprintf(buf, PAGE_SIZE, "%u\n", val); +@@ -413,10 +431,10 @@ static ssize_t config_num_requests_store(struct device *dev, + mutex_unlock(&test_fw_mutex); + goto out; + } +- mutex_unlock(&test_fw_mutex); + +- rc = test_dev_config_update_u8(buf, count, +- &test_fw_config->num_requests); ++ rc = __test_dev_config_update_u8(buf, count, ++ &test_fw_config->num_requests); ++ mutex_unlock(&test_fw_mutex); + + out: + return rc; +@@ -460,10 +478,10 @@ static ssize_t config_buf_size_store(struct device *dev, + mutex_unlock(&test_fw_mutex); + goto out; + } +- mutex_unlock(&test_fw_mutex); + +- rc = test_dev_config_update_size_t(buf, count, +- &test_fw_config->buf_size); ++ rc = __test_dev_config_update_size_t(buf, count, ++ &test_fw_config->buf_size); ++ mutex_unlock(&test_fw_mutex); + + out: + return rc; +@@ -490,10 +508,10 @@ static ssize_t config_file_offset_store(struct device *dev, + mutex_unlock(&test_fw_mutex); + goto out; + } +- mutex_unlock(&test_fw_mutex); + +- rc = test_dev_config_update_size_t(buf, count, +- &test_fw_config->file_offset); ++ rc = __test_dev_config_update_size_t(buf, count, ++ &test_fw_config->file_offset); ++ mutex_unlock(&test_fw_mutex); + + out: + return rc; +-- +2.39.2 + diff --git a/queue-5.10/test_firmware-use-kstrtobool-instead-of-strtobool.patch b/queue-5.10/test_firmware-use-kstrtobool-instead-of-strtobool.patch new file mode 100644 index 00000000000..a13d7be7ec8 --- /dev/null +++ b/queue-5.10/test_firmware-use-kstrtobool-instead-of-strtobool.patch @@ -0,0 +1,51 @@ +From e86096fc8ade63ea7dc9e6c537e6266cee79e3ad Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Jan 2023 10:22:03 +0100 +Subject: test_firmware: Use kstrtobool() instead of strtobool() + +From: Christophe JAILLET + +[ Upstream commit f7d85515bd21902b218370a1a6301f76e4e636ff ] + +strtobool() is the same as kstrtobool(). +However, the latter is more used within the kernel. + +In order to remove strtobool() and slightly simplify kstrtox.h, switch to +the other function name. + +While at it, include the corresponding header file () + +Signed-off-by: Christophe JAILLET +Acked-by: Luis Chamberlain +Link: https://lore.kernel.org/r/34f04735d20e0138695dd4070651bd860a36b81c.1673688120.git.christophe.jaillet@wanadoo.fr +Signed-off-by: Greg Kroah-Hartman +Stable-dep-of: 4acfe3dfde68 ("test_firmware: prevent race conditions by a correct implementation of locking") +Signed-off-by: Sasha Levin +--- + lib/test_firmware.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/lib/test_firmware.c b/lib/test_firmware.c +index 3edbc17d92db5..b99cf0a50a698 100644 +--- a/lib/test_firmware.c ++++ b/lib/test_firmware.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -326,7 +327,7 @@ static int test_dev_config_update_bool(const char *buf, size_t size, + int ret; + + mutex_lock(&test_fw_mutex); +- if (strtobool(buf, cfg) < 0) ++ if (kstrtobool(buf, cfg) < 0) + ret = -EINVAL; + else + ret = size; +-- +2.39.2 + -- 2.47.2