Re: [PATCH] tty: Fix WARNING in tty_set_termios
From: shuah <shuah@kernel.org>
Date: 2019-01-31 00:35:24
Also in:
linux-bluetooth, linux-serial, linux-wireless, lkml
On 1/30/19 3:32 AM, Johan Hovold wrote:
On Mon, Jan 28, 2019 at 02:29:22PM -0700, shuah wrote:quoted
On 1/25/19 9:14 PM, Al Viro wrote:quoted
On Fri, Jan 25, 2019 at 04:29:05PM -0700, Shuah Khan wrote:quoted
tty_set_termios() has the following WARMN_ON which can be triggered with a syscall to invoke TIOCGETD __NR_ioctl.You meant TIOCSETD here, and in fact its the call which sets the uart protocol that triggers the warning.
Right. It is a TIOCSETD.
quoted
quoted
quoted
WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); Reference: https://syzkaller.appspot.com/bug?id=2410d22f1d8e5984217329dd0884b01d99e3e48d A simple change would have been to print error message instead of WARN_ON. However, the callers assume that tty_set_termios() always returns 0 and don't check return value. The complete solution is fixing all the callers to check error and bail out to fix the WARN_ON. This fix changes tty_set_termios() to return error and all the callers to check error and bail out. The reproducer is used to reproduce the problem and verify the fix.quoted
--- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c@@ -321,6 +321,8 @@ void hci_uart_set_flow_control(struct hci_uart *hu, bool enable) status = tty_set_termios(tty, &ktermios); BT_DBG("Disabling hardware flow control: %s", status ? "failed" : "success"); + if (status) + return;Can that ldisc end up set on pty master? And does it make any sense there?The initial objective of the patch is to prevent the WARN_ON by making the change to return error instead of WARN_ON. However, without changes to places that don't check the return and keep making progress, there will be secondary problems. Without this change to return here, instead of WARN_ON, it will fail with the following NULL pointer dereference at the next thing hci_uart_set_flow_control() attempts. status = tty->driver->ops->tiocmget(tty); kernel: [10140.649783] BUG: unable to handle kernel NULL pointerThat's a separate issue, which is being fixed: https://lkml.kernel.org/r/20190130095938.GP3691@localhost
Ah good to know.
quoted
quoted
IOW, I don't believe that this patch makes any sense. If anything, we need to prevent unconditional tty_set_termios() on the path that *does* lead to calling it for pty.I don't think preventing unconditional tty_set_termios() is enough to prevent secondary problems such as the one above. For example, the following call chain leads to the WARN_ON that was reported. Even if void hci_uart_set_baudrate() prevents the very first tty_set_termios() call, its caller hci_uart_setup() continues with more tty setup. It goes ahead to call driver setup callback. The driver callback goes on to do more setup calling tty_set_termios(). WARN_ON call path: hci_uart_set_baudrate+0x1cc/0x250 drivers/bluetooth/hci_ldisc.c:378 hci_uart_setup+0xa2/0x490 drivers/bluetooth/hci_ldisc.c:401 hci_dev_do_open+0x6b1/0x1920 net/bluetooth/hci_core.c:1423 Once this WARN_ON is changed to return error, the following happens, when hci_uart_setup() does driver setup callback. kernel: [10140.649836] mrvl_setup+0x17/0x80 [hci_uart] kernel: [10140.649840] hci_uart_setup+0x56/0x160 [hci_uart] kernel: [10140.649850] hci_dev_do_open+0xe6/0x630 [bluetooth] kernel: [10140.649860] hci_power_on+0x52/0x220 [bluetooth] I think continuing to catch the invalid condition in tty_set_termios() and preventing progress by checking return value is a straight forward change to avoid secondary problems, and it might be difficult to catch all the cases where it could fail.I agree with Al that this change doesn't make much sense. The WARN_ON is there to catch any bugs leading to the termios being changed for a master side pty. Those should bugs should be fixed, and not worked around in order to silence a WARN_ON. The problem started with 7721383f4199 ("Bluetooth: hci_uart: Support operational speed during setup") which introduced a new way for how tty_set_termios() could end up being called for a master pty.
Ah. Thanks for the context.
As Al hinted at, setting these ldiscs for a master pty really makes no sense and perhaps that is what we should prevent unless simply making sure they do not call tty_set_termios() is sufficient for the time being.
I will take a look to see if not calling tty_set_termios() is enough.
Finally, note that serdev never operates on a pty, and that this is only an issue for (the three) line disciplines.
Thanks for the detailed message explaining the evolution. Now it makes sense. -- Shuah