diff mbox series

[RFC] spi: fix use-after-free of the add_lock mutex

Message ID 20211110160836.3304104-1-michael@walle.cc (mailing list archive)
State Superseded
Headers show
Series [RFC] spi: fix use-after-free of the add_lock mutex | expand

Commit Message

Michael Walle Nov. 10, 2021, 4:08 p.m. UTC
Commit 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on
SPI buses") introduced a per-controller mutex. But mutex_unlock() of
said lock is called after the controller is already freed:

  spi_unregister_controller(ctlr)
   -> put_device(&ctlr->dev)
    -> spi_controller_release(dev)
  mutex_unlock(&ctrl->add_lock)

Move the put_device() after the mutex_unlock().

Fixes: 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on SPI buses")
Signed-off-by: Michael Walle <michael@walle.cc>
---
I'm not sure if this is the correct fix. I don't know if the put_device()
will have to be protected by the add_lock (remember before, the add_lock
was a global lock).

For reference, the kernel oops is:
[   20.242505] Unable to handle kernel paging request at virtual address 0042a2203dc65260
[   20.250468] Mem abort info:
[   20.253270]   ESR = 0x96000044
[   20.256332]   EC = 0x25: DABT (current EL), IL = 32 bits
[   20.261662]   SET = 0, FnV = 0
[   20.264723]   EA = 0, S1PTW = 0
[   20.267869]   FSC = 0x04: level 0 translation fault
[   20.272764] Data abort info:
[   20.275646]   ISV = 0, ISS = 0x00000044
[   20.279494]   CM = 0, WnR = 1
[   20.282469] [0042a2203dc65260] address between user and kernel address ranges
[   20.289632] Internal error: Oops: 96000044 [#1] SMP
[   20.294525] Modules linked in:
[   20.297586] CPU: 1 PID: 1546 Comm: init Not tainted 5.15.0-next-20211109+ #1307
[   20.304919] Hardware name: Kontron KBox A-230-LS (DT)
[   20.309983] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[   20.316968] pc : queued_spin_lock_slowpath+0x1a8/0x3a0
[   20.322127] lr : __mutex_unlock_slowpath.constprop.0+0x180/0x190
[   20.328156] sp : ffff800013c23b80
[   20.331475] x29: ffff800013c23b80 x28: ffff002003941040 x27: 0000000000000000
[   20.338639] x26: ffff002000e49c90 x25: ffff80001167de48 x24: ffff800011f55578
[   20.345802] x23: ffff002002b1d350 x22: 0000000000000002 x21: 0000000000000001
[   20.352964] x20: ffff800013c23bb8 x19: ffff002002b1d350 x18: 00000000fffffffb
[   20.360126] x17: 0000000000000001 x16: 0000000000000001 x15: 0000000000000020
[   20.367288] x14: 0000000000000001 x13: 0000000000000000 x12: ffff002002c27938
[   20.374450] x11: ffff002002c27908 x10: 0000000000000000 x9 : 0000000000080000
[   20.381612] x8 : 0000000000000000 x7 : ffff00207f7b7a00 x6 : ffff8000119d1a00
[   20.388774] x5 : ffff00207f7b7a00 x4 : 504322202c293830 x3 : ffff002002b1d358
[   20.395936] x2 : ffff8000119d1a30 x1 : ffff8000119d1a30 x0 : ffff00207f7b7a08
[   20.403098] Call trace:
[   20.405546]  queued_spin_lock_slowpath+0x1a8/0x3a0
[   20.410352]  mutex_unlock+0x5c/0x70
[   20.413849]  spi_unregister_controller+0xf0/0x170
[   20.418568]  dspi_remove+0x28/0xb0
[   20.421978]  dspi_shutdown+0x1c/0x30
[   20.425561]  platform_shutdown+0x30/0x40
[   20.429495]  device_shutdown+0x14c/0x420
[   20.433427]  __do_sys_reboot+0x214/0x29c
[   20.437361]  __arm64_sys_reboot+0x30/0x40
[   20.441380]  invoke_syscall+0x50/0x120
[   20.445140]  el0_svc_common.constprop.0+0x58/0x190
[   20.449944]  do_el0_svc+0x30/0x94
[   20.453267]  el0_svc+0x20/0x90
[   20.456327]  el0t_64_sync_handler+0x1a4/0x1b0
[   20.460694]  el0t_64_sync+0x1a0/0x1a4
[   20.464368] Code: 910020e0 8b0200c2 f861d884 aa0203e1 (f8246827) 
[   20.470479] ---[ end trace 9ee0c21f9e4bc5d5 ]---
[   21.475251] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
[   21.482940] Kernel Offset: disabled
[   21.486433] CPU features: 0x2,000001c2,40000846
[   21.490976] Memory Limit: none
[   21.494036] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000 ]---

 drivers/spi/spi.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

