diff options
| author | Ludvig Michaelsson <ludvig.michaelsson@yubico.com> | 2023-06-21 13:17:43 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2023-07-01 13:12:41 +0200 |
| commit | 05b47034e2488c2924e5c032e20a1979d012b5b5 (patch) | |
| tree | d256f5380b2ad302c24781fdaea59745f76ee335 | |
| parent | 14fdcf965dc569f2c879fc2d234d95bc2711d6c2 (diff) | |
| download | linux-05b47034e2488c2924e5c032e20a1979d012b5b5.tar.gz linux-05b47034e2488c2924e5c032e20a1979d012b5b5.tar.bz2 linux-05b47034e2488c2924e5c032e20a1979d012b5b5.zip | |
HID: hidraw: fix data race on device refcount
commit 944ee77dc6ec7b0afd8ec70ffc418b238c92f12b upstream.
The hidraw_open() function increments the hidraw device reference
counter. The counter has no dedicated synchronization mechanism,
resulting in a potential data race when concurrently opening a device.
The race is a regression introduced by commit 8590222e4b02 ("HID:
hidraw: Replace hidraw device table mutex with a rwsem"). While
minors_rwsem is intended to protect the hidraw_table itself, by instead
acquiring the lock for writing, the reference counter is also protected.
This is symmetrical to hidraw_release().
Link: https://github.com/systemd/systemd/issues/27947
Fixes: 8590222e4b02 ("HID: hidraw: Replace hidraw device table mutex with a rwsem")
Cc: stable@vger.kernel.org
Signed-off-by: Ludvig Michaelsson <ludvig.michaelsson@yubico.com>
Link: https://lore.kernel.org/r/20230621-hidraw-race-v1-1-a58e6ac69bab@yubico.com
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
| -rw-r--r-- | drivers/hid/hidraw.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 93e62b161501..e63c56a0d57f 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -272,7 +272,12 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; } - down_read(&minors_rwsem); + /* + * Technically not writing to the hidraw_table but a write lock is + * required to protect the device refcount. This is symmetrical to + * hidraw_release(). + */ + down_write(&minors_rwsem); if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { err = -ENODEV; goto out_unlock; @@ -301,7 +306,7 @@ static int hidraw_open(struct inode *inode, struct file *file) spin_unlock_irqrestore(&hidraw_table[minor]->list_lock, flags); file->private_data = list; out_unlock: - up_read(&minors_rwsem); + up_write(&minors_rwsem); out: if (err < 0) kfree(list); |
