From: Harald Welte <laforge@gnumonks.org>
To: Chris Wright <chrisw@osdl.org>
Cc: Linus Torvalds <torvalds@osdl.org>,
Sergey Vlasov <vsu@altlinux.ru>,
linux-usb-devel@lists.sourceforge.net,
linux-kernel@vger.kernel.org, security@linux.kernel.org,
vendor-sec@lst.de
Subject: Re: [BUG/PATCH/RFC] Oops while completing async USB via usbdevio
Date: Tue, 11 Oct 2005 11:45:51 +0200 [thread overview]
Message-ID: <20051011094550.GI4290@rama> (raw)
In-Reply-To: <20051010180745.GT5856@shell0.pdx.osdl.net>
[-- Attachment #1: Type: text/plain, Size: 8526 bytes --]
On Mon, Oct 10, 2005 at 11:07:45AM -0700, Chris Wright wrote:
> * Harald Welte (laforge@gnumonks.org) wrote:
> > diff --git a/kernel/signal.c b/kernel/signal.c
> > --- a/kernel/signal.c
> > +++ b/kernel/signal.c
> > @@ -1193,6 +1193,40 @@ kill_proc_info(int sig, struct siginfo *
> > return error;
> > }
> >
> > +/* like kill_proc_info(), but doesn't use uid/euid of "current" */
>
> Maybe additional comment reminding that you most likely don't want this
> interface.
>
> Also, looks like there's same issue again:
Mh, didn't hit that bug since I don't use disconnect signals. But it
looks like it has the same issue.
Please consider the patch below, it
1) changes pid_t to uid_t
2) exports the symbol
3) adresses the same task_struct referencing issue for disconnect
signals
I hope this now finally is the last take ;)
[USBDEVIO] Fix Oops in usbdevio async URB completion (CAN-2005-3055)
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.
This basically means that any userspace process with permissions to
any arbitrary USB device can Ooops any kernel.(!)
In fact, there are two 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. Therefore, the USB
async URB completion handler needs to reliably check whether
task_struct->sighand is still valid or not. In order to prevent a
race with __exit_sighand(), it needs to grab a
read_lock(&tasklist_lock). This strategy seems to work, since the
send_sig_info() code uses the same protection.
However, we now would need to export a __send_sig_info() function, one
that expects to be called with read_lock(&tasklist_lock) already held by
the caller.
So what we do instead, is to save the PID of the process, and introduce a
new kill_proc_info_as_uid() function. Yes, pid's can and will wrap, so
this is just a short-term fix until usbfs2 will appear.
Signed-off-by: Harald Welte <laforge@gnumonks.org>
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -30,6 +30,8 @@
* Revision history
* 22.12.1999 0.1 Initial release (split from proc_usb.c)
* 04.01.2000 0.2 Turned into its own filesystem
+ * 30.09.2005 0.3 Fix user-triggerable oops in async URB delivery
+ * (CAN-2005-3055)
*/
/*****************************************************************************/
@@ -58,7 +60,8 @@ static struct class *usb_device_class;
struct async {
struct list_head asynclist;
struct dev_state *ps;
- struct task_struct *task;
+ pid_t pid;
+ uid_t uid, euid;
unsigned int signr;
unsigned int ifnum;
void __user *userbuffer;
@@ -290,7 +293,8 @@ static void async_completed(struct urb *
sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
- send_sig_info(as->signr, &sinfo, as->task);
+ kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
+ as->euid);
}
wake_up(&ps->wait);
}
@@ -525,9 +529,11 @@ static int usbdev_open(struct inode *ino
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
- ps->discsignr = 0;
- ps->disctask = current;
- ps->disccontext = NULL;
+ ps->disc.signr = 0;
+ ps->disc.pid = current->pid;
+ ps->disc.uid = current->uid;
+ ps->disc.euid = current->euid;
+ ps->disc.context = NULL;
ps->ifclaimed = 0;
wmb();
list_add_tail(&ps->list, &dev->filelist);
@@ -988,7 +994,9 @@ static int proc_do_submiturb(struct dev_
as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
- as->task = current;
+ as->pid = current->pid;
+ as->uid = current->uid;
+ as->euid = current->euid;
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
@@ -1203,8 +1211,8 @@ static int proc_disconnectsignal(struct
return -EFAULT;
if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
return -EINVAL;
- ps->discsignr = ds.signr;
- ps->disccontext = ds.context;
+ ps->disc.signr = ds.signr;
+ ps->disc.context = ds.context;
return 0;
}
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -708,12 +708,14 @@ void usbfs_remove_device(struct usb_devi
ds = list_entry(dev->filelist.next, struct dev_state, list);
wake_up_all(&ds->wait);
list_del_init(&ds->list);
- if (ds->discsignr) {
+ if (ds->disc.signr) {
sinfo.si_signo = SIGPIPE;
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
- sinfo.si_addr = ds->disccontext;
- send_sig_info(ds->discsignr, &sinfo, ds->disctask);
+ sinfo.si_addr = ds->disc.context;
+ kill_proc_info_as_uid(ds->disc.signr, &sinfo,
+ ds->disc.pid, ds->disc.uid,
+ ds->disc.euid);
}
}
usbfs_update_special();
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -51,9 +51,12 @@ struct dev_state {
struct list_head async_pending;
struct list_head async_completed;
wait_queue_head_t wait; /* wake up if a request completed */
- unsigned int discsignr;
- struct task_struct *disctask;
- void __user *disccontext;
+ struct {
+ unsigned int signr;
+ pid_t pid;
+ uid_t uid, euid;
+ void __user *context;
+ } disc;
unsigned long ifclaimed;
};
diff --git a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1018,6 +1018,7 @@ extern int force_sig_info(int, struct si
extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
extern int kill_pg_info(int, struct siginfo *, pid_t);
extern int kill_proc_info(int, struct siginfo *, pid_t);
+extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t);
extern void do_notify_parent(struct task_struct *, int);
extern void force_sig(int, struct task_struct *);
extern void force_sig_specific(int, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1193,6 +1193,42 @@ kill_proc_info(int sig, struct siginfo *
return error;
}
+/* This is like kill_proc_info(), but doesn't use uid/euid of "current".
+ * Most likely this function is not what you want, it was added as a special
+ * case for usbdevio */
+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;
+}
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).
@@ -1974,6 +2010,7 @@ EXPORT_SYMBOL(flush_signals);
EXPORT_SYMBOL(force_sig);
EXPORT_SYMBOL(kill_pg);
EXPORT_SYMBOL(kill_proc);
+EXPORT_SYMBOL_GPL(kill_proc_info_as_uid);
EXPORT_SYMBOL(ptrace_notify);
EXPORT_SYMBOL(send_sig);
EXPORT_SYMBOL(send_sig_info);
--
- Harald Welte <laforge@gnumonks.org> http://gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
next prev parent reply other threads:[~2005-10-11 13:48 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-09-25 15:13 [BUG/PATCH/RFC] Oops while completing async USB via usbdevio Harald Welte
2005-09-27 8:04 ` [vendor-sec] " Greg KH
2005-09-27 9:13 ` Greg KH
[not found] ` <20050927110319.GD1980@piware.de>
2005-09-27 12:22 ` [vendor-sec] " Greg KH
2005-09-27 12:48 ` [vendor-sec] " Christoph Hellwig
2005-09-27 12:57 ` Greg KH
2005-09-27 12:59 ` Christoph Hellwig
2005-09-27 13:09 ` Greg KH
2005-09-27 15:27 ` David Brownell
2005-09-27 14:53 ` [Security] " Linus Torvalds
2005-09-27 16:00 ` [linux-usb-devel] " Sergey Vlasov
2005-09-27 16:09 ` Linus Torvalds
2005-09-27 16:52 ` Sergey Vlasov
2005-09-27 17:02 ` Linus Torvalds
2005-09-30 10:47 ` Harald Welte
2005-09-30 14:56 ` Linus Torvalds
2005-09-30 18:44 ` Chris Wright
2005-09-30 19:27 ` Linus Torvalds
2005-09-30 20:38 ` Chris Wright
2005-09-30 22:08 ` Harald Welte
2005-09-30 22:16 ` Linus Torvalds
2005-10-10 17:44 ` Harald Welte
2005-10-10 18:07 ` Chris Wright
2005-10-11 9:45 ` Harald Welte [this message]
2005-10-11 23:10 ` [vendor-sec] " Greg KH
2005-10-11 23:44 ` Linus Torvalds
2005-10-12 7:24 ` Harald Welte
2005-10-13 5:51 ` Horms
2005-10-11 13:57 ` Bernd Petrovitsch
2005-10-10 18:19 ` Linus Torvalds
2005-10-10 22:47 ` Chris Wright
2005-10-10 20:03 ` [linux-usb-devel] " Alan Stern
2005-10-11 8:28 ` Harald Welte
2005-10-11 17:37 ` Paul Jackson
2005-10-11 17:58 ` linux-os (Dick Johnson)
2005-10-11 19:13 ` Alan Stern
2005-10-11 20:02 ` [Security] " Alan Cox
2005-09-27 17:20 ` PID reuse safety for userspace apps (Re: [linux-usb-devel] Re: [Security] [vendor-sec] [BUG/PATCH/RFC] Oops while completing async USB via usbdevio) Solar Designer
2005-09-27 20:34 ` Alan Cox
2005-09-27 20:42 ` Linus Torvalds
2005-09-27 21:16 ` Solar Designer
2005-09-27 21:03 ` Solar Designer
2005-09-27 16:58 ` [linux-usb-devel] Re: [Security] [vendor-sec] [BUG/PATCH/RFC] Oops while completing async USB via usbdevio Alan Cox
2005-09-27 16:59 ` Linus Torvalds
2005-09-27 20:35 ` Alan Cox
2005-10-13 23:00 ` Pete Zaitcev
2005-10-13 23:16 ` Linus Torvalds
2005-10-13 23:56 ` Pete Zaitcev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20051011094550.GI4290@rama \
--to=laforge@gnumonks.org \
--cc=chrisw@osdl.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb-devel@lists.sourceforge.net \
--cc=security@linux.kernel.org \
--cc=torvalds@osdl.org \
--cc=vendor-sec@lst.de \
--cc=vsu@altlinux.ru \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox