β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-0265

Missing distance bounds validation in inflate: heap OOB read when windowBits<15

Field Value
ID DF-0265
Status new
Severity High
CVSS 3.1 CVSS:3.1/AV:A/AC:H/PR:L/UI:N/S:U/C:H/I:N/A:C
CWE CWE-125 Out-of-bounds Read
File sys/net/zlib.c
Lines 4824-5085
Area net
Confidence certain
Discovered 2026-06-30
Reported pending
Known CVE CVE-2018-25032 (related, NOT equivalent)
CVE match variant

Summary

The in-kernel zlib is version 1.0.4 from December 1997 (FILEVERSION 971210) β€” 28 years old, predating ALL modern zlib security hardening. The inflate code computes back-reference source pointers from decoded distance codes without checking that the distance does not exceed the allocated window size. DEFLATE allows distances up to 32768 bytes, but inflateInit2_ permits windowBits as low as 8 (256-byte window). A malicious compressed stream using large distance codes against a small window causes a heap buffer over-read of up to ~32KB.

Root cause

Distance code range: cpdist[30] (line 4149) allows distances up to 32768 bytes.

Window size: inflateInit2_ (line 3180) allows windowBits 8..15. Window allocation is 1 << wbits bytes (line 3350).

Missing check: The decoded distance is used directly in pointer arithmetic at line 4825 (inflate_codes COPY case):

s->end - (c->sub.copy.dist - (q - s->window))

and line 5076 (inflate_fast):

r = s->end - e

No check exists that dist <= (1 << s->wbits). Modern zlib validates dist <= state->dmax β€” this check is entirely absent in 1.0.4.

Threat model & preconditions

  • Attacker position: Authenticated PPP peer (via netgraph7_deflate compression). The PPP peer negotiates windowBits < 15 during CCP, then sends a compressed frame containing a large distance code.
  • Impact: Kernel heap info leak (up to ~32KB of adjacent heap contents per malicious packet) and/or kernel panic (OOB read crossing into unmapped memory).
  • Required config: PPP with deflate compression enabled. netgraph7_deflate uses raw DEFLATE mode (-windowBits, nowrap=1), bypassing zlib header validation entirely.

Short-term: Add distance validation before the COPY case:

if (c->sub.copy.dist > (1 << s->wbits)) {
    z->msg = "invalid distance too far back";
    c->mode = BADCODE;
    r = Z_DATA_ERROR;
    LEAVE;
}

Long-term: Replace this 28-year-old zlib with the modern sys/contrib/zlib/ already present in the tree, which has 28 years of security fixes including this one.

References

  • CVE-2018-25032 / FreeBSD-SA-22:08.zlib β€” related but NOT equivalent. That CVE is an out-of-bounds write in zlib's deflate (compression) routine in contrib/ zlib. DF-0265 is an out-of-bounds read in zlib's inflate (decompression) distance handling in the separate, ancient sys/net/zlib.c 1.0.4 copy (netboot PPP Deflate compression), not the contrib/ tree. Same broad bug class (zlib OOB memory access), different operation, different code copy, different impact (read vs write) β€” hence variant, not equivalent.
  • This zlib version: 1.0.4, FILEVERSION 971210
  • Modern zlib fix: if (dist > state->dmax) check in inflate.c

Timeline

  • 2026-06-30 Discovered during automated audit.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-0265 Β· 19 files
