linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
@ 2019-01-18  9:27 Li RongQing
  2019-01-18 12:50 ` Kohli, Gaurav
  2019-01-30 10:19 ` Greg KH
  0 siblings, 2 replies; 9+ messages in thread
From: Li RongQing @ 2019-01-18  9:27 UTC (permalink / raw)
  To: gregkh, jslaby, linux-kernel, gkohli

There still is a race window after the commit b027e2298bd588
("tty: fix data race between tty_init_dev and flush of buf"),
and we encountered this crash issue if receive_buf call comes
before tty initialization completes in n_tty_open and
tty->driver_data may be NULL.

CPU0                                    CPU1
----                                    ----
                                 n_tty_open
                                   tty_init_dev
                                     tty_ldisc_unlock
                                       schedule
flush_to_ldisc
 receive_buf
  tty_port_default_receive_buf
   tty_ldisc_receive_buf
    n_tty_receive_buf_common
      __receive_buf
       uart_flush_chars
        uart_start
        /*tty->driver_data is NULL*/
                                   tty->ops->open
                                   /*init tty->driver_data*/

it can be fixed by extending ldisc semaphore lock in tty_init_dev
to driver_data initialized completely after tty->ops->open(), but
this will lead to put lock on one function and unlock in some other
function, and hard to maintain, so fix this race only by checking
tty->driver_data when receiving, and return if tty->driver_data
is NULL

Signed-off-by: Wang Li <wangli39@baidu.com>
Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
Signed-off-by: Li RongQing <lirongqing@baidu.com>
---
V4: add version information
V3: not used ldisc semaphore lock, only checking tty->driver_data with NULL
V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
V1: extend ldisc lock to protect that tty->driver_data is inited 

drivers/tty/tty_port.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index 044c3cbdcfa4..86d0bec38322 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port *port,
 	if (!tty)
 		return 0;
 
+	if (!tty->driver_data)
+		return 0;
+
 	disc = tty_ldisc_ref(tty);
 	if (!disc)
 		return 0;
-- 
2.16.2


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

