All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Fabio M. De Francesco" <fmdefrancesco@gmail.com>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Jiri Slaby <jirislaby@kernel.org>,
	linux-kernel@vger.kernel.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
Cc: syzbot+5f47a8cea6a12b77a876@syzkaller.appspotmail.com,
	Marco Elver <elver@google.com>, Max Filippov <jcmvbkbc@gmail.com>,
	David Sterba <dsterba@suse.com>,
	Bhaskar Chowdhury <unixbhaskar@gmail.com>,
	nick black <dankamongmen@gmail.com>,
	Igor Matheus Andrade Torrente <igormtorrente@gmail.com>
Subject: Re: [PATCH] tty: n_hdlc: make n_hdlc_tty_wakeup() asynchronous
Date: Mon, 06 Dec 2021 20:06:06 +0100	[thread overview]
Message-ID: <3981949.J2oczr2A6u@localhost.localdomain> (raw)
In-Reply-To: <e2f074e2-b19e-da5b-9db9-c0b4142de618@i-love.sakura.ne.jp>

On Monday, December 6, 2021 12:44:38 PM CET Tetsuo Handa wrote:
> syzbot is reporting that an unprivileged user who logged in from tty
> console can crash the system using a reproducer shown below [1], for
> n_hdlc_tty_wakeup() is synchronously calling n_hdlc_send_frames().
> 
> ----------
>   #include <sys/ioctl.h>
>   #include <unistd.h>
> 
>   int main(int argc, char *argv[])
>   {
>     const int disc = 0xd;
> 
>     ioctl(1, TIOCSETD, &disc);
>     while (1) {
>       ioctl(1, TCXONC, 0);
>       write(1, "", 1);
>       ioctl(1, TCXONC, 1); /* Kernel panic - not syncing: scheduling while atomic */
>     }
>   }
> ----------
> 
> Linus suspected that "struct tty_ldisc"->ops->write_wakeup() must not
> sleep, and Jiri confirmed it from include/linux/tty_ldisc.h. Thus, defer
> n_hdlc_send_frames() from n_hdlc_tty_wakeup() to a WQ context like
> net/nfc/nci/uart.c does.
> 
> Link: https://syzkaller.appspot.com/bug?extid=5f47a8cea6a12b77a876 [1]
> Reported-by: syzbot <syzbot+5f47a8cea6a12b77a876@syzkaller.appspotmail.com>
> Analyzed-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>
> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
> Confirmed-by: Jiri Slaby <jirislaby@kernel.org>
> Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> ---
>  drivers/tty/n_hdlc.c | 23 ++++++++++++++++++++++-
>  1 file changed, 22 insertions(+), 1 deletion(-)

This looks to be the correct solution, at least for fixing the SAC bug that 
Syzbot reported.

I say "at least" only because (for the moment) we have lost the synchronization 
that the spinlocks in n_hdlc_tty_ioctl() were meant to assure. 

As we have discussed, now n_hdlc_tty_wakeup() returns immediately after 
calling schedule_work(). Therefore, n_hdlc_tty_ioctl() releases the spinlock 
without it being notified whether or not n_hdlc_send_frames() has had the 
chance to run and complete.[1][2][3]

Only a minor note: since the purpose of the new "write_work"  is to start tty, 
I'd have chosen different name, like "start_work" or "start_write_work" and I'd 
have used "n_hdlc_tty_start_work()" instead of "n_hdlc_tty_write_work()" for the 
callback.

Since I have analyzed and discussed this bug with you and others, I assume that 
I got the necessary knowledge of this subject that allows me to review this patch.

Therefore, despite the due reservations about the loss of alternation and 
synchronization between __stop_tty () and __start_tty (), this work is useful for 
fixing the reported bug, so I'd like to give my tag...

Reviewed-by: Fabio M. De Francesco <fmdefrancesco@gmail.com>

Thanks for your patch,

Fabio M. De Francesco

[1] https://lore.kernel.org/lkml/3017492.JFOoIcAZ2s@localhost.localdomain/
[2] https://lore.kernel.org/lkml/5d055fbd-e94a-fe54-d3e0-982dc455ed1a@i-love.sakura.ne.jp/
[3] https://lore.kernel.org/lkml/2064700.cDd5PexU1D@localhost.localdomain/

