diff options
-rw-r--r-- | drivers/usb/core/devio.c | 12 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | kernel/signal.c | 34 |
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; | |||
58 | struct async { | 60 | struct 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 *); | |||
1018 | extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); | 1018 | extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp); |
1019 | extern int kill_pg_info(int, struct siginfo *, pid_t); | 1019 | extern int kill_pg_info(int, struct siginfo *, pid_t); |
1020 | extern int kill_proc_info(int, struct siginfo *, pid_t); | 1020 | extern int kill_proc_info(int, struct siginfo *, pid_t); |
1021 | extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t); | ||
1021 | extern void do_notify_parent(struct task_struct *, int); | 1022 | extern void do_notify_parent(struct task_struct *, int); |
1022 | extern void force_sig(int, struct task_struct *); | 1023 | extern void force_sig(int, struct task_struct *); |
1023 | extern void force_sig_specific(int, struct task_struct *); | 1024 | extern 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" */ | ||
1197 | int 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 | } | ||
1225 | out_unlock: | ||
1226 | read_unlock(&tasklist_lock); | ||
1227 | return ret; | ||
1228 | } | ||
1229 | EXPORT_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). |