* Re: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-18  9:27 [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open Li RongQing
@ 2019-01-18 12:50 ` Kohli, Gaurav
  2019-01-30  9:29   ` 答复: " Li,Rongqing
  2019-01-30 10:19 ` Greg KH
  1 sibling, 1 reply; 9+ messages in thread
From: Kohli, Gaurav @ 2019-01-18 12:50 UTC (permalink / raw)
  To: Li RongQing, gregkh, jslaby, linux-kernel



On 1/18/2019 2:57 PM, Li RongQing wrote:
> There still is a race window after the commit b027e2298bd588
> ("tty: fix data race between tty_init_dev and flush of buf"),
> and we encountered this crash issue if receive_buf call comes
> before tty initialization completes in n_tty_open and
> tty->driver_data may be NULL.
> 
> CPU0                                    CPU1
> ----                                    ----
>                                   n_tty_open
>                                     tty_init_dev
>                                       tty_ldisc_unlock
>                                         schedule
> flush_to_ldisc
>   receive_buf
>    tty_port_default_receive_buf
>     tty_ldisc_receive_buf
>      n_tty_receive_buf_common
>        __receive_buf
>         uart_flush_chars
>          uart_start
>          /*tty->driver_data is NULL*/
>                                     tty->ops->open
>                                     /*init tty->driver_data*/
> 
> it can be fixed by extending ldisc semaphore lock in tty_init_dev
> to driver_data initialized completely after tty->ops->open(), but
> this will lead to put lock on one function and unlock in some other
> function, and hard to maintain, so fix this race only by checking
> tty->driver_data when receiving, and return if tty->driver_data
> is NULL
> 
> Signed-off-by: Wang Li <wangli39@baidu.com>
> Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
> V4: add version information
> V3: not used ldisc semaphore lock, only checking tty->driver_data with NULL
> V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> V1: extend ldisc lock to protect that tty->driver_data is inited
> 
> drivers/tty/tty_port.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
> index 044c3cbdcfa4..86d0bec38322 100644
> --- a/drivers/tty/tty_port.c
> +++ b/drivers/tty/tty_port.c
> @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port *port,
>   	if (!tty)
>   		return 0;
>   
> +	if (!tty->driver_data)
> +		return 0;
> +
>   	disc = tty_ldisc_ref(tty);
>   	if (!disc)
>   		return 0;
>
Acked-by: Gaurav Kohli <gkohli@codeaurora.org>

It looks good to me w.r.t previous approach, but Let's Maintainer decide 
once.

Regards
Gaurav
-- 
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, 
Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project.

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

* 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-18 12:50 ` Kohli, Gaurav
@ 2019-01-30  9:29   ` Li,Rongqing
  0 siblings, 0 replies; 9+ messages in thread
From: Li,Rongqing @ 2019-01-30  9:29 UTC (permalink / raw)
  To: Kohli, Gaurav, gregkh, jslaby, linux-kernel
  Cc: Greg Kroah-Hartman, linux-serial



> -----邮件原件-----
> 发件人: Kohli, Gaurav [mailto:gkohli@codeaurora.org]
> 发送时间: 2019年1月18日 20:51
> 收件人: Li,Rongqing <lirongqing@baidu.com>; gregkh@linuxfoundation.org;
> jslaby@suse.com; linux-kernel@vger.kernel.org
> 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
> 
> 
> 
> On 1/18/2019 2:57 PM, Li RongQing wrote:
> > There still is a race window after the commit b027e2298bd588
> > ("tty: fix data race between tty_init_dev and flush of buf"), and we
> > encountered this crash issue if receive_buf call comes before tty
> > initialization completes in n_tty_open and
> > tty->driver_data may be NULL.
> >
> > CPU0                                    CPU1
> > ----                                    ----
> >                                   n_tty_open
> >                                     tty_init_dev
> >                                       tty_ldisc_unlock
> >                                         schedule flush_to_ldisc
> >   receive_buf
> >    tty_port_default_receive_buf
> >     tty_ldisc_receive_buf
> >      n_tty_receive_buf_common
> >        __receive_buf
> >         uart_flush_chars
> >          uart_start
> >          /*tty->driver_data is NULL*/
> >                                     tty->ops->open
> >                                     /*init tty->driver_data*/
> >
> > it can be fixed by extending ldisc semaphore lock in tty_init_dev to
> > driver_data initialized completely after tty->ops->open(), but this
> > will lead to put lock on one function and unlock in some other
> > function, and hard to maintain, so fix this race only by checking
> > tty->driver_data when receiving, and return if tty->driver_data
> > is NULL
> >
> > Signed-off-by: Wang Li <wangli39@baidu.com>
> > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > ---
> > V4: add version information
> > V3: not used ldisc semaphore lock, only checking tty->driver_data with
> > NULL
> > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > V1: extend ldisc lock to protect that tty->driver_data is inited
> >
> > drivers/tty/tty_port.c | 3 +++
> >   1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index
> > 044c3cbdcfa4..86d0bec38322 100644
> > --- a/drivers/tty/tty_port.c
> > +++ b/drivers/tty/tty_port.c
> > @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port
> *port,
> >   	if (!tty)
> >   		return 0;
> >
> > +	if (!tty->driver_data)
> > +		return 0;
> > +
> >   	disc = tty_ldisc_ref(tty);
> >   	if (!disc)
> >   		return 0;
> >
> Acked-by: Gaurav Kohli <gkohli@codeaurora.org>
> 
> It looks good to me w.r.t previous approach, but Let's Maintainer decide once.
> 

Thanks for your review, this one is simple and safe, it is used as live-patch online

-RongQing


> Regards
> Gaurav
> --
> Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.
> is a member of the Code Aurora Forum, a Linux Foundation Collaborative
> Project.

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

* Re: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-18  9:27 [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open Li RongQing
  2019-01-18 12:50 ` Kohli, Gaurav
@ 2019-01-30 10:19 ` Greg KH
  2019-01-30 12:48   ` 答复: " Li,Rongqing
  1 sibling, 1 reply; 9+ messages in thread
From: Greg KH @ 2019-01-30 10:19 UTC (permalink / raw)
  To: Li RongQing; +Cc: jslaby, linux-kernel, gkohli

On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> There still is a race window after the commit b027e2298bd588
> ("tty: fix data race between tty_init_dev and flush of buf"),
> and we encountered this crash issue if receive_buf call comes
> before tty initialization completes in n_tty_open and
> tty->driver_data may be NULL.
> 
> CPU0                                    CPU1
> ----                                    ----
>                                  n_tty_open
>                                    tty_init_dev
>                                      tty_ldisc_unlock
>                                        schedule
> flush_to_ldisc
>  receive_buf
>   tty_port_default_receive_buf
>    tty_ldisc_receive_buf
>     n_tty_receive_buf_common
>       __receive_buf
>        uart_flush_chars
>         uart_start
>         /*tty->driver_data is NULL*/
>                                    tty->ops->open
>                                    /*init tty->driver_data*/
> 
> it can be fixed by extending ldisc semaphore lock in tty_init_dev
> to driver_data initialized completely after tty->ops->open(), but
> this will lead to put lock on one function and unlock in some other
> function, and hard to maintain, so fix this race only by checking
> tty->driver_data when receiving, and return if tty->driver_data
> is NULL
> 
> Signed-off-by: Wang Li <wangli39@baidu.com>
> Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> Signed-off-by: Li RongQing <lirongqing@baidu.com>
> ---
> V4: add version information
> V3: not used ldisc semaphore lock, only checking tty->driver_data with NULL
> V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> V1: extend ldisc lock to protect that tty->driver_data is inited 
> 
> drivers/tty/tty_port.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
> index 044c3cbdcfa4..86d0bec38322 100644
> --- a/drivers/tty/tty_port.c
> +++ b/drivers/tty/tty_port.c
> @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port *port,
>  	if (!tty)
>  		return 0;
>  
> +	if (!tty->driver_data)
> +		return 0;
> +

How is this working?  What is setting driver_data to NULL to "stop" this
race?

There's no requirement that a tty driver set this field to NULL when it
is "done" with the tty device, so I think you are just getting lucky in
that your specific driver happens to be doing this.

What driver are you testing this against?

thanks,

greg k-h

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

* 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-30 10:19 ` Greg KH
@ 2019-01-30 12:48   ` Li,Rongqing
  2019-01-30 13:16     ` Greg KH
  0 siblings, 1 reply; 9+ messages in thread
From: Li,Rongqing @ 2019-01-30 12:48 UTC (permalink / raw)
  To: Greg KH; +Cc: jslaby, linux-kernel, gkohli



> -----邮件原件-----
> 发件人: linux-kernel-owner@vger.kernel.org
> [mailto:linux-kernel-owner@vger.kernel.org] 代表 Greg KH
> 发送时间: 2019年1月30日 18:19
> 收件人: Li,Rongqing <lirongqing@baidu.com>
> 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org; gkohli@codeaurora.org
> 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
> 
> On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> > There still is a race window after the commit b027e2298bd588
> > ("tty: fix data race between tty_init_dev and flush of buf"), and we
> > encountered this crash issue if receive_buf call comes before tty
> > initialization completes in n_tty_open and
> > tty->driver_data may be NULL.
> >
> > CPU0                                    CPU1
> > ----                                    ----
> >                                  n_tty_open
> >                                    tty_init_dev
> >                                      tty_ldisc_unlock
> >                                        schedule flush_to_ldisc
> > receive_buf
> >   tty_port_default_receive_buf
> >    tty_ldisc_receive_buf
> >     n_tty_receive_buf_common
> >       __receive_buf
> >        uart_flush_chars
> >         uart_start
> >         /*tty->driver_data is NULL*/
> >                                    tty->ops->open
> >                                    /*init tty->driver_data*/
> >
> > it can be fixed by extending ldisc semaphore lock in tty_init_dev to
> > driver_data initialized completely after tty->ops->open(), but this
> > will lead to put lock on one function and unlock in some other
> > function, and hard to maintain, so fix this race only by checking
> > tty->driver_data when receiving, and return if tty->driver_data
> > is NULL
> >
> > Signed-off-by: Wang Li <wangli39@baidu.com>
> > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > ---
> > V4: add version information
> > V3: not used ldisc semaphore lock, only checking tty->driver_data with
> > NULL
> > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > V1: extend ldisc lock to protect that tty->driver_data is inited
> >
> > drivers/tty/tty_port.c | 3 +++
> >  1 file changed, 3 insertions(+)
> >
> > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index
> > 044c3cbdcfa4..86d0bec38322 100644
> > --- a/drivers/tty/tty_port.c
> > +++ b/drivers/tty/tty_port.c
> > @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port
> *port,
> >  	if (!tty)
> >  		return 0;
> >
> > +	if (!tty->driver_data)
> > +		return 0;
> > +
> 
> How is this working?  What is setting driver_data to NULL to "stop" this race?
> 


if tty->driver_data is NULL and return,  tty_port_default_receive_buf will not step to
uart_start which access tty->driver_data and trigger panic before tty_open, so it can
fix the system panic

> There's no requirement that a tty driver set this field to NULL when it is "done"
> with the tty device, so I think you are just getting lucky in that your specific
> driver happens to be doing this.
> 

when tty_open is running, tty is allocated by kzalloc in tty_init_dev which called
by tty_open_by_driver, tty is inited to 0

> What driver are you testing this against?
> 

8250

Thanks

-RongQing

> thanks,
> 
> greg k-h

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

* Re: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-30 12:48   ` 答复: " Li,Rongqing
@ 2019-01-30 13:16     ` Greg KH
  2019-01-31  2:15       ` 答复: " Li,Rongqing
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2019-01-30 13:16 UTC (permalink / raw)
  To: Li,Rongqing; +Cc: jslaby, linux-kernel, gkohli, linux-serial

On Wed, Jan 30, 2019 at 12:48:42PM +0000, Li,Rongqing wrote:
> 
> 
> > -----邮件原件-----
> > 发件人: linux-kernel-owner@vger.kernel.org
> > [mailto:linux-kernel-owner@vger.kernel.org] 代表 Greg KH
> > 发送时间: 2019年1月30日 18:19
> > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org; gkohli@codeaurora.org
> > 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
> > 
> > On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> > > There still is a race window after the commit b027e2298bd588
> > > ("tty: fix data race between tty_init_dev and flush of buf"), and we
> > > encountered this crash issue if receive_buf call comes before tty
> > > initialization completes in n_tty_open and
> > > tty->driver_data may be NULL.
> > >
> > > CPU0                                    CPU1
> > > ----                                    ----
> > >                                  n_tty_open
> > >                                    tty_init_dev
> > >                                      tty_ldisc_unlock
> > >                                        schedule flush_to_ldisc
> > > receive_buf
> > >   tty_port_default_receive_buf
> > >    tty_ldisc_receive_buf
> > >     n_tty_receive_buf_common
> > >       __receive_buf
> > >        uart_flush_chars
> > >         uart_start
> > >         /*tty->driver_data is NULL*/
> > >                                    tty->ops->open
> > >                                    /*init tty->driver_data*/
> > >
> > > it can be fixed by extending ldisc semaphore lock in tty_init_dev to
> > > driver_data initialized completely after tty->ops->open(), but this
> > > will lead to put lock on one function and unlock in some other
> > > function, and hard to maintain, so fix this race only by checking
> > > tty->driver_data when receiving, and return if tty->driver_data
> > > is NULL
> > >
> > > Signed-off-by: Wang Li <wangli39@baidu.com>
> > > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > > ---
> > > V4: add version information
> > > V3: not used ldisc semaphore lock, only checking tty->driver_data with
> > > NULL
> > > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > > V1: extend ldisc lock to protect that tty->driver_data is inited
> > >
> > > drivers/tty/tty_port.c | 3 +++
> > >  1 file changed, 3 insertions(+)
> > >
> > > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index
> > > 044c3cbdcfa4..86d0bec38322 100644
> > > --- a/drivers/tty/tty_port.c
> > > +++ b/drivers/tty/tty_port.c
> > > @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct tty_port
> > *port,
> > >  	if (!tty)
> > >  		return 0;
> > >
> > > +	if (!tty->driver_data)
> > > +		return 0;
> > > +
> > 
> > How is this working?  What is setting driver_data to NULL to "stop" this race?
> > 
> 
> 
> if tty->driver_data is NULL and return,  tty_port_default_receive_buf will not step to
> uart_start which access tty->driver_data and trigger panic before tty_open, so it can
> fix the system panic
> 
> > There's no requirement that a tty driver set this field to NULL when it is "done"
> > with the tty device, so I think you are just getting lucky in that your specific
> > driver happens to be doing this.
> > 
> 
> when tty_open is running, tty is allocated by kzalloc in tty_init_dev which called
> by tty_open_by_driver, tty is inited to 0
> 
> > What driver are you testing this against?
> > 
> 
> 8250

Ok, as this is specific to the uart core, how about this patch instead:

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 5c01bb6d1c24..b56a6250df3f 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty)
 	struct uart_port *port;
 	unsigned long flags;
 
