โฌข DragonFlyBSD Kernel Audit
DF-4812 / run.log
โ† back to finding โ†“ download raw
DF-4812 run log (full untrimmed console output of the decisive runs)
=====================================================================
Guest: DragonFly dfbsd 6.5-DEVELOPMENT #0 (in-guest built kernel, X86_64_GENERIC)
Setup: guest booted with QEMU_EXTRA="-acpitable file=.../ssdt_tosh.aml"
       (SSDT v02 AUDIT TOSHCI defines \TSH0 with _HID=TOS6200; GHCI returns a
       3-element package instead of the 6 the driver requires; ENAB returns 0)
Driver attach:
  # kldload acpi_toshiba
  acpi_toshiba0: <Toshiba HCI Extras> on acpi0
  # devinfo -v | grep -i tosh
      acpi_toshiba0 pnpinfo _HID=TOS6200 _UID=0 at handle=\TSH0

Single-read behavior (NOTE: DF sysctl(8) silently swallows failed leaf reads โ€”
show_var() does `if (i || !len) { error = 1; goto done; }` with no message and
main() returns warncount=0, so the trigger leaves NO trace for the victim user;
each sysctl(8) invocation performs TWO handler calls: size-estimate + real):
  $ sysctl hw.acpi.toshiba.force_fan
  rc=0   (no output)
  # dmesg | tail -2
  toshiba: invalid package!          <-- acpi_toshiba.c:438, the leak path
  toshiba: invalid package!

---------------------------------------------------------------------
RUN 1 (BASELINE, unprivileged user "maxx", 20,000 reads of force_fan)
  before :              acpica      469   46.0K       0    390M     221K
  command:  $ i=0; while [ $i -lt 20000 ]; do \
                sysctl hw.acpi.toshiba.force_fan >/dev/null 2>&1; i=$((i+1)); done
  after  :              acpica    39.5K   3.71M       0    390M     572K
  DELTA  : +39,031 M_ACPICA objects, +3.66 MB leaked (~190 B / invocation,
           ~2 objects/invocation = 1 object per hci_call() โ€” matches the two
           handler calls per sysctl(8) invocation)

---------------------------------------------------------------------
RUN 2 (BASELINE stress, unprivileged, 20,000 iters x 2 nodes = 40,000 reads)
  before :              acpica    39.5K   3.71M       0    390M     572K
  command:  $ i=0; while [ $i -lt 20000 ]; do \
                sysctl hw.acpi.toshiba.force_fan >/dev/null 2>&1; \
                sysctl hw.acpi.toshiba.lcd_brightness >/dev/null 2>&1; i=$((i+1)); done
  after  :              acpica     118K   11.0M       0    390M    1.25M
  DELTA  : +78.5K objects, +7.3 MB โ€” linear, unbounded

  total markers in msgbuf after runs: 40,283 x "toshiba: invalid package!"
  (msgbuf is a wrap-around ring; 60,000 invocations x 2 calls each)

---------------------------------------------------------------------
FIX VALIDATION (same guest, same SSDT, same load)
  # cd /usr/src && patch -p1 < /tmp/df4812/fix.diff
  (hunk #1 succeeded at 434 โ€” adds AcpiOsFree(results.Pointer) before the
   early `return (ENXIO)`)
  # cd /usr/src/sys/dev/acpica/acpi_toshiba && make obj && make   [see fix_build.log]
  # kldunload acpi_toshiba
  # kldload /usr/obj/usr/src/sys/dev/acpica/acpi_toshiba/acpi_toshiba.ko

  post-swap baseline:   acpica     118K   11.0M       0    390M    1.32M
                       (the 11 MB leaked by the baseline module is of course
                        not recovered retroactively โ€” it stays allocated)

RUN 3 (PATCHED, identical load: 20,000 iters x 2 nodes = 40,000 reads)
  command:  $ i=0; while [ $i -lt 20000 ]; do \
                sysctl hw.acpi.toshiba.force_fan >/dev/null 2>&1; \
                sysctl hw.acpi.toshiba.lcd_brightness >/dev/null 2>&1; i=$((i+1)); done
  after  :              acpica     118K   11.0M       0    390M    2.00M
  DELTA  : 0 objects, 0 bytes โ€” FLAT.
           Requests counter climbed 1.32M -> 2.00M (~680K more allocations
           serviced), and dmesg still shows fresh "toshiba: invalid package!"
           markers, proving the same code path executed and now frees.

---------------------------------------------------------------------
Conclusion: unauthenticated local, silent, unbounded kernel heap (M_ACPICA)
leak of ~190 bytes per sysctl(8) invocation on any machine whose Toshiba GHCI
implementation answers with a package of < 6 elements; one-line fix verified:
leak gone, behavior otherwise unchanged.