Comments

Mark Brown Nov. 10, 2021, 4:27 p.m. UTC | #1
On Wed, Nov 10, 2021 at 05:08:36PM +0100, Michael Walle wrote:
> Commit 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on
> SPI buses") introduced a per-controller mutex. But mutex_unlock() of
> said lock is called after the controller is already freed:
> 
>   spi_unregister_controller(ctlr)
>    -> put_device(&ctlr->dev)
>     -> spi_controller_release(dev)
>   mutex_unlock(&ctrl->add_lock)
> 
> Move the put_device() after the mutex_unlock().

Do we even need to unlock the mutex here?

> 
> For reference, the kernel oops is:
> [   20.242505] Unable to handle kernel paging request at virtual address 0042a2203dc65260
> [   20.250468] Mem abort info:
> [   20.253270]   ESR = 0x96000044

Please think hard before including complete backtraces in upstream
reports, they are very large and contain almost no useful information
relative to their size so often obscure the relevant content in your
message. If part of the backtrace is usefully illustrative (it often is
for search engines if nothing else) then it's usually better to pull out
the relevant sections.
Michael Walle Nov. 10, 2021, 4:30 p.m. UTC | #2
Am 2021-11-10 17:27, schrieb Mark Brown:
>> For reference, the kernel oops is:
>> [   20.242505] Unable to handle kernel paging request at virtual 
>> address 0042a2203dc65260
>> [   20.250468] Mem abort info:
>> [   20.253270]   ESR = 0x96000044
> 
> Please think hard before including complete backtraces in upstream
> reports, they are very large and contain almost no useful information
> relative to their size so often obscure the relevant content in your
> message. If part of the backtrace is usefully illustrative (it often is
> for search engines if nothing else) then it's usually better to pull 
> out
> the relevant sections.

It was in the comments section of the patch, for exactly this purpose.
That's how you're doing it, no?

-michael
Mark Brown Nov. 10, 2021, 4:39 p.m. UTC | #3
On Wed, Nov 10, 2021 at 05:30:48PM +0100, Michael Walle wrote:
> Am 2021-11-10 17:27, schrieb Mark Brown:

> > > For reference, the kernel oops is:
> > > [   20.242505] Unable to handle kernel paging request at virtual
> > > address 0042a2203dc65260
> > > [   20.250468] Mem abort info:
> > > [   20.253270]   ESR = 0x96000044

> > Please think hard before including complete backtraces in upstream
> > reports, they are very large and contain almost no useful information
> > relative to their size so often obscure the relevant content in your
> > message. If part of the backtrace is usefully illustrative (it often is
> > for search engines if nothing else) then it's usually better to pull out
> > the relevant sections.

> It was in the comments section of the patch, for exactly this purpose.
> That's how you're doing it, no?

That helps with what ends up in git but it's still including multiple
screenfuls of noise in the email which is where the usability problem
is.
Andy Shevchenko Nov. 10, 2021, 4:49 p.m. UTC | #4
On Wed, Nov 10, 2021 at 6:09 PM Michael Walle <michael@walle.cc> wrote:
>
> Commit 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on
> SPI buses") introduced a per-controller mutex. But mutex_unlock() of
> said lock is called after the controller is already freed:
>
>   spi_unregister_controller(ctlr)
>    -> put_device(&ctlr->dev)
>     -> spi_controller_release(dev)
>   mutex_unlock(&ctrl->add_lock)
>
> Move the put_device() after the mutex_unlock().

I have a déjà-vu feeling about this code (Cc Lukas).

