From: Hugo Villeneuve Date: Fri, 10 Apr 2026 15:20:13 +0000 (-0400) Subject: serial: core: prevent division by zero by always returning non-zero baud rate X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=091ea8e5d34e1dca5d8f30127173b949e3f803ce;p=thirdparty%2Fkernel%2Fstable.git serial: core: prevent division by zero by always returning non-zero baud rate If a device has a minimum baud rate > 9600 bauds, and a new termios baud rate of 0 (hang up) is requested, uart_get_baud_rate() will return 0. Most drivers do not check this return value and call uart_update_timeout() with this zero baud rate, which will trigger a "Division by zero in kernel" fault: stty -F /dev/ttySC0 0 Division by zero in kernel. ... Fix by returning the larger of 9600 or min for the B0 case. This now ensures that a non-zero baud rate is returned, and greatly simplifies the code. Signed-off-by: Hugo Villeneuve Link: https://patch.msgid.link/20260410152022.2146488-6-hugo@hugovil.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f89c0dc29516..075a69164aa7 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -462,11 +462,10 @@ EXPORT_SYMBOL(uart_update_timeout); * * Decode the termios structure into a numeric baud rate, taking account of the * magic 38400 baud rate (with spd_* flags), and mapping the %B0 rate to 9600 - * baud. + * baud or min argument, whichever is greater. * * If the new baud rate is invalid, try the @old termios setting. If it's still * invalid, clip to the nearest chip supported rate. - * If that is also invalid 0 is returned. * * The @termios structure is updated to reflect the baud rate we're actually * going to be using. Don't do this for the case where B0 is requested ("hang @@ -481,7 +480,6 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, unsigned int try; unsigned int baud; unsigned int altbaud; - int hung_up = 0; upf_t flags = port->flags & UPF_SPD_MASK; switch (flags) { @@ -515,10 +513,8 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, /* * Special case: B0 rate. */ - if (baud == 0) { - hung_up = 1; - baud = 9600; - } + if (baud == 0) + return max(min, 9600); if (baud >= min && baud <= max) return baud; @@ -530,9 +526,7 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, termios->c_cflag &= ~CBAUD; if (old) { baud = tty_termios_baud_rate(old); - if (!hung_up) - tty_termios_encode_baud_rate(termios, - baud, baud); + tty_termios_encode_baud_rate(termios, baud, baud); old = NULL; continue; } @@ -541,15 +535,16 @@ uart_get_baud_rate(struct uart_port *port, struct ktermios *termios, * As a last resort, if the range cannot be met then clip to * the nearest chip supported rate. */ - if (!hung_up) { - if (baud <= min) - baud = min + 1; - else - baud = max - 1; + if (baud <= min) + baud = min + 1; + else + baud = max - 1; - tty_termios_encode_baud_rate(termios, baud, baud); - } + tty_termios_encode_baud_rate(termios, baud, baud); } + + /* Should never happen */ + WARN_ON(1); return 0; } EXPORT_SYMBOL(uart_get_baud_rate);