All of lore.kernel.org
 help / color / mirror / Atom feed
* Race in vt_event_wait() during suspend/resume
@ 2012-05-18 11:04 Rabin Vincent
  2012-05-18 11:40 ` Alan Cox
  0 siblings, 1 reply; 7+ messages in thread
From: Rabin Vincent @ 2012-05-18 11:04 UTC (permalink / raw)
  To: alan, gregkh; +Cc: LKML

pm_restore_console() is called from the suspend/resume path,
this calls vt_move_to_console(), which calls vt_event_wait().

There's a race in this path which causes the process
which requests the suspend to sleep indefinitely waiting
for an event which already happened:

P1					P2
 vt_move_to_console()
   set_console()
     schedule_console_callback()
   vt_waitactive()
     check n == fg_console +1
					console_callback()
					  switch_screen()
					  vt_event_post() // no waiters

     vt_event_wait() // forever

I think the following should fix it.  Comments?

diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,16 +110,7 @@ void vt_event_post(unsigned int event, unsigned
int old, unsigned int new)
 		wake_up_interruptible(&vt_event_waitqueue);
 }

-/**
- *	vt_event_wait		-	wait for an event
- *	@vw: our event
- *
- *	Waits for an event to occur which completes our vt_event_wait
- *	structure. On return the structure has wv->done set to 1 for success
- *	or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
+static void __vt_event_queue(struct vt_event_wait *vw)
 {
 	unsigned long flags;
 	/* Prepare the event */
@@ -129,8 +120,18 @@ static void vt_event_wait(struct vt_event_wait *vw)
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_add(&vw->list, &vt_events);
 	spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
 	/* Wait for it to pass */
 	wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+	unsigned long flags;
+
 	/* Dequeue it */
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_del(&vw->list);
@@ -138,6 +139,22 @@ static void vt_event_wait(struct vt_event_wait *vw)
 }

 /**
+ *	vt_event_wait		-	wait for an event
+ *	@vw: our event
+ *
+ *	Waits for an event to occur which completes our vt_event_wait
+ *	structure. On return the structure has wv->done set to 1 for success
+ *	or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+	__vt_event_queue(vw);
+	__vt_event_wait(vw);
+	__vt_event_dequeue(vw);
+}
+
+/**
  *	vt_event_wait_ioctl	-	event ioctl handler
  *	@arg: argument to ioctl
  *
@@ -177,10 +194,14 @@ int vt_waitactive(int n)
 {
 	struct vt_event_wait vw;
 	do {
-		if (n == fg_console + 1)
-			break;
 		vw.event.event = VT_EVENT_SWITCH;
-		vt_event_wait(&vw);
+		__vt_event_queue(&vw);
+		if (n == fg_console + 1) {
+			__vt_event_dequeue(&vw);
+			break;
+		}
+		__vt_event_wait(&vw);
+		__vt_event_dequeue(&vw);
 		if (vw.done == 0)
 			return -EINTR;
 	} while (vw.event.newev != n);

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

* Re: Race in vt_event_wait() during suspend/resume
  2012-05-18 11:04 Race in vt_event_wait() during suspend/resume Rabin Vincent
@ 2012-05-18 11:40 ` Alan Cox
  2012-05-18 18:06   ` Greg KH
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Cox @ 2012-05-18 11:40 UTC (permalink / raw)
  To: Rabin Vincent; +Cc: alan, gregkh, LKML

On Fri, 18 May 2012 16:34:53 +0530
Rabin Vincent <rabin@rab.in> wrote:

> pm_restore_console() is called from the suspend/resume path,
> this calls vt_move_to_console(), which calls vt_event_wait().
> 
> There's a race in this path which causes the process
> which requests the suspend to sleep indefinitely waiting
> for an event which already happened:
> 
> P1					P2
>  vt_move_to_console()
>    set_console()
>      schedule_console_callback()
>    vt_waitactive()
>      check n == fg_console +1
> 					console_callback()
> 					  switch_screen()
> 					  vt_event_post() // no waiters
> 
>      vt_event_wait() // forever
> 
> I think the following should fix it.  Comments?
> 

Looks right to me.

Alan

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

* Re: Race in vt_event_wait() during suspend/resume
  2012-05-18 11:40 ` Alan Cox
@ 2012-05-18 18:06   ` Greg KH
  2012-05-21  8:08     ` [PATCH] vt: fix race in vt_waitactive() Rabin Vincent
  0 siblings, 1 reply; 7+ messages in thread
From: Greg KH @ 2012-05-18 18:06 UTC (permalink / raw)
  To: Alan Cox; +Cc: Rabin Vincent, alan, LKML

