aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/devio.c12
-rw-r--r--include/linux/sched.h1
-rw-r--r--kernel/signal.c34
3 files changed, 44 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);
diff --git a/include/linux/sched.h b/include/linux/sched.h
index c3ba31f210a9..27519df0f987 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1018,6 +1018,7 @@ extern int force_sig_info(int, struct siginfo *, struct task_struct *);
1018extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); 1018extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
1019extern int kill_pg_info(int, struct siginfo *, pid_t); 1019extern int kill_pg_info(int, struct siginfo *, pid_t);
1020extern int kill_proc_info(int, struct siginfo *, pid_t); 1020extern int kill_proc_info(int, struct siginfo *, pid_t);
1021extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t);
1021extern void do_notify_parent(struct task_struct *, int); 1022extern void do_notify_parent(struct task_struct *, int);
1022extern void force_sig(int, struct task_struct *); 1023extern void force_sig(int, struct task_struct *);
1023extern void force_sig_specific(int, struct task_struct *); 1024extern void force_sig_specific(int, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
index cba193ceda0d..50c992643771 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1193,6 +1193,40 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
1193 return error; 1193 return error;
1194} 1194}
1195 1195
1196/* like kill_proc_info(), but doesn't use uid/euid of "current" */
1197int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
1198 uid_t uid, uid_t euid)
1199{
1200 int ret = -EINVAL;
1201 struct task_struct *p;
1202
1203 if (!valid_signal(sig))
1204 return ret;
1205
1206 read_lock(&tasklist_lock);
1207 p = find_task_by_pid(pid);
1208 if (!p) {
1209 ret = -ESRCH;
1210 goto out_unlock;
1211 }
1212 if ((!info || ((unsigned long)info != 1 &&
1213 (unsigned long)info != 2 && SI_FROMUSER(info)))
1214 && (euid != p->suid) && (euid != p->uid)
1215 && (uid != p->suid) && (uid != p->uid)) {
1216 ret = -EPERM;
1217 goto out_unlock;
1218 }
1219 if (sig && p->sighand) {
1220 unsigned long flags;
1221 spin_lock_irqsave(&p->sighand->siglock, flags);
1222 ret = __group_send_sig_info(sig, info, p);
1223 spin_unlock_irqrestore(&p->sighand->siglock, flags);
1224 }
1225out_unlock:
1226 read_unlock(&tasklist_lock);
1227 return ret;
1228}
1229EXPORT_SYMBOL_GPL(kill_proc_info_as_uid);
1196 1230
1197/* 1231/*
1198 * kill_something_info() interprets pid in interesting ways just like kill(2). 1232 * kill_something_info() interprets pid in interesting ways just like kill(2).