Skip to content

Commit

Permalink
fbdev: smscufx: Fix use-after-free in ufx_ops_open()
Browse files Browse the repository at this point in the history
commit 5610bcf upstream.

A race condition may occur if the user physically removes the
USB device while calling open() for this device node.

This is a race condition between the ufx_ops_open() function and
the ufx_usb_disconnect() function, which may eventually result in UAF.

So, add a mutex to the ufx_ops_open() and ufx_usb_disconnect() functions
to avoid race contidion of krefs.

Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
V4bel authored and gregkh committed Oct 21, 2022
1 parent b0625de commit e2e5264
Showing 1 changed file with 13 additions and 1 deletion.
14 changes: 13 additions & 1 deletion drivers/video/fbdev/smscufx.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ static int ufx_submit_urb(struct ufx_data *dev, struct urb * urb, size_t len);
static int ufx_alloc_urb_list(struct ufx_data *dev, int count, size_t size);
static void ufx_free_urb_list(struct ufx_data *dev);

static DEFINE_MUTEX(disconnect_mutex);

/* reads a control register */
static int ufx_reg_read(struct ufx_data *dev, u32 index, u32 *data)
{
Expand Down Expand Up @@ -1071,9 +1073,13 @@ static int ufx_ops_open(struct fb_info *info, int user)
if (user == 0 && !console)
return -EBUSY;

mutex_lock(&disconnect_mutex);

/* If the USB device is gone, we don't accept new opens */
if (dev->virtualized)
if (dev->virtualized) {
mutex_unlock(&disconnect_mutex);
return -ENODEV;
}

dev->fb_count++;

Expand All @@ -1097,6 +1103,8 @@ static int ufx_ops_open(struct fb_info *info, int user)
pr_debug("open /dev/fb%d user=%d fb_info=%p count=%d",
info->node, user, info, dev->fb_count);

mutex_unlock(&disconnect_mutex);

return 0;
}

Expand Down Expand Up @@ -1741,6 +1749,8 @@ static void ufx_usb_disconnect(struct usb_interface *interface)
{
struct ufx_data *dev;

mutex_lock(&disconnect_mutex);

dev = usb_get_intfdata(interface);

pr_debug("USB disconnect starting\n");
Expand All @@ -1761,6 +1771,8 @@ static void ufx_usb_disconnect(struct usb_interface *interface)
kref_put(&dev->kref, ufx_free);

/* consider ufx_data freed */

mutex_unlock(&disconnect_mutex);
}

static struct usb_driver ufx_driver = {
Expand Down

0 comments on commit e2e5264

Please sign in to comment.