On Fri, May 18, 2012 at 12:40:51PM +0100, Alan Cox wrote:
> On Fri, 18 May 2012 16:34:53 +0530
> Rabin Vincent <rabin@rab.in> wrote:
> 
> > pm_restore_console() is called from the suspend/resume path,
> > this calls vt_move_to_console(), which calls vt_event_wait().
> > 
> > There's a race in this path which causes the process
> > which requests the suspend to sleep indefinitely waiting
> > for an event which already happened:
> > 
> > P1					P2
> >  vt_move_to_console()
> >    set_console()
> >      schedule_console_callback()
> >    vt_waitactive()
> >      check n == fg_console +1
> > 					console_callback()
> > 					  switch_screen()
> > 					  vt_event_post() // no waiters
> > 
> >      vt_event_wait() // forever
> > 
> > I think the following should fix it.  Comments?
> > 
> 
> Looks right to me.

Great, Rabin, care to resend it with a proper Signed-off-by: line so
that I can apply it?

thanks,

greg k-h

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

* [PATCH] vt: fix race in vt_waitactive()
  2012-05-18 18:06   ` Greg KH
@ 2012-05-21  8:08     ` Rabin Vincent
  2012-06-13 23:44       ` Greg KH
  0 siblings, 1 reply; 7+ messages in thread
From: Rabin Vincent @ 2012-05-21  8:08 UTC (permalink / raw)
  To: gregkh; +Cc: linux-kernel, rabin, Rabin Vincent, Alan Cox

pm_restore_console() is called from the suspend/resume path, and this
calls vt_move_to_console(), which calls vt_waitactive().

There's a race in this path which causes the process which requests the
suspend to sleep indefinitely waiting for an event which already
happened:

P1                                      P2
 vt_move_to_console()
  set_console()
    schedule_console_callback()
  vt_waitactive()
    check n == fg_console +1
                                       console_callback()
                                         switch_screen()
                                         vt_event_post() // no waiters

    vt_event_wait() // forever

Fix the race by ensuring we're registered for the event before we check
if it's already completed.

Cc: Alan Cox <alan@linux.intel.com>
Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
---
 drivers/tty/vt/vt_ioctl.c |   47 ++++++++++++++++++++++++++++++++------------
 1 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef1..1d02e32 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -110,16 +110,7 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
 		wake_up_interruptible(&vt_event_waitqueue);
 }
 
-/**
- *	vt_event_wait		-	wait for an event
- *	@vw: our event
- *
- *	Waits for an event to occur which completes our vt_event_wait
- *	structure. On return the structure has wv->done set to 1 for success
- *	or 0 if some event such as a signal ended the wait.
- */
-
-static void vt_event_wait(struct vt_event_wait *vw)
+static void __vt_event_queue(struct vt_event_wait *vw)
 {
 	unsigned long flags;
 	/* Prepare the event */
@@ -129,8 +120,18 @@ static void vt_event_wait(struct vt_event_wait *vw)
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_add(&vw->list, &vt_events);
 	spin_unlock_irqrestore(&vt_event_lock, flags);
+}
+
+static void __vt_event_wait(struct vt_event_wait *vw)
+{
 	/* Wait for it to pass */
 	wait_event_interruptible(vt_event_waitqueue, vw->done);
+}
+
+static void __vt_event_dequeue(struct vt_event_wait *vw)
+{
+	unsigned long flags;
+
 	/* Dequeue it */
 	spin_lock_irqsave(&vt_event_lock, flags);
 	list_del(&vw->list);
@@ -138,6 +139,22 @@ static void vt_event_wait(struct vt_event_wait *vw)
 }
 
 /**
+ *	vt_event_wait		-	wait for an event
+ *	@vw: our event
+ *
+ *	Waits for an event to occur which completes our vt_event_wait
+ *	structure. On return the structure has wv->done set to 1 for success
+ *	or 0 if some event such as a signal ended the wait.
+ */
+
+static void vt_event_wait(struct vt_event_wait *vw)
+{
+	__vt_event_queue(vw);
+	__vt_event_wait(vw);
+	__vt_event_dequeue(vw);
+}
+
+/**
  *	vt_event_wait_ioctl	-	event ioctl handler
  *	@arg: argument to ioctl
  *
@@ -177,10 +194,14 @@ int vt_waitactive(int n)
 {
 	struct vt_event_wait vw;
 	do {
-		if (n == fg_console + 1)
-			break;
 		vw.event.event = VT_EVENT_SWITCH;
-		vt_event_wait(&vw);
+		__vt_event_queue(&vw);
+		if (n == fg_console + 1) {
+			__vt_event_dequeue(&vw);
+			break;
+		}
+		__vt_event_wait(&vw);
+		__vt_event_dequeue(&vw);
 		if (vw.done == 0)
 			return -EINTR;
 	} while (vw.event.newev != n);
-- 
1.7.4.3


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

* Re: [PATCH] vt: fix race in vt_waitactive()
  2012-05-21  8:08     ` [PATCH] vt: fix race in vt_waitactive() Rabin Vincent
