Files
SixSixSix 6c71bedba9 initial: research mono-repo, first finding cifs-smb2-read-overflow
Companion repository for the writeups at https://trexnegro.github.io.
Each subdirectory is one finding with its own README, reproducer, and
artifacts.

First entry: cifs-smb2-read-overflow — Linux kernel integer overflow
in fs/smb/client/{transport.c,smb2ops.c}, fixed upstream in mainline
commit 81a874233c305d29e37fdb70b691ff4254294c0b and AUTOSEL'd to
stable on 2026-05-20. Includes impacket-based malicious server, QEMU
lab scripts, and side-by-side KASAN traces (vulnerable ~245s stall
vs patched ~66s clean shutdown).

Companion writeup:
https://trexnegro.github.io/posts/u32-plus-u32-equals-zero-smb2-overflow/
2026-06-01 23:49:43 +00:00
..

cifs-smb2-read-overflow

Reproducer for an integer overflow in the Linux SMB2 client (fs/smb/client/) that lets a malicious SMB server stall a mount.cifs mount for 180 seconds per READ. Fixed upstream in 81a874233c305d29e37fdb70b691ff4254294c0b ("smb: client: avoid integer overflow in SMB2 READ length check"), AUTOSEL'd to stable on 2026-05-20.

This is one finding inside the unified research repository. Top-level index: ../README.md.

Companion write-up: https://trexnegro.github.io/posts/u32-plus-u32-equals-zero-smb2-overflow/

What the bug is

cifs_readv_receive() and handle_read_data() validate the SMB2 READ response with an unguarded sum:

if (!use_rdma_mr && (data_offset + data_len > buflen))   /* transport.c */
    return -1;

} else if (buf_len >= data_offset + data_len) {          /* smb2ops.c */
    copy_to_iter(buf + data_offset, data_len, &rdata->subreq.io_iter);

Both data_offset and data_len are unsigned int. A malicious server that replies with DataOffset = 0x50 and DataLength = 0xFFFFFFB0 wraps the sum to 0, the check passes, and the kernel walks into reading ~4 GiB off the TCP socket — stalling for the 180-second response timeout before reconnecting.

Layout

server/malicious_server.py    impacket-based hostile SMB2 server
lab/run-vulnerable.sh         QEMU lifter against an unpatched bzImage
lab/run-patched.sh            same lifter against a patched bzImage
lab/init.sh                   guest init script (place in initrd as /init)
logs/qemu-vulnerable-redacted.log    ~245 s vulnerable run (stall + reconnect)
logs/qemu-patched-clean.log          ~66 s patched run (clean shutdown)

Running it

Pre-reqs on the host:

  • Python 3.10+ with pip install impacket (>=0.11)
  • QEMU 10+ with TCG (KVM not required)
  • A Linux source tree at linux-v7.0 or earlier (vulnerable) for one run
  • A Linux source tree at linux-v7.1+ or with the patch backported (patched) for comparison

Build kernels with at minimum:

CONFIG_CIFS=y
CONFIG_KASAN_GENERIC=y
CONFIG_KASAN_OUTLINE=y
CONFIG_FORTIFY_SOURCE=y

Pack an initrd containing mount.cifs and BusyBox, with lab/init.sh installed as /init.

Then:

# vulnerable
export KERNEL=/path/to/vulnerable/arch/x86/boot/bzImage
export INITRD=/path/to/initrd.cpio.gz
./lab/run-vulnerable.sh

# patched
export KERNEL=/path/to/patched/arch/x86/boot/bzImage
./lab/run-patched.sh

Expected vulnerable output, around the 240-second mark:

CIFS: VFS: \\10.0.2.2 has not responded in 180 seconds. Reconnecting...
CIFS: fs/smb/client/transport.c:
  total_read=4294967273  buflen=144  remaining=4294967216

The remaining=4294967216 value is 0xFFFFFFB0 — exactly the attacker's DataLength. That value reaching the receive call is the smoking gun.

Patched output: mount + dd + clean shutdown in ~66 s, no not responded line.

Sample side-by-side logs are included under logs/.

The fix, for reference

The upstream patch wraps both sites with check_add_overflow():

- } else if (buf_len >= data_offset + data_len) {
+ } else if (!check_add_overflow(data_offset, data_len, &end_off) &&
+        buf_len >= end_off) {
- if (!use_rdma_mr && (data_offset + data_len > buflen))
-     return -1;
+ if (!use_rdma_mr) {
+     if (check_add_overflow(data_offset, data_len, &end_off))
+         return -1;
+     if (end_off > buflen)
+         return -1;
+ }

check_add_overflow() lives in include/linux/overflow.h and is already used elsewhere in fs/smb/.

Scope and intent

Authorised research / education use only. The malicious server is small, boring, and easy to detect; it exists to make the bug reproducible on a single workstation. Do not point it at servers you don't own.

License

MIT — see ../LICENSE at the repository root.