aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2005-10-10 13:44:29 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-10 19:16:33 -0400
commit46113830a18847cff8da73005e57bc49c2f95a56 (patch)
tree93946fc290d9481e7055217ff497583647d1e4d4 /drivers/usb
parent094804c5a132f04c12dd4902ee15c64362e5c1af (diff)
[PATCH] Fix signal sending in usbdevio on async URB completion
If a process issues an URB from userspace and (starts to) terminate before the URB comes back, we run into the issue described above. This is because the urb saves a pointer to "current" when it is posted to the device, but there's no guarantee that this pointer is still valid afterwards. In fact, there are three separate issues: 1) the pointer to "current" can become invalid, since the task could be completely gone when the URB completion comes back from the device. 2) Even if the saved task pointer is still pointing to a valid task_struct, task_struct->sighand could have gone meanwhile. 3) Even if the process is perfectly fine, permissions may have changed, and we can no longer send it a signal. So what we do instead, is to save the PID and uid's of the process, and introduce a new kill_proc_info_as_uid() function. Signed-off-by: Harald Welte <laforge@gnumonks.org> [ Fixed up types and added symbol exports ] Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/core/devio.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index b4265aa7d45e..6c35dcbea664 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -30,6 +30,8 @@
30 * Revision history 30 * Revision history
31 * 22.12.1999 0.1 Initial release (split from proc_usb.c) 31 * 22.12.1999 0.1 Initial release (split from proc_usb.c)
32 * 04.01.2000 0.2 Turned into its own filesystem 32 * 04.01.2000 0.2 Turned into its own filesystem
33 * 30.09.2005 0.3 Fix user-triggerable oops in async URB delivery
34 * (CAN-2005-3055)
33 */ 35 */
34 36
35/*****************************************************************************/ 37/*****************************************************************************/
@@ -58,7 +60,8 @@ static struct class *usb_device_class;
58struct async { 60struct async {
59 struct list_head asynclist; 61 struct list_head asynclist;
60 struct dev_state *ps; 62 struct dev_state *ps;
61 struct task_struct *task; 63 pid_t pid;
64 uid_t uid, euid;
62 unsigned int signr; 65 unsigned int signr;
63 unsigned int ifnum; 66 unsigned int ifnum;
64 void __user *userbuffer; 67 void __user *userbuffer;
@@ -290,7 +293,8 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
290 sinfo.si_errno = as->urb->status; 293 sinfo.si_errno = as->urb->status;
291 sinfo.si_code = SI_ASYNCIO; 294 sinfo.si_code = SI_ASYNCIO;
292 sinfo.si_addr = as->userurb; 295 sinfo.si_addr = as->userurb;
293 send_sig_info(as->signr, &sinfo, as->task); 296 kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
297 as->euid);
294 } 298 }
295 wake_up(&ps->wait); 299 wake_up(&ps->wait);
296} 300}
@@ -988,7 +992,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
988 as->userbuffer = NULL; 992 as->userbuffer = NULL;
989 as->signr = uurb->signr; 993 as->signr = uurb->signr;
990 as->ifnum = ifnum; 994 as->ifnum = ifnum;
991 as->task = current; 995 as->pid = current->pid;
996 as->uid = current->uid;
997 as->euid = current->euid;
992 if (!(uurb->endpoint & USB_DIR_IN)) { 998 if (!(uurb->endpoint & USB_DIR_IN)) {
993 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) { 999 if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
994 free_async(as); 1000 free_async(as);