>
> Fixes: 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on SPI buses")
> Signed-off-by: Michael Walle <michael@walle.cc>
> ---
> I'm not sure if this is the correct fix. I don't know if the put_device()
> will have to be protected by the add_lock (remember before, the add_lock
> was a global lock).
>
> For reference, the kernel oops is:
> [   20.242505] Unable to handle kernel paging request at virtual address 0042a2203dc65260
> [   20.250468] Mem abort info:
> [   20.253270]   ESR = 0x96000044
> [   20.256332]   EC = 0x25: DABT (current EL), IL = 32 bits
> [   20.261662]   SET = 0, FnV = 0
> [   20.264723]   EA = 0, S1PTW = 0
> [   20.267869]   FSC = 0x04: level 0 translation fault
> [   20.272764] Data abort info:
> [   20.275646]   ISV = 0, ISS = 0x00000044
> [   20.279494]   CM = 0, WnR = 1
> [   20.282469] [0042a2203dc65260] address between user and kernel address ranges
> [   20.289632] Internal error: Oops: 96000044 [#1] SMP
> [   20.294525] Modules linked in:
> [   20.297586] CPU: 1 PID: 1546 Comm: init Not tainted 5.15.0-next-20211109+ #1307
> [   20.304919] Hardware name: Kontron KBox A-230-LS (DT)
> [   20.309983] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
> [   20.316968] pc : queued_spin_lock_slowpath+0x1a8/0x3a0
> [   20.322127] lr : __mutex_unlock_slowpath.constprop.0+0x180/0x190
> [   20.328156] sp : ffff800013c23b80
> [   20.331475] x29: ffff800013c23b80 x28: ffff002003941040 x27: 0000000000000000
> [   20.338639] x26: ffff002000e49c90 x25: ffff80001167de48 x24: ffff800011f55578
> [   20.345802] x23: ffff002002b1d350 x22: 0000000000000002 x21: 0000000000000001
> [   20.352964] x20: ffff800013c23bb8 x19: ffff002002b1d350 x18: 00000000fffffffb
> [   20.360126] x17: 0000000000000001 x16: 0000000000000001 x15: 0000000000000020
> [   20.367288] x14: 0000000000000001 x13: 0000000000000000 x12: ffff002002c27938
> [   20.374450] x11: ffff002002c27908 x10: 0000000000000000 x9 : 0000000000080000
> [   20.381612] x8 : 0000000000000000 x7 : ffff00207f7b7a00 x6 : ffff8000119d1a00
> [   20.388774] x5 : ffff00207f7b7a00 x4 : 504322202c293830 x3 : ffff002002b1d358
> [   20.395936] x2 : ffff8000119d1a30 x1 : ffff8000119d1a30 x0 : ffff00207f7b7a08
> [   20.403098] Call trace:
> [   20.405546]  queued_spin_lock_slowpath+0x1a8/0x3a0
> [   20.410352]  mutex_unlock+0x5c/0x70
> [   20.413849]  spi_unregister_controller+0xf0/0x170
> [   20.418568]  dspi_remove+0x28/0xb0
> [   20.421978]  dspi_shutdown+0x1c/0x30
> [   20.425561]  platform_shutdown+0x30/0x40
> [   20.429495]  device_shutdown+0x14c/0x420
> [   20.433427]  __do_sys_reboot+0x214/0x29c
> [   20.437361]  __arm64_sys_reboot+0x30/0x40
> [   20.441380]  invoke_syscall+0x50/0x120
> [   20.445140]  el0_svc_common.constprop.0+0x58/0x190
> [   20.449944]  do_el0_svc+0x30/0x94
> [   20.453267]  el0_svc+0x20/0x90
> [   20.456327]  el0t_64_sync_handler+0x1a4/0x1b0
> [   20.460694]  el0t_64_sync+0x1a0/0x1a4
> [   20.464368] Code: 910020e0 8b0200c2 f861d884 aa0203e1 (f8246827)
> [   20.470479] ---[ end trace 9ee0c21f9e4bc5d5 ]---
> [   21.475251] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000
> [   21.482940] Kernel Offset: disabled
> [   21.486433] CPU features: 0x2,000001c2,40000846
> [   21.490976] Memory Limit: none
> [   21.494036] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000 ]---
>
>  drivers/spi/spi.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> index b23e675953e1..fdd530b150a7 100644
> --- a/drivers/spi/spi.c
> +++ b/drivers/spi/spi.c
> @@ -3099,12 +3099,6 @@ void spi_unregister_controller(struct spi_controller *ctlr)
>
>         device_del(&ctlr->dev);
>
> -       /* Release the last reference on the controller if its driver
> -        * has not yet been converted to devm_spi_alloc_master/slave().
> -        */
> -       if (!ctlr->devm_allocated)
> -               put_device(&ctlr->dev);
> -
>         /* free bus id */
>         mutex_lock(&board_lock);
>         if (found == ctlr)
> @@ -3113,6 +3107,12 @@ void spi_unregister_controller(struct spi_controller *ctlr)
>
>         if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
>                 mutex_unlock(&ctlr->add_lock);
> +
> +       /* Release the last reference on the controller if its driver
> +        * has not yet been converted to devm_spi_alloc_master/slave().
> +        */
> +       if (!ctlr->devm_allocated)
> +               put_device(&ctlr->dev);
>  }
>  EXPORT_SYMBOL_GPL(spi_unregister_controller);
>
> --
> 2.30.2
>
Uwe Kleine-König Nov. 10, 2021, 5:28 p.m. UTC | #5
Hello,

