summaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2005-10-10 19:44:29 +0200
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-10 16:16:33 -0700
commit46113830a18847cff8da73005e57bc49c2f95a56 (patch)
tree93946fc290d9481e7055217ff497583647d1e4d4 /kernel/signal.c
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 'kernel/signal.c')
-rw-r--r--kernel/signal.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index cba193ceda0..50c99264377 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1193,6 +1193,40 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
return error;
}
+/* like kill_proc_info(), but doesn't use uid/euid of "current" */
+int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
+ uid_t uid, uid_t euid)
+{
+ int ret = -EINVAL;
+ struct task_struct *p;
+
+ if (!valid_signal(sig))
+ return ret;
+
+ read_lock(&tasklist_lock);
+ p = find_task_by_pid(pid);
+ if (!p) {
+ ret = -ESRCH;
+ goto out_unlock;
+ }
+ if ((!info || ((unsigned long)info != 1 &&
+ (unsigned long)info != 2 && SI_FROMUSER(info)))
+ && (euid != p->suid) && (euid != p->uid)
+ && (uid != p->suid) && (uid != p->uid)) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+ if (sig && p->sighand) {
+ unsigned long flags;
+ spin_lock_irqsave(&p->sighand->siglock, flags);
+ ret = __group_send_sig_info(sig, info, p);
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
+ }
+out_unlock:
+ read_unlock(&tasklist_lock);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(kill_proc_info_as_uid);
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).