+	if (!state)
+		return;
+
 	port = uart_port_lock(state, flags);
 	__uart_start(tty);
 	uart_port_unlock(port, flags);

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

* 答复: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-30 13:16     ` Greg KH
@ 2019-01-31  2:15       ` Li,Rongqing
  2019-01-31  6:52         ` Greg KH
  0 siblings, 1 reply; 9+ messages in thread
From: Li,Rongqing @ 2019-01-31  2:15 UTC (permalink / raw)
  To: Greg KH; +Cc: jslaby, linux-kernel, gkohli, linux-serial



> -----邮件原件-----
> 发件人: Greg KH [mailto:gregkh@linuxfoundation.org]
> 发送时间: 2019年1月30日 21:17
> 收件人: Li,Rongqing <lirongqing@baidu.com>
> 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org; gkohli@codeaurora.org;
> linux-serial@vger.kernel.org
> 主题: Re: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
> 
> On Wed, Jan 30, 2019 at 12:48:42PM +0000, Li,Rongqing wrote:
> >
> >
> > > -----邮件原件-----
> > > 发件人: linux-kernel-owner@vger.kernel.org
> > > [mailto:linux-kernel-owner@vger.kernel.org] 代表 Greg KH
> > > 发送时间: 2019年1月30日 18:19
> > > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org;
> > > gkohli@codeaurora.org
> > > 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and
> > > tty_open
> > >
> > > On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> > > > There still is a race window after the commit b027e2298bd588
> > > > ("tty: fix data race between tty_init_dev and flush of buf"), and
> > > > we encountered this crash issue if receive_buf call comes before
> > > > tty initialization completes in n_tty_open and
> > > > tty->driver_data may be NULL.
> > > >
> > > > CPU0                                    CPU1
> > > > ----                                    ----
> > > >                                  n_tty_open
> > > >                                    tty_init_dev
> > > >                                      tty_ldisc_unlock
> > > >                                        schedule flush_to_ldisc
> > > > receive_buf
> > > >   tty_port_default_receive_buf
> > > >    tty_ldisc_receive_buf
> > > >     n_tty_receive_buf_common
> > > >       __receive_buf
> > > >        uart_flush_chars
> > > >         uart_start
> > > >         /*tty->driver_data is NULL*/
> > > >                                    tty->ops->open
> > > >                                    /*init tty->driver_data*/
> > > >
> > > > it can be fixed by extending ldisc semaphore lock in tty_init_dev
> > > > to driver_data initialized completely after tty->ops->open(), but
> > > > this will lead to put lock on one function and unlock in some
> > > > other function, and hard to maintain, so fix this race only by
> > > > checking
> > > > tty->driver_data when receiving, and return if tty->driver_data
> > > > is NULL
> > > >
> > > > Signed-off-by: Wang Li <wangli39@baidu.com>
> > > > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > > > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > > > ---
> > > > V4: add version information
> > > > V3: not used ldisc semaphore lock, only checking tty->driver_data
> > > > with NULL
> > > > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > > > V1: extend ldisc lock to protect that tty->driver_data is inited
> > > >
> > > > drivers/tty/tty_port.c | 3 +++
> > > >  1 file changed, 3 insertions(+)
> > > >
> > > > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index
> > > > 044c3cbdcfa4..86d0bec38322 100644
> > > > --- a/drivers/tty/tty_port.c
> > > > +++ b/drivers/tty/tty_port.c
> > > > @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct
> > > > tty_port
> > > *port,
> > > >  	if (!tty)
> > > >  		return 0;
> > > >
> > > > +	if (!tty->driver_data)
> > > > +		return 0;
> > > > +
> > >
> > > How is this working?  What is setting driver_data to NULL to "stop" this
> race?
> > >
> >
> >
> > if tty->driver_data is NULL and return,  tty_port_default_receive_buf
> > will not step to uart_start which access tty->driver_data and trigger
> > panic before tty_open, so it can fix the system panic
> >
> > > There's no requirement that a tty driver set this field to NULL when it is
> "done"
> > > with the tty device, so I think you are just getting lucky in that
> > > your specific driver happens to be doing this.
> > >
> >
> > when tty_open is running, tty is allocated by kzalloc in tty_init_dev
> > which called by tty_open_by_driver, tty is inited to 0
> >
> > > What driver are you testing this against?
> > >
> >
> > 8250
> 
> Ok, as this is specific to the uart core, how about this patch instead:
> 
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 5c01bb6d1c24..b56a6250df3f 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty)
>  	struct uart_port *port;
>  	unsigned long flags;
> 
> +	if (!state)
> +		return;
> +
>  	port = uart_port_lock(state, flags);
>  	__uart_start(tty);
>  	uart_port_unlock(port, flags);


If move the check into uart_start, i am afraid that it maybe not fully fix this issue,
Since n_tty_receive_buf_common maybe call n_tty_check_throttle/ 
tty_unthrottle_safe which maybe use the tty->driver_data

if tty is not fully opened, I think no gain to step into more function

thanks

-RongQing

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

* Re: 答复: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-31  2:15       ` 答复: " Li,Rongqing
@ 2019-01-31  6:52         ` Greg KH
  2019-01-31  7:40           ` 答复: " Li,Rongqing
  0 siblings, 1 reply; 9+ messages in thread