FileTypeDescriptionSize
harness.c trigger-source guard-page allocator + inflate driver; links the verbatim audited zlib.c and catches the window underflow as SIGSEGV 11.1 KB view raw
zlib.c audit-source-copy byte-identical copy of sys/net/zlib.c (the vulnerable code under test) 172.9 KB view raw
zlib.h audit-source-copy byte-identical copy of sys/net/zlib.h 42.4 KB view raw
kshim.h build-shim userspace stubs for kernel-only MODULE_VERSION/MAX tokens; -include'd, does NOT touch inflate code 842 B view raw
gen_stream.py stream-generator host-side script that produced the crafted raw-DEFLATE stream embedded in harness.c 1.6 KB view raw
build.sh build-script exact cc command 480 B view raw
run.sh run-script exact run command (arg = windowBits) 362 B view raw
build.log build-log final successful build, full output 13 B view raw
run.log run-log decisive vulnerable run (wbits=-8): SIGSEGV -255 bytes before window 709 B view raw
run.control.log run-log control run (wbits=-15): clean Z_STREAM_END, total_out=916 573 B view raw
run_stress.log run-log 3 repeat runs of the vulnerable config (deterministic) 1.9 KB view raw
env.txt environment uname, cc version, kldstat, module availability (ng_deflate NOT built) 748 B view raw
fix.diff suggested-fix git-apply-able unified diff: dist>window check in inflate_codes AND inflate_fast; VERIFIED (patch -p1 clean, harness OOB closed, kernel modules build -Werror) 1.6 KB view raw
fix_run.log fix-run-log patched-harness run: wbits=-8 -> Z_DATA_ERROR 'invalid distance too far back' (no OOB); wbits=-15 still Z_STREAM_END total_out=916; deterministic x3 2.1 KB view raw
fix_build.log fix-build-log kernel-tree: patch -p1 applies both hunks (4818,5073); zlib.ko + ng_deflate.ko build clean with -D_KERNEL -Werror (MAKE_RC=0); new error string in zlib.o 13.4 KB view raw
VERDICT.md verdict full narrative analysis: root cause, reproduction, reachability, fix verification (Section 6 = Phase 8 results) 10.5 KB ↓ raw
README.md readme human reproduce instructions 3.0 KB ↓ raw
../fix_build_combined.log build-log Combined 41-finding kernel build (rc=0, -Werror clean) 5.6 MB ↓ download
../fix_build_summary.txt build-summary Summary of the combined 41-finding kernel build 826 B view raw
README.md readme human reproduce instructions
↓ download raw

DF-0265 β€” PoC: heap OOB read in zlib 1.0.4 inflate when windowBits < 15

Verbatim copy of the audited sys/net/zlib.c (and sys/net/zlib.h), plus a userspace harness that links them unmodified and drives inflate with a crafted raw-DEFLATE stream. A guard page placed before every zlib allocation surfaces the sliding-window underflow as a SIGSEGV β€” conclusive proof of the missing distance-bounds check.

Build

./build.sh          # cc -O2 -Wall -include kshim.h -o harness harness.c zlib.c

kshim.h only stubs out the kernel-only MODULE_VERSION / MAX tokens that zlib.c references at file scope; it does not touch the inflate code under test (the file is byte-identical to sys/net/zlib.c).

Run

./run.sh            # vulnerable config: windowBits=-8 (256-byte window)
./run.sh -15        # control:           windowBits=-15 (32KiB window), no OOB

Expected (bug present), windowBits=-8

[harness] *** SIGSEGV/SIGBUS during inflate at 0x800480f01 ***
[harness] nearest alloc #2 [user=0x800481000 size=256 (0x100)]: fault is -255 bytes (BEFORE-start (underflow into guard page))
[harness] RESULT: OOB READ CONFIRMED -- inflate dereferenced memory outside an allocation ...

The fault address is 255 bytes before the 256-byte sliding window β€” i.e. inflate read s->end - (dist - (q - s->window)) with dist far larger than the window and underflowed past s->window into the guard page.

Expected, windowBits=-15 (control)

[harness] inflate returned 1, msg=(null), total_out=916

The 32 KiB window swallows the stream's distance (658) cleanly β€” same code, same stream, no OOB. This isolates the cause to the missing dist <= window check at small windowBits.

With the fix applied (see fix.diff)

windowBits=-8 : inflate returned -3, msg=invalid distance too far back   # rejected, no OOB
windowBits=-15: inflate returned 1,  total_out=916                       # still decodes cleanly

Files

file purpose
harness.c guard-page allocator + inflate driver; identifies the faulting allocation
zlib.c,zlib.h verbatim copies of the audited sys/net/zlib.c / sys/net/zlib.h
kshim.h userspace stubs for the kernel-only MODULE_VERSION / MAX tokens (-include)
build.sh,run.sh exact reproduce commands
gen_stream.py how the crafted raw-DEFLATE stream embedded in harness.c was produced
build.log final successful build output
run.log decisive vulnerable run (wbits=-8), full output
run.control.log control run (wbits=-15), full output
run_stress.log 3 repeat runs (deterministic)
env.txt guest uname / cc / kldstat / module availability
fix.diff git-apply-able unified diff adding the distance-bounds check
VERDICT.md full narrative analysis
manifest.json machine-readable artifact catalog

See VERDICT.md for the full root-cause analysis, reachability on the audited kernel, and the threat model.

VERDICT.md verdict full narrative analysis: root cause, reproduction, reachability, fix verification (Section 6 = Phase 8 results)
↓ download raw

DF-0265 β€” Verdict: REPRODUCED (latent on the audited kernel config)