> 
> diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c
> index 7e0884ecc74f..23ba1fc99df8 100644
> --- a/drivers/tty/n_hdlc.c
> +++ b/drivers/tty/n_hdlc.c
> @@ -140,6 +140,8 @@ struct n_hdlc {
>  	struct n_hdlc_buf_list	rx_buf_list;
>  	struct n_hdlc_buf_list	tx_free_buf_list;
>  	struct n_hdlc_buf_list	rx_free_buf_list;
> +	struct work_struct	write_work;
> +	struct tty_struct	*tty_for_write_work;
>  };
>  
>  /*
> @@ -154,6 +156,7 @@ static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
>  /* Local functions */
>  
>  static struct n_hdlc *n_hdlc_alloc(void);
> +static void n_hdlc_tty_write_work(struct work_struct *work);
>  
>  /* max frame size for memory allocations */
>  static int maxframe = 4096;
> @@ -210,6 +213,8 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
>  	wake_up_interruptible(&tty->read_wait);
>  	wake_up_interruptible(&tty->write_wait);
>  
> +	cancel_work_sync(&n_hdlc->write_work);
> +
>  	n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
>  	n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
>  	n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
> @@ -241,6 +246,8 @@ static int n_hdlc_tty_open(struct tty_struct *tty)
>  		return -ENFILE;
>  	}
>  
> +	INIT_WORK(&n_hdlc->write_work, n_hdlc_tty_write_work);
> +	n_hdlc->tty_for_write_work = tty;
>  	tty->disc_data = n_hdlc;
>  	tty->receive_room = 65536;
>  
> @@ -334,6 +341,20 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
>  		goto check_again;
>  }	/* end of n_hdlc_send_frames() */
>  
> +/**
> + * n_hdlc_tty_write_work - Asynchronous callback for transmit wakeup
> + * @work: pointer to work_struct
> + *
> + * Called when low level device driver can accept more send data.
> + */
> +static void n_hdlc_tty_write_work(struct work_struct *work)
> +{
> +	struct n_hdlc *n_hdlc = container_of(work, struct n_hdlc, write_work);
> +	struct tty_struct *tty = n_hdlc->tty_for_write_work;
> +
> +	n_hdlc_send_frames(n_hdlc, tty);
> +}	/* end of n_hdlc_tty_write_work() */
> +
>  /**
>   * n_hdlc_tty_wakeup - Callback for transmit wakeup
>   * @tty: pointer to associated tty instance data
> @@ -344,7 +365,7 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
>  {
>  	struct n_hdlc *n_hdlc = tty->disc_data;
>  
> -	n_hdlc_send_frames(n_hdlc, tty);
> +	schedule_work(&n_hdlc->write_work);
>  }	/* end of n_hdlc_tty_wakeup() */
>  
>  /**
> -- 
> 2.18.4
> 
> 
> 





      parent reply	other threads:[~2021-12-06 19:06 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-16 14:49 [PATCH] vt: Fix sleeping functions called from atomic context Fabio M. De Francesco
2021-11-16 14:58 ` Greg Kroah-Hartman
2021-11-16 15:35   ` Fabio M. De Francesco
2021-11-16 16:59     ` Greg Kroah-Hartman
2021-11-16 17:28       ` Fabio M. De Francesco
2021-11-17  8:23       ` Fabio M. De Francesco
2021-11-17  8:54         ` Greg Kroah-Hartman
2021-11-17 10:51           ` Tetsuo Handa
2021-11-18  8:31             ` Fabio M. De Francesco
2021-11-18  9:38               ` Fabio M. De Francesco
2021-11-18 12:14                 ` Tetsuo Handa
2021-11-18 17:01                   ` Fabio M. De Francesco
2021-11-19 14:55                     ` [PATCH] tty: vt: make do_con_write() no-op if IRQ is disabled Tetsuo Handa
2021-12-01 13:40                       ` Tetsuo Handa
2021-12-01 14:20                         ` Greg Kroah-Hartman
2021-12-01 19:05                         ` Linus Torvalds
2021-12-02 15:40                           ` Tetsuo Handa
2021-12-02 18:35                             ` Linus Torvalds
2021-12-03  5:03                               ` Jiri Slaby
2021-12-03 11:00                               ` Fabio M. De Francesco
2021-12-03 12:32                                 ` Tetsuo Handa
2021-12-03 14:51                                   ` Fabio M. De Francesco
2021-11-17 12:38           ` [PATCH] vt: Fix sleeping functions called from atomic context Fabio M. De Francesco
2021-11-17  1:55 ` Tetsuo Handa
2021-11-17  7:02   ` Fabio M. De Francesco
2021-12-06 11:44 ` [PATCH] tty: n_hdlc: make n_hdlc_tty_wakeup() asynchronous Tetsuo Handa
2021-12-06 18:07   ` Linus Torvalds
2021-12-09 13:18     ` Tetsuo Handa
2021-12-15 11:52       ` [PATCH (resend)] " Tetsuo Handa
2021-12-06 19:06   ` Fabio M. De Francesco [this message]

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=3981949.J2oczr2A6u@localhost.localdomain \
    --to=fmdefrancesco@gmail.com \
    --cc=dankamongmen@gmail.com \
    --cc=dsterba@suse.com \
    --cc=elver@google.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=igormtorrente@gmail.com \
    --cc=jcmvbkbc@gmail.com \
    --cc=jirislaby@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=penguin-kernel@i-love.sakura.ne.jp \
    --cc=syzbot+5f47a8cea6a12b77a876@syzkaller.appspotmail.com \
    --cc=torvalds@linux-foundation.org \
    --cc=unixbhaskar@gmail.com \
    /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 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.