public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Greg KH <greg@kroah.com>
To: Christoph Hellwig <hch@infradead.org>,
	Harald Welte <laforge@gnumonks.org>,
	linux-usb-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, vendor-sec@lst.de,
	security@linux.kernel.org
Subject: Re: [vendor-sec] [BUG/PATCH/RFC] Oops while completing async USB via usbdevio
Date: Tue, 27 Sep 2005 05:57:55 -0700	[thread overview]
Message-ID: <20050927125755.GA10738@kroah.com> (raw)
In-Reply-To: <20050927124846.GA29649@infradead.org>

On Tue, Sep 27, 2005 at 01:48:46PM +0100, Christoph Hellwig wrote:
> On Tue, Sep 27, 2005 at 01:04:15AM -0700, Greg KH wrote:
> > First off, thanks for providing a patch for this problem, it is real,
> > and has been known for a while (thanks to your debugging :)
> > 
> > On Sun, Sep 25, 2005 at 05:13:30PM +0200, Harald Welte wrote:
> > > 
> > > I suggest this (or any other) fix to be applied to both 2.6.14 final and
> > > the stable series.  I didn't yet investigate 2.4.x, but I think it is
> > > likely to have the same problem.
> > 
> > I agree, but I think we need an EXPORT_SYMBOL_GPL() for your newly
> > exported symbol, otherwise the kernel will not build if you have USB
> > built as a module.
> 
> Where's the actual patch?  And no, we certainly shouldn't export anything
> to put a task_struct.

Earlier in this thread, on these mailing lists.

I've included it below too.

thanks,

greg k-h


From: Harald Welte <laforge@gnumonks.org>
Subject: USB: fix oops while completing async USB via usbdevio

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.
   This can be fixed by get_task_struct() / put_task_struct().

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 need to export a __send_sig_info() function, one that
   expects to be called with read_lock(&tasklist_lock) already held by the
   caller.  It's ugly, but I doubt there is a less invasive solution.

Signed-off-by: Harald Welte <laforge@gnumonks.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>


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
@@ -44,6 +44,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/cdev.h>
+#include <linux/sched.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
@@ -231,6 +232,10 @@ static inline void async_newpending(stru
         struct dev_state *ps = as->ps;
         unsigned long flags;
         
+	/* increase refcount to task, so our as->task pointer is still
+	 * valid when URB comes back -HW */
+	get_task_struct(current);
+
         spin_lock_irqsave(&ps->lock, flags);
         list_add_tail(&as->asynclist, &ps->async_pending);
         spin_unlock_irqrestore(&ps->lock, flags);
@@ -244,8 +249,12 @@ static inline void async_removepending(s
         spin_lock_irqsave(&ps->lock, flags);
         list_del_init(&as->asynclist);
         spin_unlock_irqrestore(&ps->lock, flags);
+
+	put_task_struct(as->task);
 }
 
+/* get a completed URB from async list.  Task reference has already been
+ * dropped in async_complete() */
 static inline struct async *async_getcompleted(struct dev_state *ps)
 {
         unsigned long flags;
@@ -260,6 +269,7 @@ static inline struct async *async_getcom
         return as;
 }
 
+/* find matching URB from pending list.  Drop refcount of task */
 static inline struct async *async_getpending(struct dev_state *ps, void __user *userurb)
 {
         unsigned long flags;
@@ -270,6 +280,7 @@ static inline struct async *async_getpen
 		if (as->userurb == userurb) {
 			list_del_init(&as->asynclist);
 			spin_unlock_irqrestore(&ps->lock, flags);
+			put_task_struct(as->task);
 			return as;
 		}
         spin_unlock_irqrestore(&ps->lock, flags);
@@ -290,8 +301,15 @@ 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);
+		read_lock(&tasklist_lock);
+		/* The task could be dying. We hold a reference to it,
+		 * but that doesn't prevent __exit_sighand() from zeroing
+		 * sighand -HW */
+		if (as->task->sighand)
+			__send_sig_info(as->signr, &sinfo, as->task);
+		read_unlock(&tasklist_lock);
 	}
+	put_task_struct(as->task);
         wake_up(&ps->wait);
 }
 
diff --git a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -999,6 +999,7 @@ extern void block_all_signals(int (*noti
 			      sigset_t *mask);
 extern void unblock_all_signals(void);
 extern void release_task(struct task_struct * p);
+extern int __send_sig_info(int, struct siginfo *, struct task_struct *);
 extern int send_sig_info(int, struct siginfo *, struct task_struct *);
 extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
 extern int force_sigsegv(int, struct task_struct *);
diff --git a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1230,12 +1230,11 @@ static int kill_something_info(int sig, 
  * These are for backward compatibility with the rest of the kernel source.
  */
 
-/*
- * These two are the most common entry points.  They send a signal
- * just to the specific thread.
- */
+
+/* This is send_sig_info() for callers that already hold the tasklist_lock.
+ * At the moment the only caller is USB devfio async URB delivery.  */
 int
-send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+__send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	int ret;
 	unsigned long flags;
@@ -1247,6 +1246,23 @@ send_sig_info(int sig, struct siginfo *i
 	if (!valid_signal(sig))
 		return -EINVAL;
 
+	spin_lock_irqsave(&p->sighand->siglock, flags);
+	ret = specific_send_sig_info(sig, info, p);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+
+	return ret;
+}
+
+/*
+ * These two are the most common entry points.  They send a signal
+ * just to the specific thread.
+ */
+
+int
+send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+	int ret;
+
 	/*
 	 * We need the tasklist lock even for the specific
 	 * thread case (when we don't need to follow the group
@@ -1254,9 +1270,7 @@ send_sig_info(int sig, struct siginfo *i
 	 * going away or changing from under us.
 	 */
 	read_lock(&tasklist_lock);  
-	spin_lock_irqsave(&p->sighand->siglock, flags);
-	ret = specific_send_sig_info(sig, info, p);
-	spin_unlock_irqrestore(&p->sighand->siglock, flags);
+	ret = __send_sig_info(sig, info, p);
 	read_unlock(&tasklist_lock);
 	return ret;
 }
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDNr6aXaXGVTD0i/8RAu9FAKCbbV491NzCY42YTkXo7XSzbRRO1QCgnM2K
j+Ae+NblrsPc6Jy9ICWOtyw=
=Ldn9
-----END PGP SIGNATURE-----


  reply	other threads:[~2005-09-27 12:58 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 [this message]
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
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=20050927125755.GA10738@kroah.com \
    --to=greg@kroah.com \
    --cc=hch@infradead.org \
    --cc=laforge@gnumonks.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb-devel@lists.sourceforge.net \
    --cc=security@linux.kernel.org \
    --cc=vendor-sec@lst.de \
    /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