From: Greg KH @ 2019-01-31  6:52 UTC (permalink / raw)
  To: Li,Rongqing; +Cc: jslaby, linux-kernel, gkohli, linux-serial

On Thu, Jan 31, 2019 at 02:15:35AM +0000, Li,Rongqing wrote:
> 
> 
> > -----邮件原件-----
> > 发件人: Greg KH [mailto:gregkh@linuxfoundation.org]
> > 发送时间: 2019年1月30日 21:17
> > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org; gkohli@codeaurora.org;
> > linux-serial@vger.kernel.org
> > 主题: Re: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
> > 
> > On Wed, Jan 30, 2019 at 12:48:42PM +0000, Li,Rongqing wrote:
> > >
> > >
> > > > -----邮件原件-----
> > > > 发件人: linux-kernel-owner@vger.kernel.org
> > > > [mailto:linux-kernel-owner@vger.kernel.org] 代表 Greg KH
> > > > 发送时间: 2019年1月30日 18:19
> > > > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > > > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org;
> > > > gkohli@codeaurora.org
> > > > 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and
> > > > tty_open
> > > >
> > > > On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> > > > > There still is a race window after the commit b027e2298bd588
> > > > > ("tty: fix data race between tty_init_dev and flush of buf"), and
> > > > > we encountered this crash issue if receive_buf call comes before
> > > > > tty initialization completes in n_tty_open and
> > > > > tty->driver_data may be NULL.
> > > > >
> > > > > CPU0                                    CPU1
> > > > > ----                                    ----
> > > > >                                  n_tty_open
> > > > >                                    tty_init_dev
> > > > >                                      tty_ldisc_unlock
> > > > >                                        schedule flush_to_ldisc
> > > > > receive_buf
> > > > >   tty_port_default_receive_buf
> > > > >    tty_ldisc_receive_buf
> > > > >     n_tty_receive_buf_common
> > > > >       __receive_buf
> > > > >        uart_flush_chars
> > > > >         uart_start
> > > > >         /*tty->driver_data is NULL*/
> > > > >                                    tty->ops->open
> > > > >                                    /*init tty->driver_data*/
> > > > >
> > > > > it can be fixed by extending ldisc semaphore lock in tty_init_dev
> > > > > to driver_data initialized completely after tty->ops->open(), but
> > > > > this will lead to put lock on one function and unlock in some
> > > > > other function, and hard to maintain, so fix this race only by
> > > > > checking
> > > > > tty->driver_data when receiving, and return if tty->driver_data
> > > > > is NULL
> > > > >
> > > > > Signed-off-by: Wang Li <wangli39@baidu.com>
> > > > > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > > > > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > > > > ---
> > > > > V4: add version information
> > > > > V3: not used ldisc semaphore lock, only checking tty->driver_data
> > > > > with NULL
> > > > > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > > > > V1: extend ldisc lock to protect that tty->driver_data is inited
> > > > >
> > > > > drivers/tty/tty_port.c | 3 +++
> > > > >  1 file changed, 3 insertions(+)
> > > > >
> > > > > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index
> > > > > 044c3cbdcfa4..86d0bec38322 100644
> > > > > --- a/drivers/tty/tty_port.c
> > > > > +++ b/drivers/tty/tty_port.c
> > > > > @@ -31,6 +31,9 @@ static int tty_port_default_receive_buf(struct
> > > > > tty_port
> > > > *port,
> > > > >  	if (!tty)
> > > > >  		return 0;
> > > > >
> > > > > +	if (!tty->driver_data)
> > > > > +		return 0;
> > > > > +
> > > >
> > > > How is this working?  What is setting driver_data to NULL to "stop" this
> > race?
> > > >
> > >
> > >
> > > if tty->driver_data is NULL and return,  tty_port_default_receive_buf
> > > will not step to uart_start which access tty->driver_data and trigger
> > > panic before tty_open, so it can fix the system panic
> > >
> > > > There's no requirement that a tty driver set this field to NULL when it is
> > "done"
> > > > with the tty device, so I think you are just getting lucky in that
> > > > your specific driver happens to be doing this.
> > > >
> > >
> > > when tty_open is running, tty is allocated by kzalloc in tty_init_dev
> > > which called by tty_open_by_driver, tty is inited to 0
> > >
> > > > What driver are you testing this against?
> > > >
> > >
> > > 8250
> > 
> > Ok, as this is specific to the uart core, how about this patch instead:
> > 
> > diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> > index 5c01bb6d1c24..b56a6250df3f 100644
> > --- a/drivers/tty/serial/serial_core.c
> > +++ b/drivers/tty/serial/serial_core.c
> > @@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty)
> >  	struct uart_port *port;
> >  	unsigned long flags;
> > 
> > +	if (!state)
> > +		return;
> > +
> >  	port = uart_port_lock(state, flags);
> >  	__uart_start(tty);
> >  	uart_port_unlock(port, flags);
> 
> 
> If move the check into uart_start, i am afraid that it maybe not fully fix this issue,
> Since n_tty_receive_buf_common maybe call n_tty_check_throttle/ 
> tty_unthrottle_safe which maybe use the tty->driver_data
> 
> if tty is not fully opened, I think no gain to step into more function

