Skip to content

Commit 44feafb

Browse files
name2965gregkh
authored andcommitted
usb: using mutex lock and supporting O_NONBLOCK flag in iowarrior_read()
iowarrior_read() uses the iowarrior dev structure, but does not use any lock on the structure. This can cause various bugs including data-races, so it is more appropriate to use a mutex lock to safely protect the iowarrior dev structure. When using a mutex lock, you should split the branch to prevent blocking when the O_NONBLOCK flag is set. In addition, it is unnecessary to check for NULL on the iowarrior dev structure obtained by reading file->private_data. Therefore, it is better to remove the check. Fixes: 946b960 ("USB: add driver for iowarrior devices.") Signed-off-by: Jeongjun Park <aha310510@gmail.com> Link: https://lore.kernel.org/r/20240919103403.3986-1-aha310510@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 67c6150 commit 44feafb

File tree

1 file changed

+36
-10
lines changed

1 file changed

+36
-10
lines changed

drivers/usb/misc/iowarrior.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -277,28 +277,45 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
277277
struct iowarrior *dev;
278278
int read_idx;
279279
int offset;
280+
int retval;
280281

281282
dev = file->private_data;
282283

284+
if (file->f_flags & O_NONBLOCK) {
285+
retval = mutex_trylock(&dev->mutex);
286+
if (!retval)
287+
return -EAGAIN;
288+
} else {
289+
retval = mutex_lock_interruptible(&dev->mutex);
290+
if (retval)
291+
return -ERESTARTSYS;
292+
}
293+
283294
/* verify that the device wasn't unplugged */
284-
if (!dev || !dev->present)
285-
return -ENODEV;
295+
if (!dev->present) {
296+
retval = -ENODEV;
297+
goto exit;
298+
}
286299

287300
dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n",
288301
dev->minor, count);
289302

290303
/* read count must be packet size (+ time stamp) */
291304
if ((count != dev->report_size)
292-
&& (count != (dev->report_size + 1)))
293-
return -EINVAL;
305+
&& (count != (dev->report_size + 1))) {
306+
retval = -EINVAL;
307+
goto exit;
308+
}
294309

295310
/* repeat until no buffer overrun in callback handler occur */
296311
do {
297312
atomic_set(&dev->overflow_flag, 0);
298313
if ((read_idx = read_index(dev)) == -1) {
299314
/* queue empty */
300-
if (file->f_flags & O_NONBLOCK)
301-
return -EAGAIN;
315+
if (file->f_flags & O_NONBLOCK) {
316+
retval = -EAGAIN;
317+
goto exit;
318+
}
302319
else {
303320
//next line will return when there is either new data, or the device is unplugged
304321
int r = wait_event_interruptible(dev->read_wait,
@@ -309,28 +326,37 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
309326
-1));
310327
if (r) {
311328
//we were interrupted by a signal
312-
return -ERESTART;
329+
retval = -ERESTART;
330+
goto exit;
313331
}
314332
if (!dev->present) {
315333
//The device was unplugged
316-
return -ENODEV;
334+
retval = -ENODEV;
335+
goto exit;
317336
}
318337
if (read_idx == -1) {
319338
// Can this happen ???
320-
return 0;
339+
retval = 0;
340+
goto exit;
321341
}
322342
}
323343
}
324344

325345
offset = read_idx * (dev->report_size + 1);
326346
if (copy_to_user(buffer, dev->read_queue + offset, count)) {
327-
return -EFAULT;
347+
retval = -EFAULT;
348+
goto exit;
328349
}
329350
} while (atomic_read(&dev->overflow_flag));
330351

331352
read_idx = ++read_idx == MAX_INTERRUPT_BUFFER ? 0 : read_idx;
332353
atomic_set(&dev->read_idx, read_idx);
354+
mutex_unlock(&dev->mutex);
333355
return count;
356+
357+
exit:
358+
mutex_unlock(&dev->mutex);
359+
return retval;
334360
}
335361

336362
/*

0 commit comments

Comments
 (0)