Skip to content

Commit 0c96b27

Browse files
Ethan BarnesKAGA-KOKO
authored andcommitted
smp/hotplug: Handle removal correctly in cpuhp_store_callbacks()
If cpuhp_store_callbacks() is called for CPUHP_AP_ONLINE_DYN or CPUHP_BP_PREPARE_DYN, which are the indicators for dynamically allocated states, then cpuhp_store_callbacks() allocates a new dynamic state. The first allocation in each range returns CPUHP_AP_ONLINE_DYN or CPUHP_BP_PREPARE_DYN. If cpuhp_remove_state() is invoked for one of these states, then there is no protection against the allocation mechanism. So the removal, which should clear the callbacks and the name, gets a new state assigned and clears that one. As a consequence the state which should be cleared stays initialized. A consecutive CPU hotplug operation dereferences the state callbacks and accesses either freed or reused memory, resulting in crashes. Add a protection against this by checking the name argument for NULL. If it's NULL it's a removal. If not, it's an allocation. [ tglx: Added a comment and massaged changelog ] Fixes: 5b7aa87 ("cpu/hotplug: Implement setup/removal interface") Signed-off-by: Ethan Barnes <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: "Srivatsa S. Bhat" <[email protected]> Cc: Sebastian Siewior <[email protected]> Cc: Paul McKenney <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/DM2PR04MB398242FC7776D603D9F99C894A60@DM2PR04MB398.namprd04.prod.outlook.com
1 parent 935acd3 commit 0c96b27

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

kernel/cpu.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,17 @@ static int cpuhp_store_callbacks(enum cpuhp_state state, const char *name,
12521252
struct cpuhp_step *sp;
12531253
int ret = 0;
12541254

1255-
if (state == CPUHP_AP_ONLINE_DYN || state == CPUHP_BP_PREPARE_DYN) {
1255+
/*
1256+
* If name is NULL, then the state gets removed.
1257+
*
1258+
* CPUHP_AP_ONLINE_DYN and CPUHP_BP_PREPARE_DYN are handed out on
1259+
* the first allocation from these dynamic ranges, so the removal
1260+
* would trigger a new allocation and clear the wrong (already
1261+
* empty) state, leaving the callbacks of the to be cleared state
1262+
* dangling, which causes wreckage on the next hotplug operation.
1263+
*/
1264+
if (name && (state == CPUHP_AP_ONLINE_DYN ||
1265+
state == CPUHP_BP_PREPARE_DYN)) {
12561266
ret = cpuhp_reserve_state(state);
12571267
if (ret < 0)
12581268
return ret;

0 commit comments

Comments
 (0)