Re: [PATCH 2/5] HID: wacom: check the input devices in the legacy irq handlers

From: Jason Gerecke

Date: Fri Oct 16 2026 - 20:06:56 EST


On Sat, Sep 26, 2026 at 9:12 PM Jinmo Yang <jinmo44.yang@xxxxxxxxx> wrote:
>
> 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.
>
Such a device does not exist for the cases handled by
wacom_graphire_irq and wacom_dtus_irq. A pen interface is expected for
all of these device types, and a pad interface is expected for all but
the GRAPHIRE case. The wacom_setup_device_quirks function takes care
of ensuring that the pad type gets added to the same interface as the
pen (for all but GRAPHIRE) so that wacom_setup_pad_input_capabilities
does not cull the interface later.

It should be safe to move the checks for valid pen and touch
interfaces to the top of both of these functions (again, with the
additional condition that wacom_graphire_irq must must ignore a NULL
pad in the case of a GRAPHIRE type).

> 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@xxxxxxxxxxxxxxx
> Signed-off-by: Jinmo Yang <jinmo44.yang@xxxxxxxxx>
> ---
> 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;
> +

As with patch 1, each of these checks is for an unusual error
condition so a dev_warn_once or hid_warn_once before returning is
suggested.

Jason (she/they)
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....


> 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
>
>