kernel/debug/gdbstub.c | 8 ++++++++ 1 file changed, 8 insertions(+)
gdb_cmd_memread() passes the length of the 'm' packet straight to
kgdb_mem2hex(), which hex-encodes the reply into
remcom_out_buffer[BUFMAX] without checking that the reply fits. A
client on the KGDB I/O console can ask for a read of any size, and
the hex encoding runs off the end of the buffer. kgdb_mem2hex() takes
that length as an int count, so 2^31 truncates to a negative value
and copy_from_kernel_nofault() is handed buf + count as its
destination.
On x86 BUFMAX is 1024, so a read of 512 bytes overruns by the single
byte that terminates the hex string:
BUG: KASAN: global-out-of-bounds in kgdb_mem2hex+0x1dd/0x230
Write of size 1 at addr ffffffff87651780 by task sh/1
...
The buggy address belongs to the variable:
remcom_out_buffer+0x400/0x420
Bounds check the length before the hex encoding:
if (length > (BUFMAX - 1) / 2) {
error_packet(remcom_out_buffer, -EINVAL);
return;
}
gdbstub_msg_write() already bounds the count it hex-encodes
against BUFMAX. Reads over the limit never returned valid data,
so an error reply loses nothing.
Fixes: dc7d55270521 ("kgdb: core")
Cc: stable@vger.kernel.org
Assisted-by: Hawkeye:GLM-5.3-flash
Assisted-by: Qoder:Qwen3.8-Max
Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
---
The scanner is a taint-style review of the packet handlers in
kernel/debug/gdbstub.c. write_mem_msg() ('M' and 'X' packets) trusts
the same length field and looks like the same class of problem; I can
send that separately if there is interest.
Reproducer: attach to a kgdboc console and send an 'm' packet with a
length above (BUFMAX - 1) / 2, e.g. "m<addr>,200" on x86. Before this
change the hex encoding runs off the end of remcom_out_buffer; after
it the stub answers E22 and the guest resumes.
Both cases were run on 704340f1cd0d (v7.3-rc4): x86_64 defconfig plus
CONFIG_KASAN_GENERIC, gcc 13.2.0, QEMU under TCG. The two kernels are
built from byte-identical .config files and differ only by this patch.
Two details of the setup are not obvious. CONFIG_KGDB_KDB has to be
off: dbg_kdb_mode starts at 1, so with kdb built in a sysrq-g break
lands in kdb_stub() and the packet is never parsed.
A minimal over-the-limit length reproduces better than a large one.
copy_from_kernel_nofault() copies through raw asm accessors that KASAN
does not instrument, so length = 0x10000 writes 64 KiB past the buffer
with no report at all and the kernel simply stops answering. length =
0x200 keeps that copy inside the buffer, which leaves the terminating
store as the only out-of-bounds access and gives the report above.
kernel/debug/gdbstub.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/kernel/debug/gdbstub.c b/kernel/debug/gdbstub.c
index e271a43..5774292 100644
--- a/kernel/debug/gdbstub.c
+++ b/kernel/debug/gdbstub.c
@@ -563,6 +563,14 @@ static void gdb_cmd_memread(struct kgdb_state *ks)
if (kgdb_hex2long(&ptr, &addr) > 0 && *ptr++ == ',' &&
kgdb_hex2long(&ptr, &length) > 0) {
+ /*
+ * The hex-encoded reply needs 2 * length + 1 bytes
+ * in remcom_out_buffer[BUFMAX].
+ */
+ if (length > (BUFMAX - 1) / 2) {
+ error_packet(remcom_out_buffer, -EINVAL);
+ return;
+ }
err = kgdb_mem2hex((char *)addr, remcom_out_buffer, length);
if (!err)
error_packet(remcom_out_buffer, -EINVAL);
--
2.50.1 (Apple Git-155)
Hi,
On Mon, Sep 14, 2026 at 11:04 AM Fang Xieyan <fangxy@xiaopeng.com> wrote:
>
> gdb_cmd_memread() passes the length of the 'm' packet straight to
> kgdb_mem2hex(), which hex-encodes the reply into
> remcom_out_buffer[BUFMAX] without checking that the reply fits. A
> client on the KGDB I/O console can ask for a read of any size, and
> the hex encoding runs off the end of the buffer. kgdb_mem2hex() takes
> that length as an int count, so 2^31 truncates to a negative value
> and copy_from_kernel_nofault() is handed buf + count as its
> destination.
>
> On x86 BUFMAX is 1024, so a read of 512 bytes overruns by the single
> byte that terminates the hex string:
>
> BUG: KASAN: global-out-of-bounds in kgdb_mem2hex+0x1dd/0x230
> Write of size 1 at addr ffffffff87651780 by task sh/1
> ...
> The buggy address belongs to the variable:
> remcom_out_buffer+0x400/0x420
>
> Bounds check the length before the hex encoding:
>
> if (length > (BUFMAX - 1) / 2) {
> error_packet(remcom_out_buffer, -EINVAL);
> return;
> }
>
> gdbstub_msg_write() already bounds the count it hex-encodes
> against BUFMAX. Reads over the limit never returned valid data,
> so an error reply loses nothing.
>
> Fixes: dc7d55270521 ("kgdb: core")
> Cc: stable@vger.kernel.org
> Assisted-by: Hawkeye:GLM-5.3-flash
> Assisted-by: Qoder:Qwen3.8-Max
> Signed-off-by: Fang Xieyan <fangxy@xiaopeng.com>
Looks like a good fix to me.
Reviewed-by: Douglas Anderson <dianders@chromium.org>
> The scanner is a taint-style review of the packet handlers in
> kernel/debug/gdbstub.c. write_mem_msg() ('M' and 'X' packets) trusts
> the same length field and looks like the same class of problem; I can
> send that separately if there is interest.
Yeah, my AI also says 'M' and 'X' packets likely have the same bug. It
also claims qRcmd packet may have similar issues. Sending a patch to
fix would be great.
-Doug
© 2016 - 2026 Red Hat, Inc.