Skip to contentSkip to conversation

clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider

PATCH Applied Gustavo A. R. Silva 2 participants 2 messages Nov 14, 2024

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 clk: clk-loongson2: Fix memory corruption bug in struct loongson2_clk_provider

Some heap space is allocated for the flexible structure struct clk_hw_onecell_data and its flexible-array member hws through the composite structure struct loongson2_clk_provider in function loongson2_clk_probe(), as shown below:

289         struct loongson2_clk_provider *clp;
	...

296 for (p = data; p->name; p++)
297 clks_num++;
298
299 clp = devm_kzalloc(dev, struct_size(clp, clk_data.hws, clks_num),
300 GFP_KERNEL);

Then some data is written into the flexible array:

350 clp->clk_data.hws[p->id] = hw;

This corrupts clk_lock, which is the spinlock variable immediately following the clk_data member in struct loongson2_clk_provider:

struct loongson2_clk_provider {
	void __iomem *base;
	struct device *dev;
	struct clk_hw_onecell_data clk_data;
	spinlock_t clk_lock;	/* protect access to DIV registers */
};

The problem is that the flexible structure is currently placed in the middle of struct loongson2_clk_provider instead of at the end.

Fix this by moving struct clk_hw_onecell_data clk_data; to the end of struct loongson2_clk_provider. Also, add a code comment to help prevent this from happening again in case new members are added to the structure in the future.

This change also fixes the following -Wflex-array-member-not-at-end warning:

drivers/clk/clk-loongson2.c:32:36: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

Fixes 9796ec0bd04b ("clk: clk-loongson2: Refactor driver for adding new platforms")
---
 drivers/clk/clk-loongson2.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/clk/clk-loongson2.c +3 -1
index 820bb1e9e3b7..e99ba79feec6 100644
@@ -29,8 +29,10 @@ enum loongson2_clk_type {
 struct loongson2_clk_provider {
 	void __iomem *base;
 	struct device *dev;
-	struct clk_hw_onecell_data clk_data;
 	spinlock_t clk_lock;	/* protect access to DIV registers */
+
+	/* Must be last --ends in a flexible-array member. */
+	struct clk_hw_onecell_data clk_data;
 };
 
 struct loongson2_clk_data {
Signature · 1 line
2.43.0
maintainer Applied
#1 lore raw

Quoting Gustavo A. R. Silva (2024-11-14 14:49:21)

Quoted 38 lines

Some heap space is allocated for the flexible structure struct clk_hw_onecell_data and its flexible-array member hws through the composite structure struct loongson2_clk_provider in function loongson2_clk_probe(), as shown below:

289         struct loongson2_clk_provider *clp;
        ...

296 for (p = data; p->name; p++)
297 clks_num++;
298
299 clp = devm_kzalloc(dev, struct_size(clp, clk_data.hws, clks_num),
300 GFP_KERNEL);

Then some data is written into the flexible array:

350 clp->clk_data.hws[p->id] = hw;

This corrupts clk_lock, which is the spinlock variable immediately following the clk_data member in struct loongson2_clk_provider:

struct loongson2_clk_provider {
        void __iomem *base;
        struct device *dev;
        struct clk_hw_onecell_data clk_data;
        spinlock_t clk_lock;    /* protect access to DIV registers */
};

The problem is that the flexible structure is currently placed in the middle of struct loongson2_clk_provider instead of at the end.

Fix this by moving struct clk_hw_onecell_data clk_data; to the end of struct loongson2_clk_provider. Also, add a code comment to help prevent this from happening again in case new members are added to the structure in the future.

This change also fixes the following -Wflex-array-member-not-at-end warning:

Quoted 6 lines

drivers/clk/clk-loongson2.c:32:36: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

Fixes 9796ec0bd04b ("clk: clk-loongson2: Refactor driver for adding new platforms")

---

Applied to clk-next