But as I said, the tty core has no knowledge of the "driver_data",
field.  It does not know if a driver really is even using that field, so
it means nothing to the tty core, so it can not check it.  Your specific
tty driver does happen to use it, so it can check it.

If you also need to check this in unthrottle, how about this patch too?
Does the combination of these two patches solve the problem for your
systems?

thanks,

greg k-h


diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 5c01bb6d1c24..e33d4c181123 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -727,6 +727,9 @@ static void uart_unthrottle(struct tty_struct *tty)
 	upstat_t mask = UPSTAT_SYNC_FIFO;
 	struct uart_port *port;
 
+	if (!state)
+		return;
+
 	port = uart_port_ref(state);
 	if (!port)
 		return;

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

* 答复: 答复: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open
  2019-01-31  6:52         ` Greg KH
@ 2019-01-31  7:40           ` Li,Rongqing
  0 siblings, 0 replies; 9+ messages in thread
From: Li,Rongqing @ 2019-01-31  7:40 UTC (permalink / raw)
  To: Greg KH; +Cc: jslaby, linux-kernel, gkohli, linux-serial



> -----邮件原件-----
> 发件人: Greg KH [mailto:gregkh@linuxfoundation.org]
> 发送时间: 2019年1月31日 14:52
> 收件人: Li,Rongqing <lirongqing@baidu.com>
> 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org; gkohli@codeaurora.org;
> linux-serial@vger.kernel.org
> 主题: Re: 答复: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and
> tty_open
> 
> On Thu, Jan 31, 2019 at 02:15:35AM +0000, Li,Rongqing wrote:
> >
> >
> > > -----邮件原件-----
> > > 发件人: Greg KH [mailto:gregkh@linuxfoundation.org]
> > > 发送时间: 2019年1月30日 21:17
> > > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org;
> > > gkohli@codeaurora.org; linux-serial@vger.kernel.org
> > > 主题: Re: 答复: [PATCH][v4] tty: fix race between flush_to_ldisc and
> > > tty_open
> > >
> > > On Wed, Jan 30, 2019 at 12:48:42PM +0000, Li,Rongqing wrote:
> > > >
> > > >
> > > > > -----邮件原件-----
> > > > > 发件人: linux-kernel-owner@vger.kernel.org
> > > > > [mailto:linux-kernel-owner@vger.kernel.org] 代表 Greg KH
> > > > > 发送时间: 2019年1月30日 18:19
> > > > > 收件人: Li,Rongqing <lirongqing@baidu.com>
> > > > > 抄送: jslaby@suse.com; linux-kernel@vger.kernel.org;
> > > > > gkohli@codeaurora.org
> > > > > 主题: Re: [PATCH][v4] tty: fix race between flush_to_ldisc and
> > > > > tty_open
> > > > >
> > > > > On Fri, Jan 18, 2019 at 05:27:17PM +0800, Li RongQing wrote:
> > > > > > There still is a race window after the commit b027e2298bd588
> > > > > > ("tty: fix data race between tty_init_dev and flush of buf"),
> > > > > > and we encountered this crash issue if receive_buf call comes
> > > > > > before tty initialization completes in n_tty_open and
> > > > > > tty->driver_data may be NULL.
> > > > > >
> > > > > > CPU0                                    CPU1
> > > > > > ----                                    ----
> > > > > >                                  n_tty_open
> > > > > >                                    tty_init_dev
> > > > > >                                      tty_ldisc_unlock
> > > > > >                                        schedule
> flush_to_ldisc
> > > > > > receive_buf
> > > > > >   tty_port_default_receive_buf
> > > > > >    tty_ldisc_receive_buf
> > > > > >     n_tty_receive_buf_common
> > > > > >       __receive_buf
> > > > > >        uart_flush_chars
> > > > > >         uart_start
> > > > > >         /*tty->driver_data is NULL*/
> > > > > >                                    tty->ops->open
> > > > > >                                    /*init tty->driver_data*/
> > > > > >
> > > > > > it can be fixed by extending ldisc semaphore lock in
> > > > > > tty_init_dev to driver_data initialized completely after
> > > > > > tty->ops->open(), but this will lead to put lock on one
> > > > > > function and unlock in some other function, and hard to
> > > > > > maintain, so fix this race only by checking
> > > > > > tty->driver_data when receiving, and return if
> > > > > > tty->tty->driver_data
> > > > > > is NULL
> > > > > >
> > > > > > Signed-off-by: Wang Li <wangli39@baidu.com>
> > > > > > Signed-off-by: Zhang Yu <zhangyu31@baidu.com>
> > > > > > Signed-off-by: Li RongQing <lirongqing@baidu.com>
> > > > > > ---
> > > > > > V4: add version information
> > > > > > V3: not used ldisc semaphore lock, only checking
> > > > > > tty->driver_data with NULL
> > > > > > V2: fix building error by EXPORT_SYMBOL tty_ldisc_unlock
> > > > > > V1: extend ldisc lock to protect that tty->driver_data is
> > > > > > inited
> > > > > >
> > > > > > drivers/tty/tty_port.c | 3 +++
> > > > > >  1 file changed, 3 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
> > > > > > index
> > > > > > 044c3cbdcfa4..86d0bec38322 100644
> > > > > > --- a/drivers/tty/tty_port.c
> > > > > > +++ b/drivers/tty/tty_port.c
> > > > > > @@ -31,6 +31,9 @@ static int
> > > > > > tty_port_default_receive_buf(struct
> > > > > > tty_port
> > > > > *port,
> > > > > >  	if (!tty)
> > > > > >  		return 0;
> > > > > >
> > > > > > +	if (!tty->driver_data)
> > > > > > +		return 0;
> > > > > > +
> > > > >
> > > > > How is this working?  What is setting driver_data to NULL to
> > > > > "stop" this
> > > race?
> > > > >
> > > >
> > > >
> > > > if tty->driver_data is NULL and return,
> > > > tty_port_default_receive_buf will not step to uart_start which
> > > > access tty->driver_data and trigger panic before tty_open, so it
> > > > can fix the system panic
> > > >
> > > > > There's no requirement that a tty driver set this field to NULL
> > > > > when it is
> > > "done"
> > > > > with the tty device, so I think you are just getting lucky in
> > > > > that your specific driver happens to be doing this.
> > > > >
> > > >
> > > > when tty_open is running, tty is allocated by kzalloc in
> > > > tty_init_dev which called by tty_open_by_driver, tty is inited to
> > > > 0
> > > >
> > > > > What driver are you testing this against?
> > > > >
> > > >
> > > > 8250
> > >
> > > Ok, as this is specific to the uart core, how about this patch instead:
> > >
> > > diff --git a/drivers/tty/serial/serial_core.c
> > > b/drivers/tty/serial/serial_core.c
> > > index 5c01bb6d1c24..b56a6250df3f 100644
> > > --- a/drivers/tty/serial/serial_core.c
> > > +++ b/drivers/tty/serial/serial_core.c
> > > @@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty)
> > >  	struct uart_port *port;
> > >  	unsigned long flags;
> > >
> > > +	if (!state)
> > > +		return;
> > > +
> > >  	port = uart_port_lock(state, flags);
> > >  	__uart_start(tty);
> > >  	uart_port_unlock(port, flags);
> >
> >
> > If move the check into uart_start, i am afraid that it maybe not fully
> > fix this issue, Since n_tty_receive_buf_common maybe call
> > n_tty_check_throttle/ tty_unthrottle_safe which maybe use the
> > tty->driver_data
> >
> > if tty is not fully opened, I think no gain to step into more function
> 
> But as I said, the tty core has no knowledge of the "driver_data", field.  It
> does not know if a driver really is even using that field, so it means nothing to
> the tty core, so it can not check it.  Your specific tty driver does happen to use
> it, so it can check it.
> 
> If you also need to check this in unthrottle, how about this patch too?
> Does the combination of these two patches solve the problem for your
> systems?
> 
> thanks,
> 
> greg k-h
> 

Thanks for you explanation, I see now
Your suggestion should work, I will send V5 based on your suggestion

-RongQing

> 
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 5c01bb6d1c24..e33d4c181123 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -727,6 +727,9 @@ static void uart_unthrottle(struct tty_struct *tty)
>  	upstat_t mask = UPSTAT_SYNC_FIFO;
>  	struct uart_port *port;
> 
> +	if (!state)
> +		return;
> +
>  	port = uart_port_ref(state);
>  	if (!port)
>  		return;

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

end of thread, other threads:[~2019-01-31  7:40 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-18  9:27 [PATCH][v4] tty: fix race between flush_to_ldisc and tty_open Li RongQing
2019-01-18 12:50 ` Kohli, Gaurav
2019-01-30  9:29   ` 答复: " Li,Rongqing
2019-01-30 10:19 ` Greg KH
2019-01-30 12:48   ` 答复: " Li,Rongqing
2019-01-30 13:16     ` Greg KH
2019-01-31  2:15       ` 答复: " Li,Rongqing
2019-01-31  6:52         ` Greg KH
2019-01-31  7:40           ` 答复: " Li,Rongqing

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