From c39c53176b2d08e372c2733349fbdeeb24550f6d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 12 Jan 2025 13:35:59 +0100 Subject: [PATCH] 5.10-stable patches added patches: md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch --- ...icity-violation-in-raid5_cache_count.patch | 114 ++++++++++++++++++ ...o-maintain-symmetry-and-transitivity.patch | 68 +++++++++++ queue-5.10/series | 2 + 3 files changed, 184 insertions(+) create mode 100644 queue-5.10/md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch create mode 100644 queue-5.10/scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch diff --git a/queue-5.10/md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch b/queue-5.10/md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch new file mode 100644 index 00000000000..f84cc5c1af2 --- /dev/null +++ b/queue-5.10/md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch @@ -0,0 +1,114 @@ +From dfd2bf436709b2bccb78c2dda550dde93700efa7 Mon Sep 17 00:00:00 2001 +From: Gui-Dong Han <2045gemini@gmail.com> +Date: Fri, 12 Jan 2024 15:10:17 +0800 +Subject: md/raid5: fix atomicity violation in raid5_cache_count + +From: Gui-Dong Han <2045gemini@gmail.com> + +commit dfd2bf436709b2bccb78c2dda550dde93700efa7 upstream. + +In raid5_cache_count(): + if (conf->max_nr_stripes < conf->min_nr_stripes) + return 0; + return conf->max_nr_stripes - conf->min_nr_stripes; +The current check is ineffective, as the values could change immediately +after being checked. + +In raid5_set_cache_size(): + ... + conf->min_nr_stripes = size; + ... + while (size > conf->max_nr_stripes) + conf->min_nr_stripes = conf->max_nr_stripes; + ... + +Due to intermediate value updates in raid5_set_cache_size(), concurrent +execution of raid5_cache_count() and raid5_set_cache_size() may lead to +inconsistent reads of conf->max_nr_stripes and conf->min_nr_stripes. +The current checks are ineffective as values could change immediately +after being checked, raising the risk of conf->min_nr_stripes exceeding +conf->max_nr_stripes and potentially causing an integer overflow. + +This possible bug is found by an experimental static analysis tool +developed by our team. This tool analyzes the locking APIs to extract +function pairs that can be concurrently executed, and then analyzes the +instructions in the paired functions to identify possible concurrency bugs +including data races and atomicity violations. The above possible bug is +reported when our tool analyzes the source code of Linux 6.2. + +To resolve this issue, it is suggested to introduce local variables +'min_stripes' and 'max_stripes' in raid5_cache_count() to ensure the +values remain stable throughout the check. Adding locks in +raid5_cache_count() fails to resolve atomicity violations, as +raid5_set_cache_size() may hold intermediate values of +conf->min_nr_stripes while unlocked. With this patch applied, our tool no +longer reports the bug, with the kernel configuration allyesconfig for +x86_64. Due to the lack of associated hardware, we cannot test the patch +in runtime testing, and just verify it according to the code logic. + +Fixes: edbe83ab4c27 ("md/raid5: allow the stripe_cache to grow and shrink.") +Cc: stable@vger.kernel.org +Signed-off-by: Gui-Dong Han <2045gemini@gmail.com> +Reviewed-by: Yu Kuai +Signed-off-by: Song Liu +Link: https://lore.kernel.org/r/20240112071017.16313-1-2045gemini@gmail.com +Signed-off-by: Song Liu +Signed-off-by: Greg Kroah-Hartman +--- + drivers/md/raid5.c | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +--- a/drivers/md/raid5.c ++++ b/drivers/md/raid5.c +@@ -2349,7 +2349,7 @@ static int grow_one_stripe(struct r5conf + atomic_inc(&conf->active_stripes); + + raid5_release_stripe(sh); +- conf->max_nr_stripes++; ++ WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes + 1); + return 1; + } + +@@ -2646,7 +2646,7 @@ static int drop_one_stripe(struct r5conf + shrink_buffers(sh); + free_stripe(conf->slab_cache, sh); + atomic_dec(&conf->active_stripes); +- conf->max_nr_stripes--; ++ WRITE_ONCE(conf->max_nr_stripes, conf->max_nr_stripes - 1); + return 1; + } + +@@ -6575,7 +6575,7 @@ raid5_set_cache_size(struct mddev *mddev + if (size <= 16 || size > 32768) + return -EINVAL; + +- conf->min_nr_stripes = size; ++ WRITE_ONCE(conf->min_nr_stripes, size); + mutex_lock(&conf->cache_size_mutex); + while (size < conf->max_nr_stripes && + drop_one_stripe(conf)) +@@ -6587,7 +6587,7 @@ raid5_set_cache_size(struct mddev *mddev + mutex_lock(&conf->cache_size_mutex); + while (size > conf->max_nr_stripes) + if (!grow_one_stripe(conf, GFP_KERNEL)) { +- conf->min_nr_stripes = conf->max_nr_stripes; ++ WRITE_ONCE(conf->min_nr_stripes, conf->max_nr_stripes); + result = -ENOMEM; + break; + } +@@ -7151,11 +7151,13 @@ static unsigned long raid5_cache_count(s + struct shrink_control *sc) + { + struct r5conf *conf = container_of(shrink, struct r5conf, shrinker); ++ int max_stripes = READ_ONCE(conf->max_nr_stripes); ++ int min_stripes = READ_ONCE(conf->min_nr_stripes); + +- if (conf->max_nr_stripes < conf->min_nr_stripes) ++ if (max_stripes < min_stripes) + /* unlikely, but not impossible */ + return 0; +- return conf->max_nr_stripes - conf->min_nr_stripes; ++ return max_stripes - min_stripes; + } + + static struct r5conf *setup_conf(struct mddev *mddev) diff --git a/queue-5.10/scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch b/queue-5.10/scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch new file mode 100644 index 00000000000..2c2b4eaaba6 --- /dev/null +++ b/queue-5.10/scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch @@ -0,0 +1,68 @@ +From 0210d251162f4033350a94a43f95b1c39ec84a90 Mon Sep 17 00:00:00 2001 +From: Kuan-Wei Chiu +Date: Thu, 26 Dec 2024 22:03:32 +0800 +Subject: scripts/sorttable: fix orc_sort_cmp() to maintain symmetry and transitivity + +From: Kuan-Wei Chiu + +commit 0210d251162f4033350a94a43f95b1c39ec84a90 upstream. + +The orc_sort_cmp() function, used with qsort(), previously violated the +symmetry and transitivity rules required by the C standard. Specifically, +when both entries are ORC_TYPE_UNDEFINED, it could result in both a < b +and b < a, which breaks the required symmetry and transitivity. This can +lead to undefined behavior and incorrect sorting results, potentially +causing memory corruption in glibc implementations [1]. + +Symmetry: If x < y, then y > x. +Transitivity: If x < y and y < z, then x < z. + +Fix the comparison logic to return 0 when both entries are +ORC_TYPE_UNDEFINED, ensuring compliance with qsort() requirements. + +Link: https://www.qualys.com/2024/01/30/qsort.txt [1] +Link: https://lkml.kernel.org/r/20241226140332.2670689-1-visitorckw@gmail.com +Fixes: 57fa18994285 ("scripts/sorttable: Implement build-time ORC unwind table sorting") +Fixes: fb799447ae29 ("x86,objtool: Split UNWIND_HINT_EMPTY in two") +Signed-off-by: Kuan-Wei Chiu +Cc: Ching-Chun (Jim) Huang +Cc: +Cc: Ingo Molnar +Cc: Josh Poimboeuf +Cc: Peter Zijlstra +Cc: Shile Zhang +Cc: Steven Rostedt +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Kuan-Wei Chiu +Signed-off-by: Greg Kroah-Hartman +--- + scripts/sorttable.h | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +--- a/scripts/sorttable.h ++++ b/scripts/sorttable.h +@@ -103,7 +103,7 @@ static inline unsigned long orc_ip(const + + static int orc_sort_cmp(const void *_a, const void *_b) + { +- struct orc_entry *orc_a; ++ struct orc_entry *orc_a, *orc_b; + const int *a = g_orc_ip_table + *(int *)_a; + const int *b = g_orc_ip_table + *(int *)_b; + unsigned long a_val = orc_ip(a); +@@ -120,8 +120,12 @@ static int orc_sort_cmp(const void *_a, + * These terminator entries exist to handle any gaps created by + * whitelisted .o files which didn't get objtool generation. + */ +- orc_a = g_orc_table + (a - g_orc_ip_table); +- return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; ++ orc_a = g_orc_table + (a - g_orc_ip_table); ++ orc_b = g_orc_table + (b - g_orc_ip_table); ++ if (orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end && ++ orc_b->sp_reg == ORC_REG_UNDEFINED && !orc_b->end) ++ return 0; ++ return orc_a->sp_reg == ORC_REG_UNDEFINED && !orc_a->end ? -1 : 1; + } + + static void *sort_orctable(void *arg) diff --git a/queue-5.10/series b/queue-5.10/series index 78ee7d672e0..273276439c6 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -26,3 +26,5 @@ riscv-fix-sleeping-in-invalid-context-in-die.patch acpi-resource-add-tongfang-gm5hg0a-to-irq1_edge_low_force_override.patch acpi-resource-add-asus-vivobook-x1504vap-to-irq1_level_low_skip_override.patch drm-amd-display-increase-max_surfaces-to-the-value-supported-by-hw.patch +scripts-sorttable-fix-orc_sort_cmp-to-maintain-symmetry-and-transitivity.patch +md-raid5-fix-atomicity-violation-in-raid5_cache_count.patch -- 2.47.3