rx-ring init writes 4-byte int into const uint16_t nr_buf_size, clobbering the adjacent flags field (latent β module does not build on DFly)
Summary
netmap_mem_rings_create initializes the rx rings' buffer-size field with *(int *)&ring->nr_buf_size, but nr_buf_size is const uint16_t immediately followed by uint16_t flags: the 4-byte store overwrites flags with the high 16 bits of the buffer size. The tx-ring init 30 lines earlier is correct (*(uint16_t *)). Benign-by-luck with default 2KB buf pools (high half = 0); with pool objsize >= 65536 flags is silently set, flipping userspace-visible ring semantics (NR_TIMESTAMP/NR_FORWARD/NR_RX_TSTMP) on rx rings only. LATENT (module unbuildable - verified). Fix: match the tx path's uint16_t width.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3397 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | β | 1.7 KB | β raw | |
| netmap_build.log | β | 12.2 KB | view raw | |
| fix.diff | β | 486 B | view raw | |
| manifest.json | β | 623 B | view raw | |
| verdict.json | β | 1.7 KB | view raw |
VERDICT β DF-3397: analysis-only (module does not build on DragonFly)
Root cause
netmap_mem_rings_create() initializes the rx rings' buffer-size
field with a 4-byte write:
sys/net/netmap/netmap_mem2.c:974: *(int *)(uintptr_t)&ring->nr_buf_size = NETMAP_BDG_BUF_SIZE(na->nm_mem);
but struct netmap_ring.nr_buf_size is const uint16_t
(sys/net/netmap/netmap.h:225), immediately followed by uint16_t flags
(netmap.h:226). The 4-byte store therefore overwrites the adjacent
flags field with the high 16 bits of the buffer size. The tx-ring
initialization 30 lines earlier does it correctly:
*(uint16_t *)(uintptr_t)&ring->nr_buf_size (netmap_mem2.c:945).
Consequence (latent)
With default pool sizes (buf objsize 2048) the high half of the size is
0, so flags is re-zeroed on an already-zeroed allocation β benign by
luck. With a large buf size (pool is configurable up to objmaxsize
65536 via dev.netmap.buf_size; NETMAP_BDG_BUF_SIZE rounds to the pool
_objsize), the high half becomes 1 and flags is silently set β
userspace then sees NR_TIMESTAMP/NR_FORWARD/NR_RX_TSTMP style flag bits
it never requested, changing ring semantics (e.g. timestamp writes into
slots, buffer forwarding) on rx rings only. Latent: the module does not
build on this tree (netmap_build.log; same platform fact as DF-3396).
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix.diff authored; cannot be built/validated because the netmap module does not compile on this tree.
fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
['VERDICT.md β the 4-byte vs 2-byte store asymmetry (:974 vs :945) and the adjacent-field layout (netmap.h:225-226)', 'netmap_build.log β module build failure on this tree']
PoC changes
No executable PoC possible; analysis-only.
Verified recommended fix
Use (uint16_t )(uintptr_t)&ring->nr_buf_size in the rx path, matching :945.
Verdict
Latent type/width bug (certain from source): rx-ring init writes a 4-byte int into the const uint16_t nr_buf_size field (netmap.h:225), clobbering the adjacent uint16_t flags (netmap.h:226) with the high half of NETMAP_BDG_BUF_SIZE; the tx-ring path at :945 uses the correct uint16_t store. Benign with default 2KB pools (high half 0), changes rx-ring semantics with >=64KB buf pools. PoC impossible: module does not compile on this tree.
No comments yet.