FAILED: patch "[PATCH] smp/hotplug: Handle removal correctly in" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
Quoted 1 line
From
0c96b27305faf06c068b45e07d28336c80dac286Mon Sep 17 00:00:00 2001
From: Ethan Barnes <[email protected]>
Date: Wed, 19 Jul 2017 22:36:00 +0000
Subject: [PATCH] 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 ]
kernel/cpu.c +11 -1
@@ -1252,7 +1252,17 @@ static int cpuhp_store_callbacks(enum cpuhp_state state, const char *name,struct cpuhp_step *sp;int ret =0 ; -if (state ==CPUHP_AP_ONLINE_DYN || state ==CPUHP_BP_PREPARE_DYN ) { +/* +* If name is NULL, then the state gets removed. +* +* CPUHP_AP_ONLINE_DYN and CPUHP_BP_PREPARE_DYN are handed out on +* the first allocation from these dynamic ranges, so the removal +* would trigger a new allocation and clear the wrong (already +* empty) state, leaving the callbacks of the to be cleared state +* dangling, which causes wreckage on the next hotplug operation. +*/ +if (name && (state ==CPUHP_AP_ONLINE_DYN || + state ==CPUHP_BP_PREPARE_DYN )) { ret =cpuhp_reserve_state (state);if (ret <0 )return ret;