@ 2012-06-13 23:44       ` Greg KH
  2012-06-14  9:48         ` Alan Cox
  0 siblings, 1 reply; 7+ messages in thread
From: Greg KH @ 2012-06-13 23:44 UTC (permalink / raw)
  To: Alan Cox, Rabin Vincent; +Cc: linux-kernel, rabin

On Mon, May 21, 2012 at 01:38:42PM +0530, Rabin Vincent wrote:
> pm_restore_console() is called from the suspend/resume path, and this
> calls vt_move_to_console(), which calls vt_waitactive().
> 
> There's a race in this path which causes the process which requests the
> suspend to sleep indefinitely waiting for an event which already
> happened:
> 
> P1                                      P2
>  vt_move_to_console()
>   set_console()
>     schedule_console_callback()
>   vt_waitactive()
>     check n == fg_console +1
>                                        console_callback()
>                                          switch_screen()
>                                          vt_event_post() // no waiters
> 
>     vt_event_wait() // forever
> 
> Fix the race by ensuring we're registered for the event before we check
> if it's already completed.
> 
> Cc: Alan Cox <alan@linux.intel.com>
> Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
> ---
>  drivers/tty/vt/vt_ioctl.c |   47 ++++++++++++++++++++++++++++++++------------
>  1 files changed, 34 insertions(+), 13 deletions(-)

Alan, any thoughts on this patch?

thanks,

greg k-h

