Skip to content

Commit 422dc0a

Browse files
oneukumgregkh
authored andcommitted
USB: chaoskey: fail open after removal
chaoskey_open() takes the lock only to increase the counter of openings. That means that the mutual exclusion with chaoskey_disconnect() cannot prevent an increase of the counter and chaoskey_open() returning a success. If that race is hit, chaoskey_disconnect() will happily free all resources associated with the device after it has dropped the lock, as it has read the counter as zero. To prevent this race chaoskey_open() has to check the presence of the device under the lock. However, the current per device lock cannot be used, because it is a part of the data structure to be freed. Hence an additional global mutex is needed. The issue is as old as the driver. Signed-off-by: Oliver Neukum <[email protected]> Reported-by: [email protected] Closes: https://syzkaller.appspot.com/bug?extid=422188bce66e76020e55 Fixes: 66e3e59 ("usb: Add driver for Altus Metrum ChaosKey device (v2)") Rule: add Link: https://lore.kernel.org/stable/20241002132201.552578-1-oneukum%40suse.com Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent e0aa961 commit 422dc0a

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

drivers/usb/misc/chaoskey.c

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ static struct usb_class_driver chaoskey_class;
2727
static int chaoskey_rng_read(struct hwrng *rng, void *data,
2828
size_t max, bool wait);
2929

30+
static DEFINE_MUTEX(chaoskey_list_lock);
31+
3032
#define usb_dbg(usb_if, format, arg...) \
3133
dev_dbg(&(usb_if)->dev, format, ## arg)
3234

@@ -230,6 +232,7 @@ static void chaoskey_disconnect(struct usb_interface *interface)
230232
if (dev->hwrng_registered)
231233
hwrng_unregister(&dev->hwrng);
232234

235+
mutex_lock(&chaoskey_list_lock);
233236
usb_deregister_dev(interface, &chaoskey_class);
234237

235238
usb_set_intfdata(interface, NULL);
@@ -244,13 +247,15 @@ static void chaoskey_disconnect(struct usb_interface *interface)
244247
} else
245248
mutex_unlock(&dev->lock);
246249

250+
mutex_unlock(&chaoskey_list_lock);
247251
usb_dbg(interface, "disconnect done");
248252
}
249253

250254
static int chaoskey_open(struct inode *inode, struct file *file)
251255
{
252256
struct chaoskey *dev;
253257
struct usb_interface *interface;
258+
int rv = 0;
254259

255260
/* get the interface from minor number and driver information */
256261
interface = usb_find_interface(&chaoskey_driver, iminor(inode));
@@ -266,18 +271,23 @@ static int chaoskey_open(struct inode *inode, struct file *file)
266271
}
267272

268273
file->private_data = dev;
274+
mutex_lock(&chaoskey_list_lock);
269275
mutex_lock(&dev->lock);
270-
++dev->open;
276+
if (dev->present)
277+
++dev->open;
278+
else
279+
rv = -ENODEV;
271280
mutex_unlock(&dev->lock);
281+
mutex_unlock(&chaoskey_list_lock);
272282

273-
usb_dbg(interface, "open success");
274-
return 0;
283+
return rv;
275284
}
276285

277286
static int chaoskey_release(struct inode *inode, struct file *file)
278287
{
279288
struct chaoskey *dev = file->private_data;
280289
struct usb_interface *interface;
290+
int rv = 0;
281291

282292
if (dev == NULL)
283293
return -ENODEV;
@@ -286,14 +296,15 @@ static int chaoskey_release(struct inode *inode, struct file *file)
286296

287297
usb_dbg(interface, "release");
288298

299+
mutex_lock(&chaoskey_list_lock);
289300
mutex_lock(&dev->lock);
290301

291302
usb_dbg(interface, "open count at release is %d", dev->open);
292303

293304
if (dev->open <= 0) {
294305
usb_dbg(interface, "invalid open count (%d)", dev->open);
295-
mutex_unlock(&dev->lock);
296-
return -ENODEV;
306+
rv = -ENODEV;
307+
goto bail;
297308
}
298309

299310
--dev->open;
@@ -302,13 +313,15 @@ static int chaoskey_release(struct inode *inode, struct file *file)
302313
if (dev->open == 0) {
303314
mutex_unlock(&dev->lock);
304315
chaoskey_free(dev);
305-
} else
306-
mutex_unlock(&dev->lock);
307-
} else
308-
mutex_unlock(&dev->lock);
309-
316+
goto destruction;
317+
}
318+
}
319+
bail:
320+
mutex_unlock(&dev->lock);
321+
destruction:
322+
mutex_lock(&chaoskey_list_lock);
310323
usb_dbg(interface, "release success");
311-
return 0;
324+
return rv;
312325
}
313326

314327
static void chaos_read_callback(struct urb *urb)

0 commit comments

Comments
 (0)