ufx_usb_disconnect() marks the device as virtualized and clears
usb_active, but the fbdev entry points that program the controller are
not serialized against it.  ufx_handle_damage(), ufx_dpy_deferred_io()
and ufx_ops_ioctl() all return early while usb_active is clear;
ufx_set_vid_mode() does not, so a mode set or a blank request that
races with the disconnect keeps issuing control transfers through
dev->udev.

The usb_device is released once the disconnect callback returns, while
dev->udev is left pointing at it, so those transfers dereference a
stale pointer and fault in __create_pipe():

  general protection fault, probably for non-canonical address
  0xdffffc0000000006: 0000 [#1] SMP
  KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037]
  RIP: 0010:__create_pipe include/linux/usb.h:2031
  Call Trace:
   ufx_set_vid_mode
   ufx_ops_set_par
   fb_set_var
   fb_set_var_from_user
   store_rotate

Return -ENODEV from ufx_set_vid_mode() when the device is no longer
active, matching the check the other transmit paths already use.  Both
callers, ufx_ops_set_par() and ufx_ops_blank(), handle the error: the
former skips the greenscreen fill and keeps the previous mode, the
latter already ignores the result.

The guard cannot live in ufx_reg_write()/ufx_reg_read() instead, since
probe programs the controller through ufx_config_ddr2(),
ufx_i2c_init(), ufx_setup_modes() and ufx_reg_set_bits() before it sets
usb_active.

Fixes: 3c8a63e22a08 ("Add support for SMSC UFX6000/7000 USB display adapters")
Cc: [email protected]
Co-developed-by: Bin Yu <[email protected]>
Signed-off-by: Bin Yu <[email protected]>
Co-developed-by: Cheng Wen <[email protected]>
Signed-off-by: Cheng Wen <[email protected]>
Signed-off-by: YuanZhe Liu <[email protected]>
---
 drivers/video/fbdev/smscufx.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index 5704f60e1741..f1b640a5d712 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -661,8 +661,12 @@ static int ufx_set_vid_mode(struct ufx_data *dev, struct 
fb_var_screeninfo *var)
        u32 temp;
        u16 h_total, h_active, h_blank_start, h_blank_end, h_sync_start, 
h_sync_end;
        u16 v_total, v_active, v_blank_start, v_blank_end, v_sync_start, 
v_sync_end;
+       int status;
+
+       if (!atomic_read(&dev->usb_active))
+               return -ENODEV;
 
-       int status = ufx_reg_write(dev, 0x8028, 0);
+       status = ufx_reg_write(dev, 0x8028, 0);
        check_warn_return(status, "ufx_set_vid_mode error disabling RGB pad");
 
        status = ufx_reg_write(dev, 0x8024, 0);
-- 
2.34.1

Reply via email to