Re: KASAN: use-after-free Write in keyspan_close

From: Oliver Neukum
Date: Thu Sep 29 2022 - 07:41:16 EST




On 20.09.22 16:47, Rondreis wrote:
Hello,

When fuzzing the Linux kernel driver v6.0-rc6, the following crash was
triggered.

HEAD commit: 521a547ced6477c54b4b0cc206000406c221b4d6
git tree: upstream

kernel config: https://pastebin.com/raw/hekxU61F
console output: https://pastebin.com/raw/gvADdA0t

Sorry for failing to extract the reproducer. But on other versions of
Linux, I also triggered this crash.

I would appreciate it if you have any idea how to solve this bug.

The crash report is as follows:
==================================================================
BUG: KASAN: use-after-free in keyspan_close+0x240/0x260

kasan_report+0x8a/0x1b0 mm/kasan/report.c:495
keyspan_close+0x240/0x260 drivers/usb/serial/keyspan.c:1589
serial_port_shutdown+0x89/0x110 drivers/usb/serial/usb-serial.c:309
tty_port_shutdown+0x1ec/0x270 drivers/tty/tty_port.c:379
tty_port_hangup+0x103/0x170 drivers/tty/tty_port.c:407
__tty_hangup.part.0+0x65b/0x770 drivers/tty/tty_io.c:660
__tty_hangup drivers/tty/tty_io.c:592 [inline]
tty_vhangup drivers/tty/tty_io.c:707 [inline]
tty_ioctl+0x956/0x1430 drivers/tty/tty_io.c:2718

This is triggered regularly by the reproducer:
r0 = openat$ttynull(0xffffffffffffff9c, &(0x7f00000000c0)='/dev/ttyUSB1', 0x0, 0x0)
[..]
ioctl$TIOCVHANGUP(r0, 0x5437, 0x0)

basically just the ioctl()

Freed by task 9889:

usb_serial_device_remove+0x13f/0x1a0 drivers/usb/serial/bus.c:97
device_remove+0xc8/0x170 drivers/base/dd.c:548
__device_release_driver drivers/base/dd.c:1249 [inline]
device_release_driver_internal+0x1a7/0x360 drivers/base/dd.c:1275
bus_remove_device+0x2e3/0x590 drivers/base/bus.c:529
device_del+0x5d2/0xe80 drivers/base/core.c:3704
usb_serial_disconnect+0x23e/0x3b0 drivers/usb/serial/usb-serial.c:1205
usb_unbind_interface+0x1bd/0x890 drivers/usb/core/driver.c:458
device_remove drivers/base/dd.c:550 [inline]

Regular disconnect

Looking at keyspan_close():

static void keyspan_close(struct usb_serial_port *port)
{
int i;
struct keyspan_port_private *p_priv;

p_priv = usb_get_serial_port_data(port);

p_priv->rts_state = 0;
p_priv->dtr_state = 0;

keyspan_send_setup(port, 2);

It is clearly written so that it must never run after
usb_serial_disconnect(). I must say that I do not clearly
understand how this is achieved.

For testing purposes could you add a check for !serial->disconnected
to the call of close() in serial_port_shutdown()?

Regards
Oliver