DF-5135 / verdict.json
{ "finding_id": "DF-5135", "status": "reproduced", "reproduced": 1, "impact": "none", "confidence": "certain", "verdict": "TUNABLE_bool (sys/dev/drm/include/linux/moduleparam.h:41) casts 1-byte _Bool module params to (int *) and kgetenv_int() stores 4 bytes, so setting any i915 bool tunable rewrites the following params of struct i915_params. Reproduced live on the stock guest i915.ko: kenv KBUILD_MODNAME.verbose_state_checks=1 before kldload silently flipped enable_dp_mst (offset 114, default true) to 0 while verbose_state_checks (@112) itself was being set \u2014 the 4-byte store spanned bytes 112..115. Contained corruption (bools are the tail members; last bools write ends in padding \u2014 sizeof=120, verified), so impact is silent misconfiguration of unrelated params plus a latent landmine for future bool params with non-padded neighbours. Root/boot-tunable trigger only. Fix (byte-safe TUNABLE_bool via SYSINIT narrowing) validated on a rebuilt i915.ko: enable_dp_mst stayed 1.", "exploit_chain": "root sets boot/loader kenv tunable for one bool param (names are mangled to KBUILD_MODNAME.<param> in the shipped module because -DKBUILD_MODNAME never reaches i915_params.c) -> tunable_int_init at module load -> kgetenv_int 4-byte store into 1-byte _Bool -> up to 3 neighbouring bool params silently zeroed/corrupted.", "evidence": "run.log: baseline enable_dp_mst=1, then after kenv KBUILD_MODNAME.verbose_state_checks=1 + reload: enable_dp_mst=0 (corrupted); build.log: layout.c output (sizeof(bool)=1, struct=120, offsets 110-116); fix_run.log: patched i915.ko keeps enable_dp_mst=1 under the identical trigger.", "kernel_refs": [ "sys/dev/drm/include/linux/moduleparam.h:41", "sys/dev/drm/i915/i915_params.c:80", "sys/dev/drm/i915/i915_params.c:112", "sys/dev/drm/i915/i915_params.h:73", "sys/kern/kern_environment.c:527", "sys/sys/stdint.h:58" ], "poc_changes": "PoC written from scratch. First attempt used the guessed tunable name i915.error_capture \u2014 no-op because (a) CONFIG_DRM_I915_CAPTURE_ERROR compiles that params registration out and (b) macro-generated names are mangled. strings(1) on the shipped i915.ko revealed the real names (KBUILD_MODNAME.<param>, unsafe params as KBUILD_MODNAME.(<param>)); switched the trigger to KBUILD_MODNAME.verbose_state_checks whose corruption target (enable_dp_mst, default true) is observably non-default.", "attempts": 3, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 500, "guest_dirty": 0, "build_cmd": "cc -O -o layout layout.c && printf KMOD=\\ti915probe\\nSRCS=\\ti915_probe.c\\n\\n.include <bsd.kmod.mk>\\n > Makefile && make", "run_cmd": "kenv KBUILD_MODNAME.verbose_state_checks=1 && kldload i915 && kldload ./i915probe.ko && sysctl hw.i915probe.params", "code_hash": "3263250cc200ed03243eed15c2e111392e85cb19d40610aa19e033044c079983", "notes": "Also documented: TUNABLE_charp is a no-op (firmware-path params unimplementable), and the module_param mode argument (0400/0600/0644) is ignored entirely \u2014 all params are boot-time kenv tunables, root-set only, so no unprivileged surface exists in this file beyond the mangled-name quirk. Guest reset clean after validation.", "recommended_fix": "Make TUNABLE_bool fetch into an int and narrow the store to the _Bool (see fix.diff); ideally also give bool params sane registered names and pass the mode through.", "fix_status": "fixed", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff replaces TUNABLE_bool with a SYSINIT that does TUNABLE_INT_FETCH into an int then (var) = !!__tv (preserving the compiled-in default when unset). Force-rebuilt i915.ko on the guest, rebooted, re-ran the identical kenv trigger: enable_dp_mst stayed 1 (no neighbour corruption); stock module flipped it to 0 minutes earlier on the same guest.", "fix_evidence": "fix_run.log (enable_dp_mst=1 ... INTACT); fix_build.log (header patch + i915_params.o forced recompile + install).", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0 (same base kernel; /boot/kernel/i915.ko rebuilt from patched moduleparam.h)" } |