From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Guanglei Zhu <zhugl3@xiaopeng.com>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
liuc63@xiaopeng.com, stable@vger.kernel.org
Subject: Re: [PATCH v2] Input: adi - bound the two-stream packet merge
Date: Wed, 04 Nov 2026 14:17:28 -0800 [thread overview]
Message-ID: <a27ddee4a4404e7d607b09f92924b2b7@gmail.com> (raw)
In-Reply-To: <20261103111714.472080-1-zhugl3@xiaopeng.com>
Hi Guanglei,
On Tue, Nov 03, 2026 at 07:17:14PM +0800, Guanglei Zhu wrote:
> When a second device shares the wire, adi_move_bits() appends the
> second packet to the first one at an offset taken from the
> 10-bit length field of the ID packet:
>
> for (i = 1; i <= adi[1].ret; i++)
> adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
>
> adi[0].ret += adi[1].ret;
>
> Nothing compares the merged packet against the size of the buffer:
> adi[0].data is the last member of struct adi, and struct adi_port
> holds two of them back to back, so an oversized length field makes
> the loop write over the second struct adi - its device pointer, its
> length and its packet - and the inflated ret later walks the reads
> past the buffer as well. The connect path also calls
> adi_move_bits() before the length has been validated at all.
>
> Reject a merge that does not fit in the buffer. Use >= for the
> combined length so adi_get_bits() can never walk to data[ret] with
> ret == ADI_MAX_LENGTH, and invalidate both half-streams on the
> rejection so the unmerged packets are not decoded as standalone
> reads.
>
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Guanglei Zhu <zhugl3@xiaopeng.com>
> ---
> v2: per review, use >= so a combined ret of ADI_MAX_LENGTH is rejected
> as well (adi_get_bits() allows idx == ret, and data[idx] with
> idx == ADI_MAX_LENGTH reads one byte past the array), and set
> adi[0].ret = adi[1].ret = -1 on the rejection path so the
> unmerged half-streams are not decoded as standalone packets.
>
> drivers/input/joystick/adi.c | 5 +++++
> 1 file changed, 5 insertions(+)
>
> diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
> index e07b719..41262b7 100644
> --- a/drivers/input/joystick/adi.c
> +++ b/drivers/input/joystick/adi.c
> @@ -168,6 +168,11 @@ static void adi_move_bits(struct adi_port *port, int length)
>
> if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
> if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
> + if (adi[0].ret + adi[1].ret >= ADI_MAX_LENGTH ||
> + ((length - 1) >> 1) + adi[1].ret + 1 >= ADI_MAX_LENGTH) {
> + adi[0].ret = adi[1].ret = -1;
> + return;
> + }
>
> for (i = 1; i <= adi[1].ret; i++)
> adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
In adi_move_bits(), length can also be 0 (either from the 10-bit header
in adi_connect() or when port->adi[0].length is 0 in adi_read()), so
please reject length <= 0 as well. It would also be cleaner to compute
the start offset (for example, offset = ((length - 1) >> 1) + 1) once
and use offset + adi[1].ret and offset + i in both the bounds check and
the copy loop.
Since you are hardening this driver against malformed packets on the
gameport wire, there are a few more bounds issues in the same file worth
addressing:
In adi_read_packet(), the condition adi[i].ret < ADI_MAX_LENGTH is off
by one because adi[i].data[++adi[i].ret] pre-increments ret, allowing a
write to adi[i].data[ADI_MAX_LENGTH] when ret is ADI_MAX_LENGTH - 1. It
should check adi[i].ret < ADI_MAX_LENGTH - 1.
In adi_id_decode(), when ADI_FLAG_10BIT is set, adi->axes10 =
adi->axes8 - i can underflow if i > adi->axes8, and for ADI_ID_TPD and
ADI_ID_WGP, adi->buttons -= 4 can underflow if adi->buttons < 4. Please
also switch the non-string byte fields and buffers in struct adi (such
as id, buttons, axes10, axes8, hats, and data) from char/unsigned char
to u8 (and s8 for pad) so their signedness does not vary across
architectures. Finally, the decoded axis, hat, and button counts are
not checked against the sizes of the static adi_abs[] and adi_key[]
tables for the device ID before adi_init_input(), adi_init_center(),
and adi_decode() walk adi->abs and adi->key.
Could you please fold these fixes in (or split them into a small series
if you prefer)?
Thanks.
--
Dmitry
next prev parent reply other threads:[~2026-11-04 22:17 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 8:41 [PATCH] Input: joydev - avoid an undefined shift in the legacy 0x read Guanglei Zhu
2026-11-03 8:41 ` [PATCH] Input: joydev - avoid signed overflow in the broken-axis correction Guanglei Zhu
2026-11-03 8:48 ` sashiko-bot
2026-11-03 8:55 ` [PATCH v2] " Guanglei Zhu
2026-11-04 3:38 ` Dmitry Torokhov
2026-11-04 5:50 ` [PATCH v3] " Guanglei Zhu
2026-11-04 6:02 ` Guanglei Zhu
2026-11-03 8:41 ` [PATCH] Input: adi - bound the two-stream packet merge Guanglei Zhu
2026-11-03 8:55 ` sashiko-bot
2026-11-03 11:17 ` [PATCH v2] " Guanglei Zhu
2026-11-04 22:17 ` Dmitry Torokhov [this message]
2026-11-03 8:41 ` [PATCH] Input: db9 - enlarge the Saturn multitap packet buffer Guanglei Zhu
2026-11-03 8:41 ` [PATCH] Input: lpc32xx-keys - reject matrices bigger than the hardware has Guanglei Zhu
2026-11-03 18:54 ` Dmitry Torokhov
2026-11-04 3:07 ` [PATCH v2] " Guanglei Zhu
2026-11-04 6:25 ` Dmitry Torokhov
2026-11-03 8:41 ` [PATCH] Input: mt6779-keypad - check the reported row and column Guanglei Zhu
2026-11-03 8:41 ` [PATCH] Input: tegra-kbc - check the pin numbers from the device tree Guanglei Zhu
2026-11-04 17:08 ` Dmitry Torokhov
2026-11-03 8:41 ` [PATCH] Input: cyapa_gen3 - clamp the reported finger count to the array Guanglei Zhu
2026-11-04 20:09 ` Dmitry Torokhov
2026-11-03 18:45 ` [PATCH] Input: joydev - avoid an undefined shift in the legacy 0x read Dmitry Torokhov
2026-11-04 3:07 ` [PATCH v2] " Guanglei Zhu
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=a27ddee4a4404e7d607b09f92924b2b7@gmail.com \
--to=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=liuc63@xiaopeng.com \
--cc=stable@vger.kernel.org \
--cc=zhugl3@xiaopeng.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.