From: Hyunwoo Kim <imv4bel@gmail.com>
To: Silvan Jegen <s.jegen@gmail.com>
Cc: erazor_de@users.sourceforge.net, jikos@kernel.org,
benjamin.tissoires@redhat.com, linux-input@vger.kernel.org
Subject: Re: [PATCH] HID: roccat: Fix Use-After-Free in roccat_read
Date: Sun, 26 Jun 2022 07:59:48 -0700 [thread overview]
Message-ID: <20220626145948.GA62550@ubuntu> (raw)
In-Reply-To: <3L3XAQ4FCEIF5.3JIFZ4LHP1KYI@homearch.localdomain>
roccat_report_event() is responsible for registering
roccat-related reports in struct roccat_device.
int roccat_report_event(int minor, u8 const *data)
{
struct roccat_device *device;
struct roccat_reader *reader;
struct roccat_report *report;
uint8_t *new_value;
device = devices[minor];
new_value = kmemdup(data, device->report_size, GFP_ATOMIC);
if (!new_value)
return -ENOMEM;
report = &device->cbuf[device->cbuf_end];
/* passing NULL is safe */
kfree(report->value);
...
The registered report is stored in the struct roccat_device member
"struct roccat_report cbuf[ROCCAT_CBUF_SIZE];".
If more reports are received than the "ROCCAT_CBUF_SIZE" value,
kfree() the saved report from cbuf[0] and allocates a new reprot.
Since there is no lock when this kfree() is performed,
kfree() can be performed even while reading the saved report.
static ssize_t roccat_read(struct file *file, char __user *buffer,
size_t count, loff_t *ppos)
{
struct roccat_reader *reader = file->private_data;
struct roccat_device *device = reader->device;
struct roccat_report *report;
ssize_t retval = 0, len;
DECLARE_WAITQUEUE(wait, current);
mutex_lock(&device->cbuf_lock);
...
report = &device->cbuf[reader->cbuf_start];
/*
* If report is larger than requested amount of data, rest of report
* is lost!
*/
len = device->report_size > count ? count : device->report_size;
if (copy_to_user(buffer, report->value, len)) {
retval = -EFAULT;
goto exit_unlock;
}
...
The roccat_read() function receives the device->cbuf report and
delivers it to the user through copy_to_user().
If the N+ROCCAT_CBUF_SIZE th report is received while copying of
the Nth report->value is in progress, the pointer that copy_to_user()
is working on is kfree()ed and UAF read may occur. (race condition)
Since the device node of this driver does not set separate permissions,
this is not a security vulnerability, but because it is used for
requesting screen display of profile or dpi settings,
a user using the roccat device can apply udev to this device node or
There is a possibility to use it by giving.
Signed-off-by: Hyunwoo Kim <imv4bel@gmail.com>
---
drivers/hid/hid-roccat.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index 26373b82fe81..6da80e442fdd 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -257,6 +257,8 @@ int roccat_report_event(int minor, u8 const *data)
if (!new_value)
return -ENOMEM;
+ mutex_lock(&device->cbuf_lock);
+
report = &device->cbuf[device->cbuf_end];
/* passing NULL is safe */
@@ -276,6 +278,8 @@ int roccat_report_event(int minor, u8 const *data)
reader->cbuf_start = (reader->cbuf_start + 1) % ROCCAT_CBUF_SIZE;
}
+ mutex_unlock(&device->cbuf_lock);
+
wake_up_interruptible(&device->wait);
return 0;
}
--
2.25.1
On Sun, Jun 26, 2022 at 02:54:47PM +0200, Silvan Jegen wrote:
> Usually for resends one would add something like "RESEND" to the patch
> according to
>
> https://www.kernel.org/doc/html/latest/process/submitting-patches.html
Thank you for telling me.
Next time I will attach the RESEND tag.
> Wouldn't we have to protect this assignment with a lock as well? Otherwise
> the copy_to_user may end up with the pointer changing mid-copy which it
> may or may not be able to deal with.
>
> > device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
Because device->cbuf_lock is used throughout the roccat_read() function that calls copy_to_user(),
modifying the value of a "report" member that is already used as copy_to_user() does not cause UAF.
(Modifying report->value or device->cbuf_end does not affect copy_to_user().)
However, it seems cleaner and safer to include the mutex in all references to
report, device, and reader in roccat_report_event().
So it seems better to modify the mutex position as above.
Regards,
Hyunwoo Kim.
next prev parent reply other threads:[~2022-06-26 14:59 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-26 11:13 [PATCH] HID: roccat: Fix Use-After-Free in roccat_read Hyunwoo Kim
2022-06-26 12:54 ` Silvan Jegen
2022-06-26 14:59 ` Hyunwoo Kim [this message]
2022-07-21 10:00 ` Jiri Kosina
2022-07-21 11:01 ` Hyunwoo Kim
2022-09-04 17:27 ` Hyunwoo Kim
2022-09-04 19:16 ` Silvan Jegen
2022-09-04 19:33 ` Hyunwoo Kim
-- strict thread matches above, loose matches on Subject: below --
2022-06-17 18:38 Hyunwoo Kim
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220626145948.GA62550@ubuntu \
--to=imv4bel@gmail.com \
--cc=benjamin.tissoires@redhat.com \
--cc=erazor_de@users.sourceforge.net \
--cc=jikos@kernel.org \
--cc=linux-input@vger.kernel.org \
--cc=s.jegen@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.