linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2.6] 2/3 Serio: possible race in handle_events
@ 2003-08-23  6:31 Dmitry Torokhov
  2003-08-23  7:00 ` Andrew Morton
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-08-23  6:31 UTC (permalink / raw)
  To: linux-kernel; +Cc: Vojtech Pavlik

The event handling in serio is racy because serio_handle_events does not
check whether serio in event list is still alive or has already been freed.
One possible solution is to check whether serio in question is still 
registered in serio_list and skip events referring to unknown serios.

Dmitry

diff -urN --exclude-from=/usr/src/exclude 2.6.0-test4/drivers/input/serio/serio.c linux-2.6.0-test4/drivers/input/serio/serio.c
--- 2.6.0-test4/drivers/input/serio/serio.c	2003-08-22 23:26:50.000000000 -0500
+++ linux-2.6.0-test4/drivers/input/serio/serio.c	2003-08-22 23:25:20.000000000 -0500
@@ -85,6 +85,16 @@
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
 
+static int is_known_serio(struct serio *serio)
+{
+	struct serio *s;
+	
+	list_for_each_entry(s, &serio_list, node)
+		if (s == serio)
+			return 1;
+	return 0;
+}
+
 void serio_handle_events(void)
 {
 	struct list_head *node, *next;
@@ -93,17 +103,21 @@
 	list_for_each_safe(node, next, &serio_event_list) {
 		event = container_of(node, struct serio_event, node);	
 
+		down(&serio_sem);
+		if (!is_known_serio(event->serio))
+			goto event_done;
+		
 		switch (event->type) {
 			case SERIO_RESCAN :
-				down(&serio_sem);
 				if (event->serio->dev && event->serio->dev->disconnect)
 					event->serio->dev->disconnect(event->serio);
 				serio_find_dev(event->serio);
-				up(&serio_sem);
 				break;
 			default:
 				break;
 		}
+event_done:	
+		up(&serio_sem);
 		list_del_init(node);
 		kfree(event);
 	}

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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
  2003-08-23  6:31 [PATCH 2.6] 2/3 Serio: possible race in handle_events Dmitry Torokhov
@ 2003-08-23  7:00 ` Andrew Morton
       [not found]   ` <200308230206.25142.dtor_core@ameritech.net>
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2003-08-23  7:00 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, vojtech

Dmitry Torokhov <dtor_core@ameritech.net> wrote:
>
> +static int is_known_serio(struct serio *serio)
>  +{
>  +	struct serio *s;
>  +	
>  +	list_for_each_entry(s, &serio_list, node)
>  +		if (s == serio)
>  +			return 1;
>  +	return 0;
>  +}

Could this just be

	return !list_empty(&serio->node);

?

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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
       [not found]   ` <200308230206.25142.dtor_core@ameritech.net>
@ 2003-08-23  7:19     ` Andrew Morton
  2003-08-23  7:25       ` Dmitry Torokhov
  0 siblings, 1 reply; 7+ messages in thread
From: Andrew Morton @ 2003-08-23  7:19 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, vojtech

Dmitry Torokhov <dtor_core@ameritech.net> wrote:
>
> On Saturday 23 August 2003 02:00 am, Andrew Morton wrote:
> > Dmitry Torokhov <dtor_core@ameritech.net> wrote:
> > > +static int is_known_serio(struct serio *serio)
> > >  +{
> > >  +	struct serio *s;
> > >  +
> > >  +	list_for_each_entry(s, &serio_list, node)
> > >  +		if (s == serio)
> > >  +			return 1;
> > >  +	return 0;
> > >  +}
> >
> > Could this just be
> >
> > 	return !list_empty(&serio->node);
> >
> > ?
> 
> The serio could be free()d, I dont think we want to call list_empty with 
> a dangling pointer. Or am I missing something?
> 

Well if we're playing around with a freed pointer then something is
seriously wrong.  Like, someone could have allocated a new one and got the
same address.

