|
Takashi Iwai |
93ac02 |
From 19e6317d24c25ee737c65d1ffb7483bdda4bb54a Mon Sep 17 00:00:00 2001
|
|
Takashi Iwai |
93ac02 |
From: Pete Zaitcev <zaitcev@redhat.com>
|
|
Takashi Iwai |
93ac02 |
Date: Wed, 4 Dec 2019 20:39:41 -0600
|
|
Takashi Iwai |
93ac02 |
Subject: [PATCH] usb: mon: Fix a deadlock in usbmon between mmap and read
|
|
Takashi Iwai |
93ac02 |
Git-commit: 19e6317d24c25ee737c65d1ffb7483bdda4bb54a
|
|
Takashi Iwai |
93ac02 |
Patch-mainline: v5.5-rc2
|
|
Takashi Iwai |
93ac02 |
References: bsc#1051510
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
The problem arises because our read() function grabs a lock of the
|
|
Takashi Iwai |
93ac02 |
circular buffer, finds something of interest, then invokes copy_to_user()
|
|
Takashi Iwai |
93ac02 |
straight from the buffer, which in turn takes mm->mmap_sem. In the same
|
|
Takashi Iwai |
93ac02 |
time, the callback mon_bin_vma_fault() is invoked under mm->mmap_sem.
|
|
Takashi Iwai |
93ac02 |
It attempts to take the fetch lock and deadlocks.
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
This patch does away with protecting of our page list with any
|
|
Takashi Iwai |
93ac02 |
semaphores, and instead relies on the kernel not close the device
|
|
Takashi Iwai |
93ac02 |
while mmap is active in a process.
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
In addition, we prohibit re-sizing of a buffer while mmap is active.
|
|
Takashi Iwai |
93ac02 |
This way, when (now unlocked) fault is processed, it works with the
|
|
Takashi Iwai |
93ac02 |
page that is intended to be mapped-in, and not some other random page.
|
|
Takashi Iwai |
93ac02 |
Note that this may have an ABI impact, but hopefully no legitimate
|
|
Takashi Iwai |
93ac02 |
program is this wrong.
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
Signed-off-by: Pete Zaitcev <zaitcev@redhat.com>
|
|
Takashi Iwai |
93ac02 |
Reported-by: syzbot+56f9673bb4cdcbeb0e92@syzkaller.appspotmail.com
|
|
Takashi Iwai |
93ac02 |
Reviewed-by: Alan Stern <stern@rowland.harvard.edu>
|
|
Takashi Iwai |
93ac02 |
Fixes: 46eb14a6e158 ("USB: fix usbmon BUG trigger")
|
|
Takashi Iwai |
93ac02 |
Cc: <stable@vger.kernel.org>
|
|
Takashi Iwai |
93ac02 |
Link: https://lore.kernel.org/r/20191204203941.3503452b@suzdal.zaitcev.lan
|
|
Takashi Iwai |
93ac02 |
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
|
Takashi Iwai |
93ac02 |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
---
|
|
Takashi Iwai |
93ac02 |
drivers/usb/mon/mon_bin.c | 32 +++++++++++++++++++++-----------
|
|
Takashi Iwai |
93ac02 |
1 file changed, 21 insertions(+), 11 deletions(-)
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
|
|
Takashi Iwai |
93ac02 |
index ac2b4fcc265f..f48a23adbc35 100644
|
|
Takashi Iwai |
93ac02 |
--- a/drivers/usb/mon/mon_bin.c
|
|
Takashi Iwai |
93ac02 |
+++ b/drivers/usb/mon/mon_bin.c
|
|
Takashi Iwai |
93ac02 |
@@ -1039,12 +1039,18 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
mutex_lock(&rp->fetch_lock);
|
|
Takashi Iwai |
93ac02 |
spin_lock_irqsave(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
- mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
|
|
Takashi Iwai |
93ac02 |
- kfree(rp->b_vec);
|
|
Takashi Iwai |
93ac02 |
- rp->b_vec = vec;
|
|
Takashi Iwai |
93ac02 |
- rp->b_size = size;
|
|
Takashi Iwai |
93ac02 |
- rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
|
|
Takashi Iwai |
93ac02 |
- rp->cnt_lost = 0;
|
|
Takashi Iwai |
93ac02 |
+ if (rp->mmap_active) {
|
|
Takashi Iwai |
93ac02 |
+ mon_free_buff(vec, size/CHUNK_SIZE);
|
|
Takashi Iwai |
93ac02 |
+ kfree(vec);
|
|
Takashi Iwai |
93ac02 |
+ ret = -EBUSY;
|
|
Takashi Iwai |
93ac02 |
+ } else {
|
|
Takashi Iwai |
93ac02 |
+ mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
|
|
Takashi Iwai |
93ac02 |
+ kfree(rp->b_vec);
|
|
Takashi Iwai |
93ac02 |
+ rp->b_vec = vec;
|
|
Takashi Iwai |
93ac02 |
+ rp->b_size = size;
|
|
Takashi Iwai |
93ac02 |
+ rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
|
|
Takashi Iwai |
93ac02 |
+ rp->cnt_lost = 0;
|
|
Takashi Iwai |
93ac02 |
+ }
|
|
Takashi Iwai |
93ac02 |
spin_unlock_irqrestore(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
mutex_unlock(&rp->fetch_lock);
|
|
Takashi Iwai |
93ac02 |
}
|
|
Takashi Iwai |
93ac02 |
@@ -1216,13 +1222,21 @@ mon_bin_poll(struct file *file, struct poll_table_struct *wait)
|
|
Takashi Iwai |
93ac02 |
static void mon_bin_vma_open(struct vm_area_struct *vma)
|
|
Takashi Iwai |
93ac02 |
{
|
|
Takashi Iwai |
93ac02 |
struct mon_reader_bin *rp = vma->vm_private_data;
|
|
Takashi Iwai |
93ac02 |
+ unsigned long flags;
|
|
Takashi Iwai |
93ac02 |
+
|
|
Takashi Iwai |
93ac02 |
+ spin_lock_irqsave(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
rp->mmap_active++;
|
|
Takashi Iwai |
93ac02 |
+ spin_unlock_irqrestore(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
}
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
static void mon_bin_vma_close(struct vm_area_struct *vma)
|
|
Takashi Iwai |
93ac02 |
{
|
|
Takashi Iwai |
93ac02 |
+ unsigned long flags;
|
|
Takashi Iwai |
93ac02 |
+
|
|
Takashi Iwai |
93ac02 |
struct mon_reader_bin *rp = vma->vm_private_data;
|
|
Takashi Iwai |
93ac02 |
+ spin_lock_irqsave(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
rp->mmap_active--;
|
|
Takashi Iwai |
93ac02 |
+ spin_unlock_irqrestore(&rp->b_lock, flags);
|
|
Takashi Iwai |
93ac02 |
}
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
/*
|
|
Takashi Iwai |
93ac02 |
@@ -1234,16 +1248,12 @@ static vm_fault_t mon_bin_vma_fault(struct vm_fault *vmf)
|
|
Takashi Iwai |
93ac02 |
unsigned long offset, chunk_idx;
|
|
Takashi Iwai |
93ac02 |
struct page *pageptr;
|
|
Takashi Iwai |
93ac02 |
|
|
Takashi Iwai |
93ac02 |
- mutex_lock(&rp->fetch_lock);
|
|
Takashi Iwai |
93ac02 |
offset = vmf->pgoff << PAGE_SHIFT;
|
|
Takashi Iwai |
93ac02 |
- if (offset >= rp->b_size) {
|
|
Takashi Iwai |
93ac02 |
- mutex_unlock(&rp->fetch_lock);
|
|
Takashi Iwai |
93ac02 |
+ if (offset >= rp->b_size)
|
|
Takashi Iwai |
93ac02 |
return VM_FAULT_SIGBUS;
|
|
Takashi Iwai |
93ac02 |
- }
|
|
Takashi Iwai |
93ac02 |
chunk_idx = offset / CHUNK_SIZE;
|
|
Takashi Iwai |
93ac02 |
pageptr = rp->b_vec[chunk_idx].pg;
|
|
Takashi Iwai |
93ac02 |
get_page(pageptr);
|
|
Takashi Iwai |
93ac02 |
- mutex_unlock(&rp->fetch_lock);
|
|
Takashi Iwai |
93ac02 |
vmf->page = pageptr;
|
|
Takashi Iwai |
93ac02 |
return 0;
|
|
Takashi Iwai |
93ac02 |
}
|
|
Takashi Iwai |
93ac02 |
--
|
|
Takashi Iwai |
93ac02 |
2.16.4
|
|
Takashi Iwai |
93ac02 |
|