On Wed, Nov 10, 2021 at 05:08:36PM +0100, Michael Walle wrote:
> Commit 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on
> SPI buses") introduced a per-controller mutex. But mutex_unlock() of
> said lock is called after the controller is already freed:
> 
>   spi_unregister_controller(ctlr)
>    -> put_device(&ctlr->dev)
>     -> spi_controller_release(dev)
>   mutex_unlock(&ctrl->add_lock)

This is indented in a misleading way. mutex_unlock() has to be on the
same level as put_device().

> Move the put_device() after the mutex_unlock().
> 
> Fixes: 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on SPI buses")
> Signed-off-by: Michael Walle <michael@walle.cc>

I first thought this was wrong, and the put_device must be dropped
altogether, but after some code reading I agree this is the right fix.

Reviewed-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

> ---
> I'm not sure if this is the correct fix. I don't know if the put_device()
> will have to be protected by the add_lock (remember before, the add_lock
> was a global lock).

No, put_device doesn't need to be protected by this lock.

Best regards and thanks for the report and diagnosis,
Uwe
Lukas Wunner Nov. 11, 2021, 5:19 a.m. UTC | #6
On Wed, Nov 10, 2021 at 05:08:36PM +0100, Michael Walle wrote:
> Commit 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on
> SPI buses") introduced a per-controller mutex. But mutex_unlock() of
> said lock is called after the controller is already freed:
> 
>   spi_unregister_controller(ctlr)
>    -> put_device(&ctlr->dev)
>     -> spi_controller_release(dev)
>   mutex_unlock(&ctrl->add_lock)
> 
> Move the put_device() after the mutex_unlock().
> 
> Fixes: 6098475d4cb4 ("spi: Fix deadlock when adding SPI controllers on SPI buses")
> Signed-off-by: Michael Walle <michael@walle.cc>

Reviewed-by: Lukas Wunner <lukas@wunner.de>
Cc: stable@vger.kernel.org # v5.15
diff mbox series

Patch

diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b23e675953e1..fdd530b150a7 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -3099,12 +3099,6 @@  void spi_unregister_controller(struct spi_controller *ctlr)
 
 	device_del(&ctlr->dev);
 
-	/* Release the last reference on the controller if its driver
-	 * has not yet been converted to devm_spi_alloc_master/slave().
-	 */
-	if (!ctlr->devm_allocated)
-		put_device(&ctlr->dev);
-
 	/* free bus id */
 	mutex_lock(&board_lock);
 	if (found == ctlr)
@@ -3113,6 +3107,12 @@  void spi_unregister_controller(struct spi_controller *ctlr)
 
 	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
 		mutex_unlock(&ctlr->add_lock);
+
+	/* Release the last reference on the controller if its driver
+	 * has not yet been converted to devm_spi_alloc_master/slave().
+	 */
+	if (!ctlr->devm_allocated)
+		put_device(&ctlr->dev);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_controller);