If event->serio can point at freed memory and there's any doubt over it
then we should be nulling out event->serio to indicate that.


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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
  2003-08-23  7:19     ` Andrew Morton
@ 2003-08-23  7:25       ` Dmitry Torokhov
  2003-08-23  7:34         ` Andrew Morton
  0 siblings, 1 reply; 7+ messages in thread
From: Dmitry Torokhov @ 2003-08-23  7:25 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, vojtech

On Saturday 23 August 2003 02:19 am, Andrew Morton wrote:
> Dmitry Torokhov <dtor_core@ameritech.net> wrote:
> > On Saturday 23 August 2003 02:00 am, Andrew Morton wrote:
> > > Dmitry Torokhov <dtor_core@ameritech.net> wrote:
> > > > +static int is_known_serio(struct serio *serio)
> > > >  +{
> > > >  +	struct serio *s;
> > > >  +
> > > >  +	list_for_each_entry(s, &serio_list, node)
> > > >  +		if (s == serio)
> > > >  +			return 1;
> > > >  +	return 0;
> > > >  +}
> > >
> > > Could this just be
> > >
> > > 	return !list_empty(&serio->node);
> > >
> > > ?
> >
> > The serio could be free()d, I dont think we want to call list_empty with
> > a dangling pointer. Or am I missing something?
>
> Well if we're playing around with a freed pointer then something is
> seriously wrong.  Like, someone could have allocated a new one and got the
> same address.
>
> If event->serio can point at freed memory and there's any doubt over it
> then we should be nulling out event->serio to indicate that.

Right now we can't as events are queued in an event list and are processed by 
other thread; serio does not know that it's queued and even existence of the
event list is not known outside of serio.c module.

Do you think we should introduce allocate_serio/free_serio pair for dynamically 
allocated serios; free_serio would scan event_list and invalidate events that 
refer to freed serio?

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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
  2003-08-23  7:25       ` Dmitry Torokhov
@ 2003-08-23  7:34         ` Andrew Morton
  2003-08-23 11:41           ` Zwane Mwaikambo
  2003-08-23 21:42           ` Dmitry Torokhov
  0 siblings, 2 replies; 7+ messages in thread
From: Andrew Morton @ 2003-08-23  7:34 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, vojtech

Dmitry Torokhov <dtor_core@ameritech.net> wrote:
>
> Do you think we should introduce allocate_serio/free_serio pair for dynamically 
>  allocated serios; free_serio would scan event_list and invalidate events that 
>  refer to freed serio?

I don't understand the subsystem well enough to say.  But if we are
receiving events which refer to an already-freed serio then something is
very broken.  We should be draining all those events before allowing the
original object to be freed up.

Let's wait for Vojtech's comments.



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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
  2003-08-23  7:34         ` Andrew Morton
@ 2003-08-23 11:41           ` Zwane Mwaikambo
  2003-08-23 21:42           ` Dmitry Torokhov
  1 sibling, 0 replies; 7+ messages in thread
From: Zwane Mwaikambo @ 2003-08-23 11:41 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Dmitry Torokhov, linux-kernel, vojtech

On Sat, 23 Aug 2003, Andrew Morton wrote:

> Dmitry Torokhov <dtor_core@ameritech.net> wrote:
> >
> > Do you think we should introduce allocate_serio/free_serio pair for dynamically 
> >  allocated serios; free_serio would scan event_list and invalidate events that 
> >  refer to freed serio?
> 
> I don't understand the subsystem well enough to say.  But if we are
> receiving events which refer to an already-freed serio then something is
> very broken.  We should be draining all those events before allowing the
> original object to be freed up.
> 
> Let's wait for Vojtech's comments.

This sounds somewhat like;

http://bugzilla.kernel.org/show_bug.cgi?id=973

Jul 25 04:54:24 lap kernel: slab error in cache_free_debugcheck(): cache 
`size-32': double free, or memory before object was overwritten
Jul 25 04:54:24 lap kernel: Call Trace:
Jul 25 04:54:24 lap kernel:  [<c014f130>] kfree+0xf0/0x310
Jul 25 04:54:24 lap kernel:  [<c02540fc>] psmouse_disconnect+0x2c/0x40
Jul 25 04:54:24 lap kernel:  [<c02540fc>] psmouse_disconnect+0x2c/0x40
Jul 25 04:54:24 lap kernel:  [<c025560d>] serio_handle_events+0xad/0xc0
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c0255665>] serio_thread+0x45/0x100
Jul 25 04:54:24 lap kernel:  [<c010a126>] work_resched+0x5/0x16
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c01073b9>] kernel_thread_helper+0x5/0xc
Jul 25 04:54:24 lap kernel:
Jul 25 04:54:24 lap kernel: slab error in cache_free_debugcheck(): cache 
`size-32': double free, or memory after  object was overwritten

