From: Oliver O'Halloran <oohall@gmail.com> Date: 2020-02-06 06:28:07
The cpufreq driver has a use-after-free that we can hit if:
a) There's an OCC message pending when the notifier is registered, and
b) The cpufreq driver fails to register with the core.
When a) occurs the notifier schedules a workqueue item to handle the
message. The backing work_struct is located on chips[].throttle and when b)
happens we clean up by freeing the array. Once we get to the (now free)
queued item and the kernel crashes.
Cc: Vaidyanathan Srinivasan <redacted>
Fixes: c5e29ea ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}")
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
---
drivers/cpufreq/powernv-cpufreq.c | 6 ++++++
1 file changed, 6 insertions(+)
@@ -1080,6 +1080,12 @@ static int init_chip_info(void)staticinlinevoidclean_chip_info(void){+inti;++/* flush any pending work items */+if(chips)+for(i=0;i<nr_chips;i++)+cancel_work_sync(&chips[i].throttle);kfree(chips);}
From: Oliver O'Halloran <oohall@gmail.com> Date: 2020-02-06 06:29:31
The PowerNV cpufreq driver registers two notifiers: one to catch throttle
messages from the OCC and one to bump the CPU frequency back to normal
before a reboot. Both require the cpufreq driver to be registered in order
to function since the notifier callbacks use various cpufreq_*() functions.
Right now we register both notifiers before we've initialised the driver.
This seems to work, but we should head off any protential problems by
registering the notifiers after the driver is initialised.
Cc: Vaidyanathan Srinivasan <redacted>
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
---
drivers/cpufreq/powernv-cpufreq.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
@@ -1114,9 +1114,6 @@ static int __init powernv_cpufreq_init(void)if(rc)gotoout;-register_reboot_notifier(&powernv_cpufreq_reboot_nb);-opal_message_notifier_register(OPAL_MSG_OCC,&powernv_cpufreq_opal_nb);-if(powernv_pstate_info.wof_enabled)powernv_cpufreq_driver.boost_enabled=true;else
@@ -1125,15 +1122,17 @@ static int __init powernv_cpufreq_init(void)rc=cpufreq_register_driver(&powernv_cpufreq_driver);if(rc){pr_info("Failed to register the cpufreq driver (%d)\n",rc);-gotocleanup_notifiers;+gotocleanup;}if(powernv_pstate_info.wof_enabled)cpufreq_enable_boost_support();+register_reboot_notifier(&powernv_cpufreq_reboot_nb);+opal_message_notifier_register(OPAL_MSG_OCC,&powernv_cpufreq_opal_nb);+return0;-cleanup_notifiers:-unregister_all_notifiers();+cleanup:clean_chip_info();out:pr_info("Platform driver disabled. System does not support PState control\n");
From: Gautham R Shenoy <hidden> Date: 2020-02-25 06:42:45
On Thu, Feb 06, 2020 at 05:26:21PM +1100, Oliver O'Halloran wrote:
The cpufreq driver has a use-after-free that we can hit if:
a) There's an OCC message pending when the notifier is registered, and
b) The cpufreq driver fails to register with the core.
When a) occurs the notifier schedules a workqueue item to handle the
message. The backing work_struct is located on chips[].throttle and when b)
happens we clean up by freeing the array. Once we get to the (now free)
queued item and the kernel crashes.
Cc: Vaidyanathan Srinivasan <redacted>
Fixes: c5e29ea ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}")
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
Thanks for this fix Oliver.
Reviewed-by: Gautham R. Shenoy <redacted>
@@ -1080,6 +1080,12 @@ static int init_chip_info(void)staticinlinevoidclean_chip_info(void){+inti;++/* flush any pending work items */+if(chips)+for(i=0;i<nr_chips;i++)+cancel_work_sync(&chips[i].throttle);kfree(chips);}
From: Gautham R Shenoy <hidden> Date: 2020-02-25 06:45:56
On Thu, Feb 06, 2020 at 05:26:22PM +1100, Oliver O'Halloran wrote:
The PowerNV cpufreq driver registers two notifiers: one to catch throttle
messages from the OCC and one to bump the CPU frequency back to normal
before a reboot. Both require the cpufreq driver to be registered in order
to function since the notifier callbacks use various cpufreq_*() functions.
Right now we register both notifiers before we've initialised the driver.
This seems to work, but we should head off any protential problems by
registering the notifiers after the driver is initialised.
Cc: Vaidyanathan Srinivasan <redacted>
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
@@ -1114,9 +1114,6 @@ static int __init powernv_cpufreq_init(void)if(rc)gotoout;-register_reboot_notifier(&powernv_cpufreq_reboot_nb);-opal_message_notifier_register(OPAL_MSG_OCC,&powernv_cpufreq_opal_nb);-if(powernv_pstate_info.wof_enabled)powernv_cpufreq_driver.boost_enabled=true;else
@@ -1125,15 +1122,17 @@ static int __init powernv_cpufreq_init(void)rc=cpufreq_register_driver(&powernv_cpufreq_driver);if(rc){pr_info("Failed to register the cpufreq driver (%d)\n",rc);-gotocleanup_notifiers;+gotocleanup;}if(powernv_pstate_info.wof_enabled)cpufreq_enable_boost_support();+register_reboot_notifier(&powernv_cpufreq_reboot_nb);+opal_message_notifier_register(OPAL_MSG_OCC,&powernv_cpufreq_opal_nb);+return0;-cleanup_notifiers:-unregister_all_notifiers();+cleanup:clean_chip_info();out:pr_info("Platform driver disabled. System does not support PState control\n");
From: Andrew Donnellan <hidden> Date: 2020-02-25 07:06:19
On 6/2/20 5:26 pm, Oliver O'Halloran wrote:
The cpufreq driver has a use-after-free that we can hit if:
a) There's an OCC message pending when the notifier is registered, and
b) The cpufreq driver fails to register with the core.
When a) occurs the notifier schedules a workqueue item to handle the
message. The backing work_struct is located on chips[].throttle and when b)
happens we clean up by freeing the array. Once we get to the (now free)
queued item and the kernel crashes.
Cc: Vaidyanathan Srinivasan <redacted>
Fixes: c5e29ea ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}")
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
This sounds like it needs to go to stable.
--
Andrew Donnellan OzLabs, ADL Canberra
ajd@linux.ibm.com IBM Australia Limited
From: Michael Ellerman <mpe@ellerman.id.au> Date: 2020-02-27 01:33:08
Andrew Donnellan [off-list ref] writes:
On 6/2/20 5:26 pm, Oliver O'Halloran wrote:
quoted
The cpufreq driver has a use-after-free that we can hit if:
a) There's an OCC message pending when the notifier is registered, and
b) The cpufreq driver fails to register with the core.
When a) occurs the notifier schedules a workqueue item to handle the
message. The backing work_struct is located on chips[].throttle and when b)
happens we clean up by freeing the array. Once we get to the (now free)
queued item and the kernel crashes.
Cc: Vaidyanathan Srinivasan <redacted>
Fixes: c5e29ea ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}")
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
From: Michael Ellerman <hidden> Date: 2020-03-17 13:33:11
On Thu, 2020-02-06 at 06:26:21 UTC, Oliver O'Halloran wrote:
The cpufreq driver has a use-after-free that we can hit if:
a) There's an OCC message pending when the notifier is registered, and
b) The cpufreq driver fails to register with the core.
When a) occurs the notifier schedules a workqueue item to handle the
message. The backing work_struct is located on chips[].throttle and when b)
happens we clean up by freeing the array. Once we get to the (now free)
queued item and the kernel crashes.
Cc: Vaidyanathan Srinivasan <redacted>
Fixes: c5e29ea ("cpufreq: powernv: Fix bugs in powernv_cpufreq_{init/exit}")
Signed-off-by: Oliver O'Halloran <oohall@gmail.com>