* [PATCH] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad()
@ 2026-05-23 15:01 Jinmo Yang
2026-05-23 15:06 ` [PATCH v2] " Jinmo Yang
0 siblings, 1 reply; 11+ messages in thread
From: Jinmo Yang @ 2026-05-23 15:01 UTC (permalink / raw)
To: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires
Cc: linux-input, linux-kernel, Jinmo Yang
wacom_intuos_pad() dereferences wacom->pad_input without a NULL check.
When a Wacom tablet is created via UHID with parameters that route
through wacom_bpt_irq() -> wacom_intuos_irq() -> wacom_intuos_pad(),
but probe did not allocate pad_input, the call to
wacom_report_numbered_buttons() passes a NULL input_dev, causing a
general protection fault in input_get_drvdata().
Add a NULL check for pad_input at the top of wacom_intuos_pad() to
bail out early when the pad input device was not set up.
The bug was found by syzkaller and confirmed on a Pixel 9 Pro
(Android 16, kernel 6.1.124) where it causes an immediate kernel
panic and reboot via /dev/uhid without requiring root privileges:
KP: Oops: Fatal exception: comm:wacom_27qhdt
Reboot reason: 0xbaba - Kernel PANIC
Reproducer (unprivileged):
open("/dev/uhid", O_RDWR)
write(fd, UHID_CREATE2{vendor=0x056a, product=0x0020})
write(fd, UHID_INPUT2{report_id=0x0c, size=10})
Fixes: c7f0522a1ad1 ("HID: wacom: Slim down wacom_intuos_pad processing")
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index da1f0ea85..251ddda3e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -515,7 +515,6 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pad_input;
- int i;
int buttons = 0, nbuttons = features->numbered_buttons;
int keys = 0, nkeys = 0;
int ring1 = 0, ring2 = 0;
@@ -523,6 +522,10 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
bool prox = false;
bool wrench = false, keyboard = false, mute_touch = false, menu = false,
info = false;
+ int i;
+
+ if (!input)
+ return 0;
/* pad packets. Works as a second tool and is always in prox */
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad()
2026-05-23 15:01 [PATCH] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad() Jinmo Yang
@ 2026-05-23 15:06 ` Jinmo Yang
2026-05-29 21:44 ` Dmitry Torokhov
0 siblings, 1 reply; 11+ messages in thread
From: Jinmo Yang @ 2026-05-23 15:06 UTC (permalink / raw)
To: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires
Cc: linux-input, linux-kernel, Jinmo Yang
wacom_intuos_pad() dereferences wacom->pad_input without a NULL check.
When a Wacom tablet is created via UHID with parameters that route
through wacom_bpt_irq() -> wacom_intuos_irq() -> wacom_intuos_pad(),
but probe did not allocate pad_input, the call to
wacom_report_numbered_buttons() passes a NULL input_dev, causing a
general protection fault in input_get_drvdata().
Add a NULL check for pad_input at the top of wacom_intuos_pad() to
bail out early when the pad input device was not set up.
The bug was found by syzkaller on linux-next 7.1.0-rc4 (next-20260522):
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000052
KASAN: null-ptr-deref in range [0x0000000000000290-0x0000000000000297]
RIP: 0010:input_get_drvdata include/linux/input.h:390 [inline]
RIP: 0010:wacom_report_numbered_buttons+0x37/0x210 drivers/hid/wacom_wac.c:4210
Call Trace:
wacom_intuos_pad drivers/hid/wacom_wac.c:643 [inline]
wacom_intuos_irq+0x29a/0x32b0 drivers/hid/wacom_wac.c:1042
wacom_bpt_irq drivers/hid/wacom_wac.c:3275 [inline]
wacom_wac_irq+0x12ed/0xaef0 drivers/hid/wacom_wac.c:3545
wacom_raw_event+0x677/0xa90 drivers/hid/wacom_sys.c:184
__hid_input_report.constprop.0+0x39a/0x4d0 drivers/hid/hid-core.c:2161
uhid_dev_input2 drivers/hid/uhid.c:618 [inline]
uhid_char_write+0xa8a/0xfa0 drivers/hid/uhid.c:776
Also confirmed on a Pixel 9 Pro (Android 16, kernel 6.1.124) where
it causes an immediate kernel panic and reboot via /dev/uhid without
requiring root privileges:
KP: Oops: Fatal exception: comm:wacom_27qhdt
Reboot reason: 0xbaba - Kernel PANIC
Reproducer (unprivileged):
open("/dev/uhid", O_RDWR)
write(fd, UHID_CREATE2{vendor=0x056a, product=0x0020})
write(fd, UHID_INPUT2{report_id=0x0c, size=10})
Fixes: c7f0522a1ad1 ("HID: wacom: Slim down wacom_intuos_pad processing")
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index da1f0ea85..251ddda3e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -515,7 +515,6 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pad_input;
- int i;
int buttons = 0, nbuttons = features->numbered_buttons;
int keys = 0, nkeys = 0;
int ring1 = 0, ring2 = 0;
@@ -523,6 +522,10 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
bool prox = false;
bool wrench = false, keyboard = false, mute_touch = false, menu = false,
info = false;
+ int i;
+
+ if (!input)
+ return 0;
/* pad packets. Works as a second tool and is always in prox */
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad()
2026-05-23 15:06 ` [PATCH v2] " Jinmo Yang
@ 2026-05-29 21:44 ` Dmitry Torokhov
2026-06-10 15:48 ` Jiri Kosina
0 siblings, 1 reply; 11+ messages in thread
From: Dmitry Torokhov @ 2026-05-29 21:44 UTC (permalink / raw)
To: Jinmo Yang
Cc: Ping Cheng, Jason Gerecke, Jiri Kosina, Benjamin Tissoires,
linux-input, linux-kernel
On Sun, May 24, 2026 at 12:06:19AM +0900, Jinmo Yang wrote:
> wacom_intuos_pad() dereferences wacom->pad_input without a NULL check.
> When a Wacom tablet is created via UHID with parameters that route
> through wacom_bpt_irq() -> wacom_intuos_irq() -> wacom_intuos_pad(),
> but probe did not allocate pad_input, the call to
> wacom_report_numbered_buttons() passes a NULL input_dev, causing a
> general protection fault in input_get_drvdata().
>
> Add a NULL check for pad_input at the top of wacom_intuos_pad() to
> bail out early when the pad input device was not set up.
>
> The bug was found by syzkaller on linux-next 7.1.0-rc4 (next-20260522):
>
> Oops: general protection fault, probably for non-canonical address 0xdffffc0000000052
> KASAN: null-ptr-deref in range [0x0000000000000290-0x0000000000000297]
> RIP: 0010:input_get_drvdata include/linux/input.h:390 [inline]
> RIP: 0010:wacom_report_numbered_buttons+0x37/0x210 drivers/hid/wacom_wac.c:4210
> Call Trace:
> wacom_intuos_pad drivers/hid/wacom_wac.c:643 [inline]
> wacom_intuos_irq+0x29a/0x32b0 drivers/hid/wacom_wac.c:1042
> wacom_bpt_irq drivers/hid/wacom_wac.c:3275 [inline]
> wacom_wac_irq+0x12ed/0xaef0 drivers/hid/wacom_wac.c:3545
> wacom_raw_event+0x677/0xa90 drivers/hid/wacom_sys.c:184
> __hid_input_report.constprop.0+0x39a/0x4d0 drivers/hid/hid-core.c:2161
> uhid_dev_input2 drivers/hid/uhid.c:618 [inline]
> uhid_char_write+0xa8a/0xfa0 drivers/hid/uhid.c:776
>
> Also confirmed on a Pixel 9 Pro (Android 16, kernel 6.1.124) where
> it causes an immediate kernel panic and reboot via /dev/uhid without
> requiring root privileges:
>
> KP: Oops: Fatal exception: comm:wacom_27qhdt
> Reboot reason: 0xbaba - Kernel PANIC
>
> Reproducer (unprivileged):
> open("/dev/uhid", O_RDWR)
> write(fd, UHID_CREATE2{vendor=0x056a, product=0x0020})
> write(fd, UHID_INPUT2{report_id=0x0c, size=10})
>
> Fixes: c7f0522a1ad1 ("HID: wacom: Slim down wacom_intuos_pad processing")
> Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
> ---
> drivers/hid/wacom_wac.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
> index da1f0ea85..251ddda3e 100644
> --- a/drivers/hid/wacom_wac.c
> +++ b/drivers/hid/wacom_wac.c
> @@ -515,7 +515,6 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
> struct wacom_features *features = &wacom->features;
> unsigned char *data = wacom->data;
> struct input_dev *input = wacom->pad_input;
> - int i;
> int buttons = 0, nbuttons = features->numbered_buttons;
> int keys = 0, nkeys = 0;
> int ring1 = 0, ring2 = 0;
> @@ -523,6 +522,10 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
> bool prox = false;
> bool wrench = false, keyboard = false, mute_touch = false, menu = false,
> info = false;
> + int i;
> +
> + if (!input)
> + return 0;
>
> /* pad packets. Works as a second tool and is always in prox */
> if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
I think there are many more places in the driver where it used
wacom->pad_input without verifying that it exists.
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad()
2026-05-29 21:44 ` Dmitry Torokhov
@ 2026-06-10 15:48 ` Jiri Kosina
2026-09-26 18:37 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
0 siblings, 2 replies; 11+ messages in thread
From: Jiri Kosina @ 2026-06-10 15:48 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Jinmo Yang, Ping Cheng, Jason Gerecke, Benjamin Tissoires,
linux-input, linux-kernel
On Fri, 29 May 2026, Dmitry Torokhov wrote:
> I think there are many more places in the driver where it used
> wacom->pad_input without verifying that it exists.
Absolutely correct observation, thanks :)
Jinmo, are you planning to submit extended version of the patch, please?
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad()
2026-06-10 15:48 ` Jiri Kosina
@ 2026-09-26 18:37 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
1 sibling, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-26 18:37 UTC (permalink / raw)
To: Jiri Kosina, Dmitry Torokhov
Cc: Jinmo Yang, Ping Cheng, Jason Gerecke, Benjamin Tissoires,
linux-input, linux-kernel
On Wed, 10 Jun 2026, Jiri Kosina wrote:
> Jinmo, are you planning to submit extended version of the patch, please?
Yes - sorry for the long delay. Dmitry's observation turned out to be
broader than pad_input, so I audited the whole driver before replying.
The check already exists in three places, just not everywhere:
wacom_wac.c:1807/1815 wacom_tpc_irq pen, touch
wacom_wac.c:1210 wacom_intuos_bt_process_data pad
wacom_wac.c:2192 wacom_wac_pad_event (HID_GENERIC)
so the inconsistency is inside the legacy dispatch. The clearest case is
two adjacent lines in wacom_intuos_bt_process_data(), one checked and
one not:
input_sync(wacom->pen_input); /* :1209 */
if (wacom->pad_input) /* :1210 */
input_sync(wacom->pad_input);
The pointers can be NULL on a fully successful probe: the handler is
chosen by features.type from the id table (wacom_sys.c:2945), while the
input devices are allocated from what the descriptor declares. When
wacom_setup_{pen,touch,pad}_input_capabilities() returns -ENODEV,
wacom_setup_inputs() frees that input, NULLs the pointer and still
returns 0 (wacom_sys.c:2172-2196) - "no pen in use on this interface".
wacom_wac_irq() then still routes reports to a handler that dereferences
it. No error injection is needed; a descriptor declaring only touch
usages is enough.
15 locations, each reproduced as a KASAN NULL-pointer dereference on
linux-next 20260925, x86_64, from one /dev/uhid device plus a single
UHID_INPUT2 write:
wacom_wac.c:137 wacom_penpartner_irq pen_input
wacom_wac.c:227 wacom_pl_irq pen_input
wacom_wac.c:244 wacom_ptu_irq pen_input
wacom_wac.c:303 wacom_dtus_irq pad_input
wacom_wac.c:326 wacom_dtus_irq pen_input
wacom_wac.c:391 wacom_graphire_irq pen_input
wacom_wac.c:444 wacom_graphire_irq pad_input
wacom_wac.c:594 wacom_intuos_pad pad_input
wacom_wac.c:1209 wacom_intuos_bt_process_data pen_input
wacom_wac.c:1232 wacom_intuos_bt_irq pen_input (dev_warn)
wacom_wac.c:3100 wacom_bpt_touch touch_input
wacom_wac.c:3117 wacom_bpt_touch pad_input
wacom_wac.c:3130 wacom_bpt3_touch_msg touch_input
wacom_wac.c:3178 wacom_bpt3_button_msg pad_input
wacom_wac.c:4229 wacom_report_numbered_buttons pad_input
Jason, your review of my earlier series ("HID: wacom: add report length
validation in irq handlers", 17 May) asked for the length checks to move
into the sub-functions with len passed in, plus WACOM_PKGLEN_* names.
Eight handlers already take len and eight do not, and six of those eight
are also on the list above - so I would like to fold the two together
and do one edit per handler: take len, use a named constant, and check
the input device in the same place.
On the shape of the fix: I plan to put a check where each pointer is
taken, as wacom_tpc_irq() already does. A per-features.type table of
required inputs would be one place instead of ~15, but a handler's needs
vary by report id - wacom_graphire_irq() takes pen_input on one branch
and pad_input on another - so the mask would have to demand every input
the handler might touch, and would then reject reports that work today
on a pen-only interface, which the "no pen in use on this interface"
case says is legitimate. Say the word if you would rather have that
anyway.
I will post it as a series split by device family shortly, with the
shared helpers (wacom_report_numbered_buttons(),
wacom_wac_finger_count_touches()) guarded once each, since several
handlers converge on them.
Thanks,
Jinmo
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 0/5] HID: wacom: check input devices in the report handlers
2026-06-10 15:48 ` Jiri Kosina
2026-09-26 18:37 ` Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 1/5] HID: wacom: check the input device in the shared report helpers Jinmo Yang
` (4 more replies)
1 sibling, 5 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang
This is the extended version Jiri asked for in
<579o8so3-09o3-o312-4sq0-0qp6n672q46p@xreary.bet>, after Dmitry's
observation that "there are many more places in the driver where it used
wacom->pad_input without verifying that it exists".
The audit turned out broader than pad_input. Of the 155 lines in
wacom_wac.c that reference pen_input, touch_input or pad_input, three
places already test the pointer first:
wacom_wac.c:1807/1815 wacom_tpc_irq pen, touch
wacom_wac.c:1210 wacom_intuos_bt_process_data pad
wacom_wac.c:2192 wacom_wac_pad_event (HID_GENERIC)
so the inconsistency is inside the legacy dispatch rather than between it
and the HID_GENERIC path. The clearest illustration is two adjacent lines
in wacom_intuos_bt_process_data(), one checked and one not:
input_sync(wacom->pen_input); /* :1209 */
if (wacom->pad_input) /* :1210 */
input_sync(wacom->pad_input);
Why the pointers can be NULL on a *successful* probe
====================================================
For a non-HID_GENERIC device the report handler is selected by
features.type, which comes from the id table (wacom_sys.c:2945), while the
three input devices are allocated from what the report descriptor declares.
When wacom_setup_{pen,touch,pad}_input_capabilities() returns -ENODEV,
wacom_setup_inputs() frees that input device, sets the pointer to NULL and
still returns 0 (wacom_sys.c:2172-2196) - the "no pen in use on this
interface" case. wacom_wac_irq() then still routes reports to a handler
that dereferences it.
No error injection is needed. A descriptor declaring only touch usages
leaves pen_input and pad_input NULL; one declaring only pen usages leaves
touch_input and pad_input NULL.
What the series fixes
=====================
15 locations, each reproduced as a KASAN NULL-pointer dereference from one
/dev/uhid device plus a single UHID_INPUT2 write, with no privilege beyond
access to /dev/uhid:
patch file:line function pointer
1 wacom_wac.c:4229 wacom_report_numbered_buttons pad
2 wacom_wac.c:137 wacom_penpartner_irq pen
2 wacom_wac.c:227 wacom_pl_irq pen
2 wacom_wac.c:244 wacom_ptu_irq pen
2 wacom_wac.c:303 wacom_dtus_irq pad
2 wacom_wac.c:326 wacom_dtus_irq pen
2 wacom_wac.c:391 wacom_graphire_irq pen
2 wacom_wac.c:444 wacom_graphire_irq pad
3 wacom_wac.c:594 wacom_intuos_pad pad
4 wacom_wac.c:1209 wacom_intuos_bt_process_data pen
4 wacom_wac.c:1232 wacom_intuos_bt_irq pen
(both covered by one check at wacom_intuos_bt_irq() entry)
5 wacom_wac.c:3100 wacom_bpt_touch touch
5 wacom_wac.c:3117 wacom_bpt_touch pad
5 wacom_wac.c:3130 wacom_bpt3_touch_msg touch
5 wacom_wac.c:3178 wacom_bpt3_button_msg pad
Patch 1 also guards wacom_wac_finger_count_touches(), and patch 2 also
guards wacom_dtu_irq(); both are reachable with a NULL pointer but their
only dereference is in a dev_dbg(), so they do not fault with
CONFIG_DYNAMIC_DEBUG=n.
Dereferences that are reached only through dev_dbg() are otherwise out of
scope here. A few remain, on unknown-report paths in wacom_dtus_irq(),
wacom_graphire_irq() and wacom_intuos_irq(); guarding those needs a
separate look at what a pen-only or pad-only interface should still
report, so I have left them for a follow-up rather than mixing them in.
Approach
========
A check where each pointer is taken, which is what wacom_tpc_irq() already
does. Where a handler serves both pen and pad reports - wacom_dtus_irq(),
wacom_graphire_irq(), wacom_bpt_touch() - the checks are per branch rather
than at function entry, so an interface that has a pad but no pen keeps
delivering pad events.
A per-features.type table of required input devices would be one place
instead of 15, but a handler's needs vary by report id, so such a mask
would have to demand every input the handler might touch and would then
reject reports that work today on a partial interface. I am happy to build
that instead if you would rather have it.
Testing
=======
linux-next 20260925 (7.3.0-rc4-next-20260925-gf5f84daefcd9), x86_64,
CONFIG_KASAN_GENERIC=y, CONFIG_DYNAMIC_DEBUG=n. 27 uhid reproducer cases
covering the sites above plus the dev_dbg-only ones, one fresh VM per case
because the oops leaves driver_input_lock held:
before after
KASAN faults 17 0
probe failures 0 0
hidraw nodes created 26 26
input devices registered 25 25
and the set of input devices registered is identical in all 27 cases, so
the checks remove the faults without changing what a device exposes. The
one case that creates no device is a product whose table entry sets
.check_for_hid_type, which uhid cannot satisfy; it behaves the same before
and after.
Each patch builds standalone with no new warnings, and checkpatch --strict
reports 0 errors, 0 warnings and 0 checks for all five.
Not in this series
==================
Jason, your review of "HID: wacom: add report length validation in irq
handlers" (17 May) asked for the length checks to move into the
sub-functions with len passed in, plus WACOM_PKGLEN_* names. Eight
handlers already take len and eight do not, and six of those eight are
also on the list above, so that work overlaps this series closely. I have
kept it out here because I have only reproduced and verified the
input-device faults; I would rather send the length revision once it has
the same evidence behind it, on top of this series.
Jinmo Yang (5):
HID: wacom: check the input device in the shared report helpers
HID: wacom: check the input devices in the legacy irq handlers
HID: wacom: check the input device in wacom_intuos_pad()
HID: wacom: check the input device in wacom_intuos_bt_irq()
HID: wacom: check the input devices in the Bamboo handlers
drivers/hid/wacom_wac.c | 97 +++++++++++++++++++++++++++++------------
1 file changed, 70 insertions(+), 27 deletions(-)
base-commit: f5f84daefcd92d7a630066635ecea1433ed5eac7
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/5] HID: wacom: check the input device in the shared report helpers
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 2/5] HID: wacom: check the input devices in the legacy irq handlers Jinmo Yang
` (3 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang, stable
wacom_report_numbered_buttons() and wacom_wac_finger_count_touches() are
reached from several report handlers and use the input device they are
given without checking it.
Both can see a NULL input device on a fully successful probe. The report
handler is selected by features.type from the id table, while the three
input devices are allocated from what the report descriptor declares.
When wacom_setup_{pen,touch,pad}_input_capabilities() returns -ENODEV,
wacom_setup_inputs() frees that input device, sets the pointer to NULL
and still returns 0 - the "no pen in use on this interface" case.
wacom_wac_irq() then still routes reports to a handler that passes the
NULL pointer down.
Reproduced on linux-next 20260925 (x86_64, KASAN) from one /dev/uhid
device plus a single UHID_INPUT2 write:
BUG: KASAN: null-ptr-deref in range [0x290-0x297]
RIP: 0010:wacom_report_numbered_buttons+0x37/0x210
wacom_intuos_irq+0x29e/0x3300
wacom_wac_irq+0x1b59/0xb3f0
wacom_raw_event+0x68f/0xb60
__hid_input_report+0x398/0x4d0
uhid_char_write+0xa99/0xfc0
Check the pointer in both helpers, following the convention the driver
already uses in wacom_tpc_irq() and wacom_wac_pad_event().
Fixes: 10059cdc0ad0 ("Input: wacom - split out the pad device for Intuos/Cintiq")
Fixes: 2a6cdbdd4cc0 ("HID: wacom: Introduce new 'touch_input' device")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index c4cd87b781c4..177a1e09fd05 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1263,6 +1263,9 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom)
int count = 0;
int i;
+ if (!input)
+ return 0;
+
if (!touch_max)
return 0;
@@ -4226,9 +4229,14 @@ static void wacom_update_led(struct wacom *wacom, int button_count, int mask,
static void wacom_report_numbered_buttons(struct input_dev *input_dev,
int button_count, int mask)
{
- struct wacom *wacom = input_get_drvdata(input_dev);
+ struct wacom *wacom;
int i;
+ if (!input_dev)
+ return;
+
+ wacom = input_get_drvdata(input_dev);
+
for (i = 0; i < wacom->led.count; i++)
wacom_update_led(wacom, button_count, mask, i);
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 2/5] HID: wacom: check the input devices in the legacy irq handlers
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
2026-09-27 4:11 ` [PATCH 1/5] HID: wacom: check the input device in the shared report helpers Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 3/5] HID: wacom: check the input device in wacom_intuos_pad() Jinmo Yang
` (2 subsequent siblings)
4 siblings, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang, stable
wacom_penpartner_irq(), wacom_pl_irq(), wacom_ptu_irq(),
wacom_dtu_irq(), wacom_dtus_irq() and wacom_graphire_irq() take
pen_input, and the latter two also take pad_input, without checking
either.
As described in "HID: wacom: check the input device in the shared
report helpers", a partial interface leaves one or two of the three
input devices NULL on a fully successful probe, and wacom_wac_irq()
still dispatches to these handlers. Seven locations fault, each
reproduced on linux-next 20260925 (x86_64, KASAN) from one /dev/uhid
device plus a single UHID_INPUT2 write:
wacom_wac.c:137 wacom_penpartner_irq pen_input
wacom_wac.c:227 wacom_pl_irq pen_input
wacom_wac.c:244 wacom_ptu_irq pen_input
wacom_wac.c:303 wacom_dtus_irq pad_input
wacom_wac.c:326 wacom_dtus_irq pen_input
wacom_wac.c:391 wacom_graphire_irq pen_input
wacom_wac.c:444 wacom_graphire_irq pad_input
for example, with vendor 0x056a product 0x0030 (PL) and report id 2:
BUG: KASAN: null-ptr-deref in input_event+0x44/0xb0
Read of size 8 at addr 0000000000000028
wacom_wac_irq+0x2b27/0xb3f0
wacom_raw_event+0x68f/0xb60
__hid_input_report+0x398/0x4d0
uhid_char_write+0xa99/0xfc0
Check each pointer where it is taken. wacom_dtus_irq() and
wacom_graphire_irq() serve both pen and pad reports, so the checks are
placed per branch rather than at function entry: an interface that has
a pad but no pen must keep delivering pad events.
wacom_dtu_irq() gets a check too. Its only dereference is in a
dev_dbg(), so it does not fault with CONFIG_DYNAMIC_DEBUG=n, but it is
unconditional in the source.
Fixes: 2a6cdbdd4cc0 ("HID: wacom: Introduce new 'touch_input' device")
Fixes: 862cf5535c0c ("HID: wacom: Introduce a new WACOM_DEVICETYPE_PAD device_type")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 177a1e09fd05..794c2865064a 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -128,6 +128,9 @@ static int wacom_penpartner_irq(struct wacom_wac *wacom)
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
+ if (!input)
+ return 0;
+
switch (data[0]) {
case 1:
if (data[5] & 0x80) {
@@ -174,6 +177,9 @@ static int wacom_pl_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->pen_input;
int prox, pressure;
+ if (!input)
+ return 0;
+
if (data[0] != WACOM_REPORT_PENABLED) {
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
@@ -233,6 +239,9 @@ static int wacom_ptu_irq(struct wacom_wac *wacom)
unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
+ if (!input)
+ return 0;
+
if (data[0] != WACOM_REPORT_PENABLED) {
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
@@ -263,6 +272,9 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->pen_input;
int prox = data[1] & 0x20;
+ if (!input)
+ return 0;
+
dev_dbg(input->dev.parent,
"%s: received report #%d", __func__, data[0]);
@@ -299,6 +311,8 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
return 0;
} else if (data[0] == WACOM_REPORT_DTUSPAD) {
input = wacom->pad_input;
+ if (!input)
+ return 0;
input_report_key(input, BTN_0, (data[1] & 0x01));
input_report_key(input, BTN_1, (data[1] & 0x02));
input_report_key(input, BTN_2, (data[1] & 0x04));
@@ -307,6 +321,9 @@ static int wacom_dtus_irq(struct wacom_wac *wacom)
data[1] & 0x0f ? PAD_DEVICE_ID : 0);
return 1;
} else {
+ if (!input)
+ return 0;
+
prox = data[1] & 0x80;
if (prox) {
switch ((data[1] >> 3) & 3) {
@@ -363,7 +380,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
}
prox = data[1] & 0x80;
- if (prox || wacom->id[0]) {
+ if (input && (prox || wacom->id[0])) {
if (prox) {
switch ((data[1] >> 5) & 3) {
@@ -438,7 +455,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
switch (features->type) {
case WACOM_G4:
prox = data[7] & 0xf8;
- if (prox || wacom->id[1]) {
+ if (pad_input && (prox || wacom->id[1])) {
wacom->id[1] = PAD_DEVICE_ID;
input_report_key(pad_input, BTN_BACK, (data[7] & 0x40));
input_report_key(pad_input, BTN_FORWARD, (data[7] & 0x80));
@@ -453,7 +470,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
case WACOM_MO:
prox = (data[7] & 0xf8) || data[8];
- if (prox || wacom->id[1]) {
+ if (pad_input && (prox || wacom->id[1])) {
wacom->id[1] = PAD_DEVICE_ID;
input_report_key(pad_input, BTN_BACK, (data[7] & 0x08));
input_report_key(pad_input, BTN_LEFT, (data[7] & 0x20));
@@ -468,7 +485,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom)
break;
case GRAPHIRE_BT:
prox = data[7] & 0x03;
- if (prox || wacom->id[1]) {
+ if (pad_input && (prox || wacom->id[1])) {
wacom->id[1] = PAD_DEVICE_ID;
input_report_key(pad_input, BTN_0, (data[7] & 0x02));
input_report_key(pad_input, BTN_1, (data[7] & 0x01));
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 3/5] HID: wacom: check the input device in wacom_intuos_pad()
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
2026-09-27 4:11 ` [PATCH 1/5] HID: wacom: check the input device in the shared report helpers Jinmo Yang
2026-09-27 4:11 ` [PATCH 2/5] HID: wacom: check the input devices in the legacy irq handlers Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 4/5] HID: wacom: check the input device in wacom_intuos_bt_irq() Jinmo Yang
2026-09-27 4:11 ` [PATCH 5/5] HID: wacom: check the input devices in the Bamboo handlers Jinmo Yang
4 siblings, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang, stable
wacom_intuos_pad() takes wacom->pad_input without checking it. An
interface that declares no pad leaves the pointer NULL on a fully
successful probe, and wacom_intuos_irq() still calls this function for
pad report ids.
Reproduced on linux-next 20260925 (x86_64, KASAN) with vendor 0x056a
product 0x032A and report id 12:
BUG: KASAN: null-ptr-deref in input_event+0x44/0xb0
Read of size 8 at addr 0000000000000028
wacom_intuos_irq+0x1b46/0x3300
wacom_wac_irq+0x1b59/0xb3f0
wacom_raw_event+0x68f/0xb60
__hid_input_report+0x398/0x4d0
uhid_char_write+0xa99/0xfc0
The function only ever serves pad reports, so the check goes at entry.
Fixes: 10059cdc0ad0 ("Input: wacom - split out the pad device for Intuos/Cintiq")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 794c2865064a..48a58a6672c2 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -553,6 +553,9 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
bool wrench = false, keyboard = false, mute_touch = false, menu = false,
info = false;
+ if (!input)
+ return 0;
+
/* pad packets. Works as a second tool and is always in prox */
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
data[0] == WACOM_REPORT_CINTIQPAD))
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/5] HID: wacom: check the input device in wacom_intuos_bt_irq()
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
` (2 preceding siblings ...)
2026-09-27 4:11 ` [PATCH 3/5] HID: wacom: check the input device in wacom_intuos_pad() Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 5/5] HID: wacom: check the input devices in the Bamboo handlers Jinmo Yang
4 siblings, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang, stable
wacom_intuos_bt_irq() reaches for wacom->pen_input three ways without
checking it: two dev_warn() calls on the short-report paths, a dev_dbg()
on the unknown-report path, and input_sync(wacom->pen_input) inside
wacom_intuos_bt_process_data(), which is called only from here. That last
one is the odd one out, because the pad_input sync two lines below it is
guarded:
input_sync(wacom->pen_input);
if (wacom->pad_input)
input_sync(wacom->pad_input);
An interface that declares no pen leaves the pointer NULL on a fully
successful probe, as described in "HID: wacom: check the input device in
the shared report helpers".
Reproduced on linux-next 20260925 (x86_64, KASAN) with bus BUS_BLUETOOTH,
vendor 0x056a product 0x00BD (INTUOS4WL):
BUG: KASAN: null-ptr-deref in range [0x258-0x25f]
RIP: 0010:wacom_wac_irq.cold+0x8f/0x16a
wacom_raw_event+0x68f/0xb60
__hid_input_report+0x398/0x4d0
uhid_char_write+0xa99/0xfc0
One check at function entry covers all of them. It is safe to bail out
there: this handler only runs for INTUOS4WL, and
wacom_setup_device_quirks() only adds WACOM_DEVICETYPE_PAD for that
range of types when WACOM_DEVICETYPE_PEN is already set, so a NULL
pen_input implies a NULL pad_input and there is nothing the function can
report. Every path that reaches the battery notification passes through
wacom_intuos_bt_process_data() first, so no reachable work is lost.
Fixes: 2a6cdbdd4cc0 ("HID: wacom: Introduce new 'touch_input' device")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 48a58a6672c2..11544adb74f5 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -1237,6 +1237,9 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len)
int i = 1;
unsigned power_raw, battery_capacity, bat_charging, ps_connected;
+ if (!wacom->pen_input)
+ return 0;
+
switch (data[0]) {
case 0x04:
if (len < 32) {
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 5/5] HID: wacom: check the input devices in the Bamboo handlers
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
` (3 preceding siblings ...)
2026-09-27 4:11 ` [PATCH 4/5] HID: wacom: check the input device in wacom_intuos_bt_irq() Jinmo Yang
@ 2026-09-27 4:11 ` Jinmo Yang
4 siblings, 0 replies; 11+ messages in thread
From: Jinmo Yang @ 2026-09-27 4:11 UTC (permalink / raw)
To: ping.cheng, jason.gerecke, jikos, bentiss
Cc: dmitry.torokhov, linux-input, linux-kernel, Jinmo Yang, stable
wacom_bpt_touch() takes both touch_input and pad_input, and
wacom_bpt3_touch_msg() and wacom_bpt3_button_msg() take touch_input and
pad_input respectively, none of them checked. An interface that declares
only pen usages leaves touch_input and pad_input NULL on a fully
successful probe, and wacom_bpt_irq() still dispatches to these
handlers.
Four locations fault, each reproduced on linux-next 20260925 (x86_64,
KASAN) from one /dev/uhid device plus a single UHID_INPUT2 write:
wacom_wac.c:3100 wacom_bpt_touch touch_input
wacom_wac.c:3117 wacom_bpt_touch pad_input
wacom_wac.c:3130 wacom_bpt3_touch_msg touch_input
wacom_wac.c:3178 wacom_bpt3_button_msg pad_input
for example, with vendor 0x056a product 0x00D4 (BAMBOO_PEN), a pen-only
descriptor and report id 2:
BUG: KASAN: null-ptr-deref in input_event+0x44/0xb0
Read of size 8 at addr 0000000000000028
wacom_wac_irq+0x8185/0xb3f0
wacom_raw_event+0x68f/0xb60
__hid_input_report+0x398/0x4d0
uhid_char_write+0xa99/0xfc0
wacom_bpt_touch() serves touch and pad in one report, so its two blocks
are guarded separately - an interface with a pad but no touch must keep
delivering pad events. In wacom_bpt3_touch_msg() the slot lookup moves
below the check because it dereferences the input device itself.
The touch block of wacom_bpt_touch() is reindented into the new
conditional; git diff -w shows no change there beyond the two style
fixes checkpatch asks for on the lines that move.
Fixes: 2a6cdbdd4cc0 ("HID: wacom: Introduce new 'touch_input' device")
Fixes: 3116871f4273 ("Input: wacom - split out the pad device for Bamboos")
Cc: stable@vger.kernel.org
Signed-off-by: Jinmo Yang <jinmo44.yang@gmail.com>
---
drivers/hid/wacom_wac.c | 56 +++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 22 deletions(-)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 11544adb74f5..dac67885f81e 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -3118,31 +3118,36 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
if (data[0] != 0x02)
return 0;
- for (i = 0; i < 2; i++) {
- int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
- bool touch = report_touch_events(wacom)
- && (data[offset + 3] & 0x80);
-
- input_mt_slot(input, i);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
- if (touch) {
- int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
- int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
- if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
- x <<= 5;
- y <<= 5;
+ if (input) {
+ for (i = 0; i < 2; i++) {
+ int offset = (data[1] & 0x80) ? (8 * i) : (9 * i);
+ bool touch = report_touch_events(wacom) &&
+ (data[offset + 3] & 0x80);
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
+ if (touch) {
+ int x = get_unaligned_be16(&data[offset + 3]) & 0x7ff;
+ int y = get_unaligned_be16(&data[offset + 5]) & 0x7ff;
+
+ if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
+ x <<= 5;
+ y <<= 5;
+ }
+ input_report_abs(input, ABS_MT_POSITION_X, x);
+ input_report_abs(input, ABS_MT_POSITION_Y, y);
}
- input_report_abs(input, ABS_MT_POSITION_X, x);
- input_report_abs(input, ABS_MT_POSITION_Y, y);
}
- }
- input_mt_sync_frame(input);
+ input_mt_sync_frame(input);
+ }
- input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
- input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
- input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
- input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+ if (pad_input) {
+ input_report_key(pad_input, BTN_LEFT, (data[1] & 0x08) != 0);
+ input_report_key(pad_input, BTN_FORWARD, (data[1] & 0x04) != 0);
+ input_report_key(pad_input, BTN_BACK, (data[1] & 0x02) != 0);
+ input_report_key(pad_input, BTN_RIGHT, (data[1] & 0x01) != 0);
+ }
wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom);
return 1;
@@ -3153,8 +3158,12 @@ static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->touch_input;
bool touch = data[1] & 0x80;
- int slot = input_mt_get_slot_by_key(input, data[0]);
+ int slot;
+ if (!input)
+ return;
+
+ slot = input_mt_get_slot_by_key(input, data[0]);
if (slot < 0)
return;
@@ -3196,6 +3205,9 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data)
struct input_dev *input = wacom->pad_input;
struct wacom_features *features = &wacom->features;
+ if (!input)
+ return;
+
if (features->type == INTUOSHT || features->type == INTUOSHT2) {
input_report_key(input, BTN_LEFT, (data[1] & 0x02) != 0);
input_report_key(input, BTN_BACK, (data[1] & 0x08) != 0);
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-09-27 4:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-23 15:01 [PATCH] HID: wacom: fix NULL pointer dereference in wacom_intuos_pad() Jinmo Yang
2026-05-23 15:06 ` [PATCH v2] " Jinmo Yang
2026-05-29 21:44 ` Dmitry Torokhov
2026-06-10 15:48 ` Jiri Kosina
2026-09-26 18:37 ` Jinmo Yang
2026-09-27 4:11 ` [PATCH 0/5] HID: wacom: check input devices in the report handlers Jinmo Yang
2026-09-27 4:11 ` [PATCH 1/5] HID: wacom: check the input device in the shared report helpers Jinmo Yang
2026-09-27 4:11 ` [PATCH 2/5] HID: wacom: check the input devices in the legacy irq handlers Jinmo Yang
2026-09-27 4:11 ` [PATCH 3/5] HID: wacom: check the input device in wacom_intuos_pad() Jinmo Yang
2026-09-27 4:11 ` [PATCH 4/5] HID: wacom: check the input device in wacom_intuos_bt_irq() Jinmo Yang
2026-09-27 4:11 ` [PATCH 5/5] HID: wacom: check the input devices in the Bamboo handlers Jinmo Yang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®