Jul 25 04:54:24 lap kernel: Call Trace:
Jul 25 04:54:24 lap kernel:  [<c014f15e>] kfree+0x11e/0x310
Jul 25 04:54:24 lap kernel:  [<c02540fc>] psmouse_disconnect+0x2c/0x40
Jul 25 04:54:24 lap kernel:  [<c02540fc>] psmouse_disconnect+0x2c/0x40
Jul 25 04:54:24 lap kernel:  [<c025560d>] serio_handle_events+0xad/0xc0
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c0255665>] serio_thread+0x45/0x100
Jul 25 04:54:24 lap kernel:  [<c010a126>] work_resched+0x5/0x16
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c0255620>] serio_thread+0x0/0x100
Jul 25 04:54:24 lap kernel:  [<c01073b9>] kernel_thread_helper+0x5/0xc
Jul 25 04:54:24 lap kernel:

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

* Re: [PATCH 2.6] 2/3 Serio: possible race in handle_events
  2003-08-23  7:34         ` Andrew Morton
  2003-08-23 11:41           ` Zwane Mwaikambo
@ 2003-08-23 21:42           ` Dmitry Torokhov
  1 sibling, 0 replies; 7+ messages in thread
From: Dmitry Torokhov @ 2003-08-23 21:42 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, vojtech

On Saturday 23 August 2003 02:34 am, Andrew Morton wrote:
> Dmitry Torokhov <dtor_core@ameritech.net> wrote:
> > Do you think we should introduce allocate_serio/free_serio pair for
> > dynamically allocated serios; free_serio would scan event_list and
> > invalidate events that refer to freed serio?
>
> I don't understand the subsystem well enough to say.  But if we are
> receiving events which refer to an already-freed serio then something is
> very broken.  We should be draining all those events before allowing the
> original object to be freed up.
>
> Let's wait for Vojtech's comments.

I think the patch below should work. We invalidate serio events at the same
time serio itself is unregistered.

The patch is on top of the 3 previous ones + synaptics, but if needed I can 
rediff against vanilla kernel.


diff -urN --exclude-from=/usr/src/exclude 2.6.0-test4/drivers/input/serio/serio.c linux-2.6.0-test4/drivers/input/serio/serio.c
--- 2.6.0-test4/drivers/input/serio/serio.c	2003-08-23 00:38:10.000000000 -0500
+++ linux-2.6.0-test4/drivers/input/serio/serio.c	2003-08-23 16:28:28.000000000 -0500
@@ -89,14 +89,13 @@
 static DECLARE_WAIT_QUEUE_HEAD(serio_wait);
 static DECLARE_COMPLETION(serio_exited);
 
-static int is_known_serio(struct serio *serio)
+static void serio_invalidate_pending_events(struct serio *serio)
 {
-	struct serio *s;
+	struct serio_event *event;
 	
-	list_for_each_entry(s, &serio_list, node)
-		if (s == serio)
-			return 1;
-	return 0;
+	list_for_each_entry(event, &serio_event_list, node)
+		if (event->serio == serio)
+			event->serio = NULL;
 }
 
 void serio_handle_events(void)
@@ -108,7 +107,7 @@
 		event = container_of(node, struct serio_event, node);	
 
 		down(&serio_sem);
-		if (!is_known_serio(event->serio))
+		if (event->serio == NULL)
 			goto event_done;
 		
 		switch (event->type) {
@@ -213,6 +212,7 @@
 void serio_unregister_port(struct serio *serio)
 {
 	down(&serio_sem);
+	serio_invalidate_pending_events(serio);
 	list_del_init(&serio->node);
 	if (serio->dev && serio->dev->disconnect)
 		serio->dev->disconnect(serio);
@@ -226,6 +226,7 @@
  */
 void serio_unregister_slave_port(struct serio *serio)
 {
+	serio_invalidate_pending_events(serio);
 	list_del_init(&serio->node);
 	if (serio->dev && serio->dev->disconnect)
 		serio->dev->disconnect(serio);

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

end of thread, other threads:[~2003-08-23 21:43 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-08-23  6:31 [PATCH 2.6] 2/3 Serio: possible race in handle_events Dmitry Torokhov
2003-08-23  7:00 ` Andrew Morton
     [not found]   ` <200308230206.25142.dtor_core@ameritech.net>
2003-08-23  7:19     ` Andrew Morton
2003-08-23  7:25       ` Dmitry Torokhov
2003-08-23  7:34         ` Andrew Morton
2003-08-23 11:41           ` Zwane Mwaikambo
2003-08-23 21:42           ` Dmitry Torokhov

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).