Verdict: REPRODUCED β€” the missing distance-bounds check in sys/net/zlib.c (zlib 1.0.4, FILEVERSION 971210) is real and exploitable, confirmed deterministically by linking the exact, unmodified audited source into a userspace harness and catching a sliding-window underflow on a guard page. The vulnerable kernel consumer (netgraph7_deflate) is not compiled into the audited X86_64_GENERIC kernel and has no loadable ng_deflate.ko on the guest, so the defect is latent on the shipped master DEV kernel; it becomes live the moment an operator builds/loads NETGRAPH7_DEFLATE.


1. The bug, line by line

sys/net/zlib.c is zlib 1.0.4 (header at line 18: ==FILEVERSION 971210==). It is compiled into the kernel via sys/conf/files:

  • net/zlib.c optional mxge pci β€” used by dev/netif/mxge
  • net/zlib.c optional netgraph7_deflate β€” used by netgraph7/deflate

inflateInit2_ (sys/net/zlib.c:3143) clamps windowBits to 8..15 (line 3175) and allocates a window of 1 << wbits bytes in inflate_blocks_new (sys/net/zlib.c:3714-3726: s->window = ZALLOC(z,1,w), s->end = s->window + w). With windowBits=8 the window is 256 bytes.

DEFLATE distance codes, however, can resolve to 1..32768 bytes (cpdist[30] at sys/net/zlib.c:4149, max entry 24577 + extra bits β†’ 32768). Nothing in the decoder rejects a distance larger than the window. Two code paths consume the decoded distance directly in pointer arithmetic with no bounds check:

  1. inflate_codes COPY case (sys/net/zlib.c:4822-4831): c f = (uInt)(q - s->window) < c->sub.copy.dist ? s->end - (c->sub.copy.dist - (q - s->window)) : /* <-- underflow */ q - c->sub.copy.dist; When dist - (q - s->window) > (s->end - s->window) (i.e. dist exceeds the window size plus the current write offset), the subtraction s->end - (dist - (q - s->window)) underflows past s->window. The subsequent copy loop (OUTBYTE(*f++), lines 4834-4838) then reads memory before the window allocation.

  2. inflate_fast (sys/net/zlib.c:5073-5088): same pattern, e = d - (uInt)(q - s->window); r = s->end - e; at lines 5075-5076, followed by *q++ = *r++ copies that read from the underflowed pointer.

Modern zlib validates this. The newer copy in the same tree (sys/vfs/hammer2/zlib/) has the check in both paths: - hammer2_zlib_inflate.c:932: if (copy > state->whave) { "invalid distance too far back"; BAD; } - hammer2_zlib_inffast.c:177: if (dist > dmax) { "invalid distance too far back"; ... }

The 1.0.4 code in sys/net/zlib.c has neither β€” confirmed by reading the full inflate_codes and inflate_fast functions. The finding is accurate.

2. Reproduction

