]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
media: rtl2832: fix use-after-free in rtl2832_remove()
authorDeepanshu Kartikey <kartikey406@gmail.com>
Wed, 22 Apr 2026 14:47:34 +0000 (20:17 +0530)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Wed, 6 May 2026 07:05:56 +0000 (09:05 +0200)
cancel_delayed_work_sync() is called before i2c_mux_del_adapters()
in rtl2832_remove(). While the cancel waits for any running instance
of i2c_gate_work to finish, it does not prevent the timer from being
rescheduled by a concurrent thread.

During probe, the r820t_attach() call attempts I2C transfers through
the mux adapter. These transfers go through i2c_mux_master_xfer(),
which calls rtl2832_deselect() after the transfer completes,
rescheduling i2c_gate_work via schedule_delayed_work(). If this
transfer is still in flight when rtl2832_remove() runs,
rtl2832_deselect() can reschedule i2c_gate_work after it has been
cancelled, causing a use-after-free when kfree(dev) is called.

Fix this by calling i2c_mux_del_adapters() before
cancel_delayed_work_sync(). Once the mux adapter is unregistered, no
new I2C transfers can go through it, so rtl2832_deselect() can no
longer reschedule i2c_gate_work. The subsequent
cancel_delayed_work_sync() is then guaranteed to be final.

Fixes: cddcc40b1b15 ("[media] rtl2832: convert to use an explicit i2c mux core")
Cc: stable@vger.kernel.org
Reported-by: syzbot+019ced393ab913002b75@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=019ced393ab913002b75
Signed-off-by: Deepanshu Kartikey <kartikey406@gmail.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/dvb-frontends/rtl2832.c

index d8e1546aea5ecca1ed8f2d15cdc7a3009d2e681f..9898f729304ae03875449b7c2046d21d71010ed5 100644 (file)
@@ -1115,10 +1115,10 @@ static void rtl2832_remove(struct i2c_client *client)
 
        dev_dbg(&client->dev, "\n");
 
-       cancel_delayed_work_sync(&dev->i2c_gate_work);
-
        i2c_mux_del_adapters(dev->muxc);
 
+       cancel_delayed_work_sync(&dev->i2c_gate_work);
+
        regmap_exit(dev->regmap);
 
        kfree(dev);