> 
> diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
> index ede2ef1..1d02e32 100644
> --- a/drivers/tty/vt/vt_ioctl.c
> +++ b/drivers/tty/vt/vt_ioctl.c
> @@ -110,16 +110,7 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
>  		wake_up_interruptible(&vt_event_waitqueue);
>  }
>  
> -/**
> - *	vt_event_wait		-	wait for an event
> - *	@vw: our event
> - *
> - *	Waits for an event to occur which completes our vt_event_wait
> - *	structure. On return the structure has wv->done set to 1 for success
> - *	or 0 if some event such as a signal ended the wait.
> - */
> -
> -static void vt_event_wait(struct vt_event_wait *vw)
> +static void __vt_event_queue(struct vt_event_wait *vw)
>  {
>  	unsigned long flags;
>  	/* Prepare the event */
> @@ -129,8 +120,18 @@ static void vt_event_wait(struct vt_event_wait *vw)
>  	spin_lock_irqsave(&vt_event_lock, flags);
>  	list_add(&vw->list, &vt_events);
>  	spin_unlock_irqrestore(&vt_event_lock, flags);
> +}
> +
> +static void __vt_event_wait(struct vt_event_wait *vw)
> +{
>  	/* Wait for it to pass */
>  	wait_event_interruptible(vt_event_waitqueue, vw->done);
> +}
> +
> +static void __vt_event_dequeue(struct vt_event_wait *vw)
> +{
> +	unsigned long flags;
> +
>  	/* Dequeue it */
>  	spin_lock_irqsave(&vt_event_lock, flags);
>  	list_del(&vw->list);
> @@ -138,6 +139,22 @@ static void vt_event_wait(struct vt_event_wait *vw)
>  }
>  
>  /**
> + *	vt_event_wait		-	wait for an event
> + *	@vw: our event
> + *
> + *	Waits for an event to occur which completes our vt_event_wait
> + *	structure. On return the structure has wv->done set to 1 for success
> + *	or 0 if some event such as a signal ended the wait.
> + */
> +
> +static void vt_event_wait(struct vt_event_wait *vw)
> +{
> +	__vt_event_queue(vw);
> +	__vt_event_wait(vw);
> +	__vt_event_dequeue(vw);
> +}
> +
> +/**
>   *	vt_event_wait_ioctl	-	event ioctl handler
>   *	@arg: argument to ioctl
>   *
> @@ -177,10 +194,14 @@ int vt_waitactive(int n)
>  {
>  	struct vt_event_wait vw;
>  	do {
> -		if (n == fg_console + 1)
> -			break;
>  		vw.event.event = VT_EVENT_SWITCH;
> -		vt_event_wait(&vw);
> +		__vt_event_queue(&vw);
> +		if (n == fg_console + 1) {
> +			__vt_event_dequeue(&vw);
> +			break;
> +		}
> +		__vt_event_wait(&vw);
> +		__vt_event_dequeue(&vw);
>  		if (vw.done == 0)
>  			return -EINTR;
>  	} while (vw.event.newev != n);
> -- 
> 1.7.4.3

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

* Re: [PATCH] vt: fix race in vt_waitactive()
  2012-06-13 23:44       ` Greg KH
@ 2012-06-14  9:48         ` Alan Cox
  2012-06-14 17:20           ` Greg KH
  0 siblings, 1 reply; 7+ messages in thread
From: Alan Cox @ 2012-06-14  9:48 UTC (permalink / raw)
  To: Greg KH; +Cc: Alan Cox, Rabin Vincent, linux-kernel, rabin

On Wed, 13 Jun 2012 16:44:52 -0700
Greg KH <gregkh@linuxfoundation.org> wrote:

> On Mon, May 21, 2012 at 01:38:42PM +0530, Rabin Vincent wrote:
> > pm_restore_console() is called from the suspend/resume path, and this
> > calls vt_move_to_console(), which calls vt_waitactive().
> > 
> > There's a race in this path which causes the process which requests the
> > suspend to sleep indefinitely waiting for an event which already
> > happened:
> > 
> > P1                                      P2
> >  vt_move_to_console()
> >   set_console()
> >     schedule_console_callback()
> >   vt_waitactive()
> >     check n == fg_console +1
> >                                        console_callback()
> >                                          switch_screen()
> >                                          vt_event_post() // no waiters
> > 
> >     vt_event_wait() // forever
> > 
> > Fix the race by ensuring we're registered for the event before we check
> > if it's already completed.
> > 
> > Cc: Alan Cox <alan@linux.intel.com>
> > Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
> > ---
> >  drivers/tty/vt/vt_ioctl.c |   47 ++++++++++++++++++++++++++++++++------------
> >  1 files changed, 34 insertions(+), 13 deletions(-)
> 
> Alan, any thoughts on this patch?

I acked it when first posted - I believe its correct.

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

* Re: [PATCH] vt: fix race in vt_waitactive()
  2012-06-14  9:48         ` Alan Cox
@ 2012-06-14 17:20           ` Greg KH
  0 siblings, 0 replies; 7+ messages in thread
From: Greg KH @ 2012-06-14 17:20 UTC (permalink / raw)
  To: Alan Cox; +Cc: Alan Cox, Rabin Vincent, linux-kernel, rabin

On Thu, Jun 14, 2012 at 10:48:02AM +0100, Alan Cox wrote:
> On Wed, 13 Jun 2012 16:44:52 -0700
> Greg KH <gregkh@linuxfoundation.org> wrote:
> 
> > On Mon, May 21, 2012 at 01:38:42PM +0530, Rabin Vincent wrote:
> > > pm_restore_console() is called from the suspend/resume path, and this
> > > calls vt_move_to_console(), which calls vt_waitactive().
> > > 
> > > There's a race in this path which causes the process which requests the
> > > suspend to sleep indefinitely waiting for an event which already
> > > happened:
> > > 
> > > P1                                      P2
> > >  vt_move_to_console()
> > >   set_console()
> > >     schedule_console_callback()
> > >   vt_waitactive()
> > >     check n == fg_console +1
> > >                                        console_callback()
> > >                                          switch_screen()
> > >                                          vt_event_post() // no waiters
> > > 
> > >     vt_event_wait() // forever
> > > 
> > > Fix the race by ensuring we're registered for the event before we check
> > > if it's already completed.
> > > 
> > > Cc: Alan Cox <alan@linux.intel.com>
> > > Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com>
> > > ---
> > >  drivers/tty/vt/vt_ioctl.c |   47 ++++++++++++++++++++++++++++++++------------
> > >  1 files changed, 34 insertions(+), 13 deletions(-)
> > 
> > Alan, any thoughts on this patch?
> 
> I acked it when first posted - I believe its correct.

Ah, sorry, I missed that somehow.  I'll go queue it up now.

greg k-h

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

end of thread, other threads:[~2012-06-14 17:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-18 11:04 Race in vt_event_wait() during suspend/resume Rabin Vincent
2012-05-18 11:40 ` Alan Cox
2012-05-18 18:06   ` Greg KH
2012-05-21  8:08     ` [PATCH] vt: fix race in vt_waitactive() Rabin Vincent
2012-06-13 23:44       ` Greg KH
2012-06-14  9:48         ` Alan Cox
2012-06-14 17:20           ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.