Commit d5dec668 authored by Matthew Leach's avatar Matthew Leach Committed by Sasha Levin

[media] media: usbtv: prevent access to free'd resources

[ Upstream commit 2a00932f ]

When disconnecting the usbtv device, the sound card is unregistered
from ALSA and the snd member of the usbtv struct is set to NULL.  If
the usbtv snd_trigger work is running, this can cause a race condition
where the kernel will attempt to access free'd resources, shown in
[1].

This patch fixes the disconnection code by cancelling any snd_trigger
work before unregistering the sound card from ALSA and checking that
the snd member still exists in the work function.

[1]:
 usb 3-1.2: USB disconnect, device number 6
 BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
 IP: [<ffffffff81093850>] process_one_work+0x30/0x480
 PGD 405bbf067 PUD 405bbe067 PMD 0
 Call Trace:
  [<ffffffff81093ce8>] worker_thread+0x48/0x4e0
  [<ffffffff81093ca0>] ? process_one_work+0x480/0x480
  [<ffffffff81093ca0>] ? process_one_work+0x480/0x480
  [<ffffffff81099998>] kthread+0xd8/0xf0
  [<ffffffff815c73c2>] ret_from_fork+0x22/0x40
  [<ffffffff810998c0>] ? kthread_worker_fn+0x170/0x170
 ---[ end trace 0f3dac5c1a38e610 ]---
Signed-off-by: default avatarMatthew Leach <matthew@mattleach.net>
Tested-by: default avatarPeter Sutton <foxxy@foxdogstudios.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: default avatarSasha Levin <alexander.levin@verizon.com>
parent def5e119
...@@ -278,6 +278,9 @@ static void snd_usbtv_trigger(struct work_struct *work) ...@@ -278,6 +278,9 @@ static void snd_usbtv_trigger(struct work_struct *work)
{ {
struct usbtv *chip = container_of(work, struct usbtv, snd_trigger); struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
if (!chip->snd)
return;
if (atomic_read(&chip->snd_stream)) if (atomic_read(&chip->snd_stream))
usbtv_audio_start(chip); usbtv_audio_start(chip);
else else
...@@ -378,6 +381,8 @@ int usbtv_audio_init(struct usbtv *usbtv) ...@@ -378,6 +381,8 @@ int usbtv_audio_init(struct usbtv *usbtv)
void usbtv_audio_free(struct usbtv *usbtv) void usbtv_audio_free(struct usbtv *usbtv)
{ {
cancel_work_sync(&usbtv->snd_trigger);
if (usbtv->snd && usbtv->udev) { if (usbtv->snd && usbtv->udev) {
snd_card_free(usbtv->snd); snd_card_free(usbtv->snd);
usbtv->snd = NULL; usbtv->snd = NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment