kernel-janitors.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 2/2] staging: line6: use after free bug requesting version
@ 2012-12-05 18:44 Dan Carpenter
  2012-12-06  5:18 ` Stefan Hajnoczi
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Dan Carpenter @ 2012-12-05 18:44 UTC (permalink / raw)
  To: kernel-janitors

In line6_version_request_async() we set up an async message but we free
the buffer with the version in it before the message has been sent.

I've introduced a new function line6_async_request_sent_free_buffer()
which frees the data after we are done with it.  I've added a "free"
parameter to the line6_send_raw_message_async() functions so that they
know if they have to free the msg->buffer or not at the end.

Reported-by: Stefan Hajnoczi <stefanha@gmail.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>

diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index 1dd768c2..918d19e 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -205,7 +205,7 @@ extern int line6_send_program(struct usb_line6 *line6, u8 value);
 extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
 				  int size);
 extern int line6_send_raw_message_async(struct usb_line6 *line6,
-					const char *buffer, int size);
+					const char *buffer, int size, int free);
 extern int line6_send_sysex_message(struct usb_line6 *line6,
 				    const char *buffer, int size);
 extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
index 4fca58f..f97512d 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -47,7 +47,7 @@ static void variax_activate_async(struct usb_line6_variax *variax, int a)
 {
 	variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
 	line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
-				     sizeof(variax_activate));
+				     sizeof(variax_activate), 0);
 }
 
 /*
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index 8a5d89e..884e0d8 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -110,7 +110,7 @@ struct message {
 */
 static void line6_data_received(struct urb *urb);
 static int line6_send_raw_message_async_part(struct message *msg,
-					     struct urb *urb);
+					     struct urb *urb, int free);
 
 /*
 	Start to listen on endpoint.
@@ -219,24 +219,42 @@ static void line6_async_request_sent(struct urb *urb)
 		usb_free_urb(urb);
 		kfree(msg);
 	} else
-		line6_send_raw_message_async_part(msg, urb);
+		line6_send_raw_message_async_part(msg, urb, 0);
+}
+
+static void line6_async_request_sent_free_buffer(struct urb *urb)
+{
+	struct message *msg = (struct message *)urb->context;
+
+	if (msg->done >= msg->size) {
+		usb_free_urb(urb);
+		kfree(msg->buffer);
+		kfree(msg);
+	} else
+		line6_send_raw_message_async_part(msg, urb, 1);
 }
 
 /*
 	Asynchronously send part of a raw message.
 */
 static int line6_send_raw_message_async_part(struct message *msg,
-					     struct urb *urb)
+					     struct urb *urb, int free)
 {
 	int retval;
 	struct usb_line6 *line6 = msg->line6;
 	int done = msg->done;
 	int bytes = min(msg->size - done, line6->max_packet_size);
+	usb_complete_t complete_fn;
+
+	if (free)
+		complete_fn = line6_async_request_sent_free_buffer;
+	else
+		complete_fn = line6_async_request_sent;
 
 	usb_fill_int_urb(urb, line6->usbdev,
 			 usb_sndintpipe(line6->usbdev, line6->ep_control_write),
-			 (char *)msg->buffer + done, bytes,
-			 line6_async_request_sent, msg, line6->interval);
+			 (char *)msg->buffer + done, bytes, complete_fn, msg,
+			 line6->interval);
 
 	msg->done += bytes;
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -267,7 +285,7 @@ void line6_start_timer(struct timer_list *timer, unsigned int msecs,
 	Asynchronously send raw message.
 */
 int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
-				 int size)
+				 int size, int free)
 {
 	struct message *msg;
 	struct urb *urb;
@@ -296,7 +314,7 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
 	msg->done = 0;
 
 	/* start sending: */
-	return line6_send_raw_message_async_part(msg, urb);
+	return line6_send_raw_message_async_part(msg, urb, free);
 }
 
 /*
@@ -316,8 +334,7 @@ int line6_version_request_async(struct usb_line6 *line6)
 	memcpy(buffer, line6_request_version, sizeof(line6_request_version));
 
 	retval = line6_send_raw_message_async(line6, buffer,
-					      sizeof(line6_request_version));
-	kfree(buffer);
+					      sizeof(line6_request_version), 1);
 	return retval;
 }
 

^ permalink raw reply related	[flat|nested] 8+ messages in thread
* Re: [patch 2/2] staging: line6: use after free bug requesting version
@ 2013-01-08 22:54 Markus Grabner
  0 siblings, 0 replies; 8+ messages in thread
From: Markus Grabner @ 2013-01-08 22:54 UTC (permalink / raw)
  To: kernel-janitors

Am Donnerstag, 6. Dezember 2012, 10:08:44 schrieb Dan Carpenter:
> On Thu, Dec 06, 2012 at 06:18:02AM +0100, Stefan Hajnoczi wrote:
> > On Wed, Dec 5, 2012 at 7:44 PM, Dan Carpenter <dan.carpenter@oracle.com> 
wrote:
> > > diff --git a/drivers/staging/line6/driver.c
> > > b/drivers/staging/line6/driver.c index 8a5d89e..884e0d8 100644
> > > --- a/drivers/staging/line6/driver.c
> > > +++ b/drivers/staging/line6/driver.c
> > > @@ -110,7 +110,7 @@ struct message {
> > > 
> > >  */
> > >  static void line6_data_received(struct urb *urb);
> > >  static int line6_send_raw_message_async_part(struct message *msg,
> > > 
> > > -                                            struct urb *urb);
> > > +                                            struct urb *urb, int free);
> > 
> > s/int/bool/
> > 
> > >  /*
> > >  
> > >         Start to listen on endpoint.
> > > 
> > > @@ -219,24 +219,42 @@ static void line6_async_request_sent(struct urb
> > > *urb)
> > > 
> > >                 usb_free_urb(urb);
> > >                 kfree(msg);
> > >         
> > >         } else
> > > 
> > > -               line6_send_raw_message_async_part(msg, urb);
> > > +               line6_send_raw_message_async_part(msg, urb, 0);
> > > +}
> > 
> > I'd add a bool free_buffer field to struct message and simply modify
> > line6_async_request_sent() to do:
> > 
> > if (msg->free_buffer)
> > 
> >          kfree(msg->buffer);
> > 
> > Then you don't need line6_async_request_sent_free_buffer() and
> > line6_send_raw_message_async_part() doesn't need to take a bool free
> > argument since struct message already contains that information.  It
> > would make the code simpler.
> 
> Yeah.  That's true.  I'll redo it.
Since two users reported this bug to me recently, I proposed a fix and asked 
them to test it. If it works for them, I'll prepare a patch against Stefan's 
repository. This is for your information only to avoid duplicate work in case 
you just wanted to pick this up again.

	Kind regards,
		Markus


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2013-01-17 21:52 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-12-05 18:44 [patch 2/2] staging: line6: use after free bug requesting version Dan Carpenter
2012-12-06  5:18 ` Stefan Hajnoczi
2012-12-06  7:08 ` Dan Carpenter
2013-01-09  6:25 ` Dan Carpenter
2013-01-13 18:15 ` Markus Grabner
2013-01-13 19:36 ` Stefan Hajnoczi
2013-01-17 21:52 ` Greg Kroah-Hartman
  -- strict thread matches above, loose matches on Subject: below --
2013-01-08 22:54 Markus Grabner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).