BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]
[...]
This is reproducible by disconnecting the device while userspace does ioctl in
a loop and doesn't check return values in order to exit the loop, like in the
following test program:
int main(int argc, char *argv[])
{
int fd = -1;
unsigned char name[256];
int ret;
if (argc != 2) {
fprintf(stderr, "usage: %s </dev/hidrawX>\n",
argv[0]);
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("hidraw open");
exit(1);
}
while (1) {
ret = ioctl(fd, HIDIOCGRAWNAME(256), name);
printf("ret: %d name: %s\n", ret, name);
}
close(fd);
exit(0);
}
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
---
Should this be applied to older stable kernels too?
Alan, Jiri,
there is a similar problem when _writing_ to the device, but Alan's
changes in that area are shuffling the code a bit, should I send a patch
[to hidraw_send_report()] on top of Alan's work for that, or a fix for
current mainline [in hidraw_write()] on which Alan should rebase his
work would be better?
The same pattern of unchecked hidraw_table[minor] is also present in
hidraw_get_report but this function is called only after the NULL check
in hidraw_ioctl _for_now_, so that is currently safe.
Thanks,
Antonio Ospite
http://ao2.it
drivers/hid/hidraw.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 47d70c5..9eaf6ae 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -244,6 +244,10 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&minors_lock);
dev = hidraw_table[minor];
+ if (!dev) {
+ ret = -ENODEV;
+ goto out;
+ }
switch (cmd) {
case HIDIOCGRDESCSIZE:
@@ -317,6 +321,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
ret = -ENOTTY;
}
+out:
...Yes, I will be adding (or feel free to do so yourself with another respin) Please send me the fix for current mainline for now, i.e. respin with the write path covered as well. We are struggling to get feedback on Alan's patches from Bluetooth maintainer, so we'd rather have this race fixed in any case. Thanks, -- Jiri Kosina SUSE Labs, Novell Inc. --
On Mon, 4 Oct 2010 15:50:31 +0200 (CEST) Ok, I hope having Alan to resend his changes again rebased on these fixes will bring the discussion on that up again. Regards, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffffa02c66b4>] hidraw_ioctl+0xfc/0x32c [hid]
[...]
This is reproducible by disconnecting the device while userspace does
ioctl in a loop and doesn't check return values in order to exit the
loop, like in the following test program:
int main(int argc, char *argv[])
{
int fd = -1;
unsigned char name[256];
int ret;
if (argc != 2) {
fprintf(stderr, "usage: %s </dev/hidrawX>\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("hidraw open");
exit(1);
}
while (1) {
ret = ioctl(fd, HIDIOCGRAWNAME(256), name);
printf("ret: %d name: %s\n", ret, name);
}
close(fd);
exit(0);
}
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
---
drivers/hid/hidraw.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 47d70c5..9eaf6ae 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -244,6 +244,10 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&minors_lock);
dev = hidraw_table[minor];
+ if (!dev) {
+ ret = -ENODEV;
+ goto out;
+ }
switch (cmd) {
case HIDIOCGRDESCSIZE:
@@ -317,6 +321,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
ret = -ENOTTY;
}
+out:
mutex_unlock(&minors_lock);
return ret;
}
--
1.7.1
--
BUG: unable to handle kernel NULL pointer dereference at 0000000000000028
IP: [<ffffffffa0f0a625>] hidraw_write+0x3b/0x116 [hid]
[...]
This is reproducible by disconnecting the device while userspace writes
to dev node in a loop and doesn't check return values in order to exit
the loop, like in the following test program:
int main(int argc, char *argv[])
{
int fd = -1;
unsigned char report[2] = {0x01, 0x00};
int ret;
if (argc != 2) {
fprintf(stderr, "usage: %s </dev/hidrawX>\n", argv[0]);
exit(1);
}
fd = open(argv[1], O_RDWR);
if (fd < 0) {
perror("hidraw open");
exit(1);
}
while (1) {
ret = write(fd, report, sizeof(report));
printf("ret: %d\n", ret);
}
close(fd);
exit(0);
}
Signed-off-by: Antonio Ospite <ospite@studenti.unina.it>
---
drivers/hid/hidraw.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 9eaf6ae..a3866b5 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -109,6 +109,12 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
int ret = 0;
mutex_lock(&minors_lock);
+
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto out;
+ }
+
dev = hidraw_table[minor]->hid;
if (!dev->hid_output_raw_report) {
--
1.7.1
--
Hi, here are some fixes to hidraw. Patches are against 2.6.36-rc6, but they should be ported to other maintained stable kernels as well. Antonio Ospite (2): HID: hidraw, fix a NULL pointer dereference in hidraw_ioctl HID: hidraw, fix a NULL pointer dereference in hidraw_write drivers/hid/hidraw.c | 11 +++++++++++ 1 files changed, 11 insertions(+), 0 deletions(-) The first one has been sent already but I am resending it with stable@stable@kernel.org in the recipients list. Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing? --
Please read Documentation/stable_kernel_rules.txt which shows you how to properly notify the stable developer to pick up the patch (hint, cc:ing them on the patch is not the correct way, you need to add the mark to the signed-off-by: area.) thanks, greg k-h --
On Tue, 5 Oct 2010 10:42:00 -0700 I see now, thanks Greg. Jiri, are you adding the Cc: mark to these when you apply them? I misunderstood your previous statement about that and thought CCing like in recipients was enough. There is one thing which is not 100% clear to me from the doc (my fault): are patches targeted to -stable to be sent _twice_? Once for linus master branch (this is what "upstream" means in that context, isn't it?) and once for -stable with the commit ID of the former? Is the Cc mark meant just to automate this very process? It seemed to me that items 1 and 2 of the "Procedure" in Documentation/stable_kernel_rules.txt are alternative each other. Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
Either you have to send it twice, or you can ad 'Cc: stable@kernel.org' to the patch meta-information, and it will be picked up for stable automatically once it lands in Linus' tree. I have added the 'Cc:' markings now and applied both patches, thanks. -- Jiri Kosina SUSE Labs, Novell Inc. --
On Wed, 6 Oct 2010 11:31:55 +0200 (CEST) Jiri, these are not in 2.6.36-rc8, any chance we can make it for 2.6.36? Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
Hi Antonio, yes, it is in my queue. I am currently a bit overloaded with other things, so as this is technically not a regression, it wasn't on very top of my list. Stil, will be pushing it to Linus soon. Thanks, -- Jiri Kosina SUSE Labs, Novell Inc. --
Hi, please fix also the window in hidraw_release. thanks, -- js --
On Tue, 05 Oct 2010 23:12:00 +0200 Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
Sure. Look at the code:
if (!hidraw_table[minor])
return -ENODEV;
...
dev = hidraw_table[minor];
if (!--dev->open) {
...
This is done without minors_lock, so you can easily have dev being NULL
even though the first if.
regards,
--
js
--
On Wed, 06 Oct 2010 12:09:07 +0200 Jiri (Slaby) I think it makes more sense if you send a patch about this as it is you who has raised the issue. Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
There is a window between hidraw_table check and its dereference.
In that window, the device may be unplugged and removed form the
system and we will then dereference NULL.
Lock that place properly so that either we get NULL and jump out or we
can work with real pointer.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
drivers/hid/hidraw.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 925992f..6d81be3 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -218,9 +218,13 @@ static int hidraw_release(struct inode * inode, struct file * file)
unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list = file->private_data;
+ int ret;
- if (!hidraw_table[minor])
- return -ENODEV;
+ mutex_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto unlock;
+ }
list_del(&list->node);
dev = hidraw_table[minor];
@@ -233,10 +237,12 @@ static int hidraw_release(struct inode * inode, struct file * file)
kfree(list->hidraw);
}
}
-
+ ret = 0;
+unlock:
+ mutex_unlock(&minors_lock);
kfree(list);
- return 0;
+ return ret;
}
static long hidraw_ioctl(struct file *file, unsigned int cmd,
--
1.7.3.1
--
Actually the kfree cannot be here. The first process to exit would free it and the others will try to free it again. Was it supposed to leak memory in the !hidraw_table[minor] case? regards, -- js suse labs --
There is a window between hidraw_table check and its dereference.
In that window, the device may be unplugged and removed form the
system and we will then dereference NULL.
Lock that place properly so that either we get NULL and jump out or we
can work with real pointer.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
drivers/hid/hidraw.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 925992f..8a4b32d 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -218,9 +218,13 @@ static int hidraw_release(struct inode * inode, struct file * file)
unsigned int minor = iminor(inode);
struct hidraw *dev;
struct hidraw_list *list = file->private_data;
+ int ret;
- if (!hidraw_table[minor])
- return -ENODEV;
+ mutex_lock(&minors_lock);
+ if (!hidraw_table[minor]) {
+ ret = -ENODEV;
+ goto unlock;
+ }
list_del(&list->node);
dev = hidraw_table[minor];
@@ -233,10 +237,12 @@ static int hidraw_release(struct inode * inode, struct file * file)
kfree(list->hidraw);
}
}
-
kfree(list);
+ ret = 0;
+unlock:
+ mutex_unlock(&minors_lock);
- return 0;
+ return ret;
}
static long hidraw_ioctl(struct file *file, unsigned int cmd,
--
1.7.3.1
--
Good catch, applied. Thanks. -- Jiri Kosina SUSE Labs, Novell Inc. --
This doesn't have anything to do with my patch really, and goes way This needs to go back into stable kernels as well, so a patch against mainline will be necessary for that. If you want to make a patch against mine, that's fine with me. If you want me to work it into my patch, I can stick a comment ahead of hidraw_send_report, similar to the one which already exists. Alan. --
On Mon, 04 Oct 2010 09:54:21 -0400 Alan rebasing your patch on top of the hidraw_write() fix is trivial so you do it in your v5, ok? It does not get rebased automatically just because of the mutex_lock() call. If it is OK to you I'd promote my Tested-by to a Signed-off-by in the commit message so to take implicit credit for the fix. But this is ACK. Thanks, Antonio -- Antonio Ospite http://ao2.it PGP public key ID: 0x4553B001 A: Because it messes up the order in which people normally read text. See http://en.wikipedia.org/wiki/Posting_style Q: Why is top-posting such a bad thing?