The harness (harness.c) links the verbatim sys/net/zlib.c in its userspace compile mode (which the file explicitly supports: it #includes "zlib.h" when _KERNEL is undefined and contains the identical distance-handling code that ships in the kernel). It supplies a custom zcalloc/zcfree that mmap's every allocation with a PROT_NONE guard page immediately before the user pointer, then drives inflate with a crafted raw-DEFLATE stream (see gen_stream.py) that contains a distance of ~658 β€” well past a 256-byte window.

Decisive run, windowBits=-8 (256-byte window), run.log:

[harness] 3 allocations made by inflateInit2:
  #2 user=0x800481000 size=256 (0x100)            <-- the sliding window
[harness] calling inflate on 551-byte stream, window=256 bytes...
[harness] *** SIGSEGV/SIGBUS during inflate at 0x800480f01 ***
[harness] nearest alloc #2 [user=0x800481000 size=256 (0x100)]:
         fault is -255 bytes (BEFORE-start (underflow into guard page))
[harness] RESULT: OOB READ CONFIRMED

inflate read 255 bytes before the window start, into the guard page. The same stream with windowBits=-15 (32 KiB window) decompresses cleanly (run.control.log: inflate returned 1, total_out=916) β€” same code, same input, no OOB. This isolates the cause to the missing distance check at small windowBits.

Reproduced 3/3 times (run_stress.log); fully deterministic.

3. Reachability on the audited master DEV kernel

consumer windowBits reachable on X86_64_GENERIC?
dev/netif/mxge/if_mxge.c:675 (firmware inflate) inflateInit β†’ default 15 (32 KiB) safe by construction (distance ≀ 32768 ≀ window); plus the firmware blob is root-loaded from disk, not attacker-controlled.
netgraph7/deflate/ng_deflate.c:270 (PPP deflate) inflateInit2(-windowBits), 8..15 accepted (line 236) NOT compiled in. No ng_deflate.ko on the guest, NETGRAPH7/NETGRAPH7_DEFLATE absent from sys/config/X86_64_GENERIC. kldstat shows only kernel/ehci.ko/xhci.ko.

So on the shipped master DEV kernel the vulnerable path is dead code: sys/net/zlib.c is compiled only for mxge (which uses the safe default window). The defect becomes reachable only if an operator explicitly enables netgraph7_deflate (custom kernel build or a hand-built module, both root-gated).

If netgraph7_deflate is enabled, the threat model in the finding holds: a malicious authenticated PPP peer negotiates windowBits=8 during CCP, the local PPP daemon configures the node via NGM_DEFLATE_CONFIG, and the peer then ships a compressed frame whose DEFLATE stream carries a large distance code. inflate underflows the 256-byte window and either leaks adjacent kernel heap into the decompressed output (returned to the peer) or panics if the underflow crosses into an unmapped page. That is a genuine remote authenticated heap OOB read / DoS β€” the High severity the finding claims β€” but only on a kernel built with that option.

4. Impact classification

  • Code defect: real, confirmed, deterministic OOB read of up to ~32 KiB of kernel heap before the inflate window (and panic when the underflow leaves the slab/page).
  • On the audited kernel (X86_64_GENERIC, master DEV): latent β€” not reachable without enabling NETGRAPH7_DEFLATE. Effective severity on this config: Low (latent hardening gap). The mxge path is safe.
  • On a kernel with NETGRAPH7_DEFLATE enabled: High β€” remote authenticated heap info-leak / DoS via crafted PPP deflate frames, exactly as the finding states.

5. The fix (fix.diff, verified)

Add a dist > window check in both consume sites, mirroring modern zlib's "invalid distance too far back" rejection:

  • inflate_codes DISTEXTβ†’COPY (sys/net/zlib.c:4820): after the distance is fully decoded, if (c->sub.copy.dist > (uInt)(s->end - s->window)) β†’ set BADCODE, Z_DATA_ERROR, LEAVE.
  • inflate_fast (sys/net/zlib.c:5063): after d is computed, if (d > (uInt)(s->end - s->window)) β†’ UNGRAB; UPDATE; return Z_DATA_ERROR.

The check uses s->end - s->window (the actual allocated window size) so it needs no new state. Verified against the harness: with the patch applied, windowBits=-8 returns Z_DATA_ERROR "invalid distance too far back" (no OOB), while windowBits=-15 still decompresses the legitimate stream (total_out=916). The long-term recommendation (replace the 28-year-old sys/net/zlib.c with the modern sys/vfs/hammer2/zlib/ copy already in the tree, or upstream sys/contrib/zlib/) stands; this minimal fix closes the specific OOB read.

This fix matches the finding markdown's ## Recommended fix (the short-term dist > (1 << s->wbits) guard) in intent; the implementation here uses the equivalent (s->end - s->window) and covers both inflate_codes and inflate_fast (the markdown snippet only showed inflate_codes).

6. Phase 8 β€” fix validation (harness + kernel-tree, this run)

Because the vulnerable consumer (netgraph7_deflate) is latent on X86_64_GENERIC (not compiled in, no ng_deflate.ko), the bug is exercised through the userspace harness that links the verbatim audited net/zlib.c. Phase 8 validates the fix two independent ways.

6a. Harness-level (primary) β€” clean before/after on the SAME crafted stream

config baseline (zlib.c unpatched) patched (zlib.c + fix.diff)
windowBits=-8 (256 B win) SIGSEGV, fault βˆ’255 B before window Z_DATA_ERROR (-3) "invalid distance too far back", total_out=659, no OOB
windowBits=-15 (32K win) Z_STREAM_END (1), total_out=916 Z_STREAM_END (1), total_out=916 (no regression)

Determinism: 3/3 patched -8 runs return the identical Z_DATA_ERROR with no fault (saved in fix_run.log). The previously-faulting stream is now rejected at the distance-bounds check and never reaches the underflowing pointer arithmetic; the legitimate 32 KiB-window decode is byte-for-byte unchanged. β†’ fix_status: harness OOB closed.

6b. Kernel-tree (secondary) β€” patch applies + modules build with -Werror

On the with-src guest (kern.version = 6.5-DEVELOPMENT #0, unpatched): - cd /usr/src && patch -p1 < fix.diff β†’ both hunks apply cleanly (hunk #1 @ 4818, hunk #2 @ 5073); patch -p1 --dry-run rc=0. - make in /usr/src/sys/net/zlib (the zlib.ko module, which compiles net/zlib.c with full kernel CFLAGS -D_KERNEL -DKLD_MODULE -Werror) β†’ MAKE_RC=0, produces zlib.ko (44128 B) + zlib.o (44016 B). The new string "invalid distance too far back" is present in the compiled object (strings zlib.o), confirming the guard compiled into both inflate_codes and inflate_fast (symbols T inflate_codes / T inflate_fast present). - make in /usr/src/sys/netgraph7/deflate (the only vulnerable caller, ng_deflate.c) β†’ NG_MAKE_RC=0, produces ng_deflate.ko (13720 B) against the patched tree β€” the fix does not break the consumer's build.

Per the finding's latent status, no full kernel was rebuilt/booted (the path is dead code in GENERIC, so a boot test would not exercise it). The module builds + the harness before/after together prove the fix closes the bug at the code level. Full output in fix_build.log.

Fix classification: FIXED (harness OOB eliminated + kernel modules compile clean with -Werror). recommended_fix = matches the finding markdown's short-term proposal; the long-term recommendation (replace the 28-year-old sys/net/zlib.c with the modern sys/contrib/zlib/ already in the tree) stands and would subsume this minimal patch.

Fix verification

fixed
baseline reproduced→ patch + rebuild →patched clean

VALIDATED at the code level (latent in-kernel). Baseline harness: windowBits=-8 SIGSEGVs at -255 bytes before the 256-byte window (OOB READ CONFIRMED, deterministic 3/3) while windowBits=-15 decodes cleanly. Patched harness (zlib.c + fix.diff, same crafted stream): windowBits=-8 now returns Z_DATA_ERROR (-3) 'invalid distance too far back' with NO fault (deterministic 3/3) and windowBits=-15 is byte-for-byte unchanged (Z_STREAM_END total_out=916) => fix closes the OOB with no regression. Kernel-tree: fix.diff applies to /usr/src/sys/net/zlib.c via 'patch -p1' (both hunks @4818/@5073, dry-run rc=0); the patched net/zlib.c compiles into zlib.ko with full kernel CFLAGS -D_KERNEL -DKLD_MODULE -Werror (MAKE_RC=0) and the new error string is in the compiled object; ng_deflate.ko (the only vulnerable caller) also builds clean (NG_MAKE_RC=0). bug closed; effective on a NETGRAPH7_DEFLATE kernel the moment the module is built with this fix.

baseline wbits=-8: 'SIGSEGV during inflate at 0x800480f01' / 'fault is -255 bytes (BEFORE-start (underflow into guard page))' / 'OOB READ CONFIRMED' (3/3). baseline wbits=-15: 'inflate returned 1, total_out=916'. PATCHED wbits=-8: 'inflate returned -3, msg=invalid distance too far back, total_out=659' RUN_EXIT=0 NO fault (3/3). PATCHED wbits=-15: 'inflate returned 1, total_out=916' (no regression). kernel-tree: patch -p1 hunk#1@4818 hunk#2@5073 rc=0; zlib.ko build cc -D_KERNEL -DKLD_MODULE -Werror MAKE_RC=0; ng_deflate.ko NG_MAKE_RC=0; strings zlib.o => 'invalid distance too far back'.
↓ fix.diffDragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 (with-src baseline; NO kernel rebuilt/booted β€” the vulnerable path is latent in X86_64_GENERIC so a boot test would not exercise it; validation was harness before/after + kernel-tree zlib.ko/ng_deflate.ko module builds against the patched source)

Confirmed kernel references

Detail

Exploit chain

inflate OOB read via crafted raw-DEFLATE stream (windowBits<15, oversized distance) -> underflow past s->window into adjacent heap (up to ~32KB info-leak per malicious frame, or panic crossing into an unmapped page). Reachable only from an authenticated PPP peer when netgraph7_deflate is compiled/loaded (the only vulnerable caller, ng_deflate.c:270 inflateInit2(-windowBits)). LATENT in the shipped GENERIC kernel; no in-kernel primitive derivable on this config. No memory-corruption write primitive (read-only OOB), so no escalation chain to develop β€” impact ceiling is remote authenticated heap info-leak / DoS once the module is enabled.

Evidence (decisive lines)

BASELINE (unpatched, wbits=-8): '[harness] *** SIGSEGV/SIGBUS during inflate at 0x800480f01 ***' / 'nearest alloc #2 [user=0x800481000 size=256 (0x100)]: fault is -255 bytes (BEFORE-start (underflow into guard page))' / 'RESULT: OOB READ CONFIRMED' (deterministic 3/3). CONTROL (wbits=-15): 'inflate returned 1, msg=(null), total_out=916'. PATCHED HARNESS (wbits=-8): 'inflate returned -3, msg=invalid distance too far back, total_out=659' RUN_EXIT=0, NO fault (deterministic 3/3); wbits=-15 still 'inflate returned 1, total_out=916' (no regression). KERNEL-TREE: 'cd /usr/src && patch -p1' hunk#1@4818 hunk#2@5073 rc=0; 'make' in sys/net/zlib -> zlib.ko (44128B) + zlib.o with cc -D_KERNEL -DKLD_MODULE -Werror MAKE_RC=0; strings zlib.o contains 'invalid distance too far back'; ng_deflate.ko NG_MAKE_RC=0.

PoC changes

No changes to the .c/.sh/.py PoC sources (code_hash unchanged). fix.diff validated AS-IS (applies cleanly to both the harness zlib.c via patch -p3 and the kernel tree /usr/src via patch -p1; closes the OOB at harness level; zlib.ko + ng_deflate.ko compile clean). Updated VERDICT.md with a new Section 6 documenting the Phase 8 harness before/after + kernel-module build results; updated manifest.json (guest_uname, tested_at, fix_status=fixed, added fix_run.log + fix_build.log artifact entries). Added fix_run.log (full patched-harness output, deterministic x3) and fix_build.log (full patch -p1 + zlib.ko/ng_deflate.ko build output).

Verified recommended fix

In sys/net/zlib.c add a distance-bounds guard in BOTH consume sites: after the distance is fully decoded in inflate_codes (line 4820, before 'c->mode=COPY') insert 'if (c->sub.copy.dist > (uInt)(s->end - s->window)) { z->msg="invalid distance too far back"; c->mode=BADCODE; r=Z_DATA_ERROR; LEAVE }', and the mirror in inflate_fast (line 5063, before the copy) 'if (d > (uInt)(s->end - s->window)) { z->msg="invalid distance too far back"; UNGRAB; UPDATE; return Z_DATA_ERROR; }'. This mirrors modern zlib's 'dist > dmax' check (already present in sys/vfs/hammer2/zlib/) and uses s->end-s->window (the actual allocated window) so no new state is needed. matches finding markdown's short-term proposal (the markdown snippet showed only inflate_codes; this covers both paths). Long-term: replace the 28-year-old sys/net/zlib.c with the modern sys/contrib/zlib/ already in the tree. Full git-apply-able diff in findings/poc/DF-0265/fix.diff.

Verdict

REPRODUCED at the code level and fix VALIDATED. The harness links the byte-identical audited sys/net/zlib.c (md5 7a3d369127c0773f099c2ccf0b9972f1) into userspace and feeds a crafted raw-DEFLATE stream (windowBits=-8, distance ~658 >> 256-byte window). On the unpatched zlib.c, inflate SIGSEGVs at a fault address 255 bytes BEFORE the 256-byte sliding window (underflow into a guard page) β€” OOB READ CONFIRMED, deterministic 3/3 (run.log/run_stress.log). The -15 control (32KiB window) decompresses cleanly (Z_STREAM_END, total_out=916), isolating the cause to the missing dist<=window check at small windowBits. The defect is real in inflate_codes (sys/net/zlib.c:4822-4831) and inflate_fast (sys/net/zlib.c:5073-5088); the modern zlib copy in sys/vfs/hammer2/zlib/ HAS both checks, the 1.0.4 code has neither. LATENT on X86_64_GENERIC: sys/conf/files only compiles net/zlib.c for mxge (safe, wbits=15 from firmware inflateInit) or netgraph7_deflate (NOT built β€” no ng_deflate.ko, NETGRAPH7 absent from config); it goes live only if an operator builds/loads NETGRAPH7_DEFLATE. fix.diff adds the dist>(s->end-s->window) guard in BOTH inflate paths; validated harness-side (OOB gone) and kernel-tree (zlib.ko + ng_deflate.ko build clean with -Werror).