From ddf7540e9c3a3d65739daa339c8838fa39cf2758 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 12 Jul 2013 11:01:02 +0200 Subject: HID: logitech-dj: use inlined helpers hid_hw_open/close Use the inlined helpers hid_hw_open/close instead of direct calls to ->ll_driver->open() and ->ll_driver->close(). Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/hid/hid-logitech-dj.c') diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 5207591a..db3192b 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -756,10 +756,10 @@ static int logi_dj_probe(struct hid_device *hdev, } /* This is enabling the polling urb on the IN endpoint */ - retval = hdev->ll_driver->open(hdev); + retval = hid_hw_open(hdev); if (retval < 0) { - dev_err(&hdev->dev, "%s:hdev->ll_driver->open returned " - "error:%d\n", __func__, retval); + dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n", + __func__, retval); goto llopen_failed; } @@ -776,7 +776,7 @@ static int logi_dj_probe(struct hid_device *hdev, return retval; logi_dj_recv_query_paired_devices_failed: - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); llopen_failed: switch_to_dj_mode_fail: @@ -818,7 +818,7 @@ static void logi_dj_remove(struct hid_device *hdev) cancel_work_sync(&djrcv_dev->work); - hdev->ll_driver->close(hdev); + hid_hw_close(hdev); hid_hw_stop(hdev); /* I suppose that at this point the only context that can access -- cgit v1.1 From 27ce405039bfe6d3f4143415c638f56a3df77dca Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Jul 2013 19:56:27 +0200 Subject: HID: fix data access in implement() implement() is setting bytes in LE data stream. In case the data is not aligned to 64bits, it reads past the allocated buffer. It doesn't really change any value there (it's properly bitmasked), but in case that this read past the boundary hits a page boundary, pagefault happens when accessing 64bits of 'x' in implement(), and kernel oopses. This happens much more often when numbered reports are in use, as the initial 8bit skip in the buffer makes the whole process work on values which are not aligned to 64bits. This problem dates back to attempts in 2005 and 2006 to make implement() and extract() as generic as possible, and even back then the problem was realized by Adam Kroperlin, but falsely assumed to be impossible to cause any harm: http://www.mail-archive.com/linux-usb-devel@lists.sourceforge.net/msg47690.html I have made several attempts at fixing it "on the spot" directly in implement(), but the results were horrible; the special casing for processing last 64bit chunk and switching to different math makes it unreadable mess. I therefore took a path to allocate a few bytes more which will never make it into final report, but are there as a cushion for all the 64bit math operations happening in implement() and extract(). All callers of hid_output_report() are converted at the same time to allocate the buffer by newly introduced hid_alloc_report_buf() helper. Bruno noticed that the whole raw_size test can be dropped as well, as hid_alloc_report_buf() makes sure that the buffer is always of a proper size. Reviewed-by: Benjamin Tissoires Acked-by: Gustavo Padovan Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/hid/hid-logitech-dj.c') diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 5207591a..4d79273 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -574,7 +574,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, struct hid_field *field; struct hid_report *report; - unsigned char data[8]; + unsigned char *data; int offset; dbg_hid("%s: %s, type:%d | code:%d | value:%d\n", @@ -590,6 +590,13 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, return -1; } hid_set_field(field, offset, value); + + data = hid_alloc_report_buf(field->report, GFP_KERNEL); + if (!data) { + dev_warn(&dev->dev, "failed to allocate report buf memory\n"); + return -1; + } + hid_output_report(field->report, &data[0]); output_report_enum = &dj_rcv_hiddev->report_enum[HID_OUTPUT_REPORT]; @@ -600,8 +607,9 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT); - return 0; + kfree(data); + return 0; } static int logi_dj_ll_start(struct hid_device *hid) -- cgit v1.1 From ce7373685ec33b94c293d9cfdb46daecb22db261 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Wed, 31 Jul 2013 17:17:58 -0400 Subject: HID: logitech-dj: Fix non-atomic kmalloc in logi_dj_ll_input_event() The ll_driver's .hidinput_input_event() method is called from atomic context [1]. Use GFP_ATOMIC for allocation of the synthesized hid report. BUG: sleeping function called from invalid context at /home/peter/src/kernels/next/mm/slub.c:941 in_atomic(): 1, irqs_disabled(): 1, pid: 2095, name: Xorg INFO: lockdep is turned off. irq event stamp: 1502178 hardirqs last enabled at (1502177): [] _raw_spin_unlock_irqrestore+0x65/0x80 hardirqs last disabled at (1502178): [] common_interrupt+0x6a/0x6f softirqs last enabled at (1501802): [] __do_softirq+0x183/0x420 softirqs last disabled at (1501799): [] irq_exit+0xb5/0xc0 CPU: 3 PID: 2095 Comm: Xorg Not tainted 3.11-next-20130725-xeon+lockdep #20130725 Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012 ffffffff81a662e0 ffff8802adcf9ca8 ffffffff8177c330 0000000000000000 ffff8802a76d2440 ffff8802adcf9cd8 ffffffff810867d0 ffff8802a7ac8000 0000000000000010 00000000ffffffff 00000000000000d0 ffff8802adcf9d38 Call Trace: [] dump_stack+0x4f/0x84 [] __might_sleep+0x140/0x1f0 [] __kmalloc+0x6b/0x2e0 [] ? hid_alloc_report_buf+0x28/0x30 [hid] [] hid_alloc_report_buf+0x28/0x30 [hid] [] logi_dj_ll_input_event+0xb0/0x1b0 [hid_logitech_dj] [] input_handle_event+0x8e/0x540 [] ? input_inject_event+0x5d/0x220 [] input_inject_event+0x1c0/0x220 [] ? input_inject_event+0x44/0x220 [] ? might_fault+0xa0/0xb0 [] ? might_fault+0x57/0xb0 [] evdev_write+0xde/0x160 [] vfs_write+0xc8/0x1f0 [] SyS_write+0x55/0xa0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Peter Hurley Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-dj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hid/hid-logitech-dj.c') diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c index 4d79273..d318222 100644 --- a/drivers/hid/hid-logitech-dj.c +++ b/drivers/hid/hid-logitech-dj.c @@ -591,7 +591,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type, } hid_set_field(field, offset, value); - data = hid_alloc_report_buf(field->report, GFP_KERNEL); + data = hid_alloc_report_buf(field->report, GFP_ATOMIC); if (!data) { dev_warn(&dev->dev, "failed to allocate report buf memory\n"); return -1; -- cgit v1.1