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

hrtimer_start_range_ns corrupts per-CPU systimer queue by calling systimer_init_oneshot without prior systimer_del on an armed timer

Summary

hrtimer_start_range_ns calls systimer_init_oneshot(&timer->st,...) at line 115 without first calling systimer_del to remove any previously-armed systimer from per-CPU queue. systimer_init_oneshot (kern_systimer.c:363) executes bzero(info sizeof(struct systimer)) which zeroes TAILQ_ENTRY(node) linkage and SYSTF_ONQUEUE flag while systimer may still be linked into gd->gd_systimerq. Neighboring queue entries retain stale tqe_next/tqe_prev pointers to this entry creating corrupted doubly-linked list causing infinite loops NULL dereferences or stale-pointer traversals in systimer_intr. systimer_add KKASSERT((info->flags & SYSTF_ONQUEUE)==0) PASSES because flags just zeroed masking corruption. Triggered by any caller invoking hrtimer_start on timer whose systimer currently armed. i915 forcewake path concrete trigger: fw_domain_arm_timer (intel_uncore.c:74-81) calls hrtimer_start_range_ns unconditionally whenever wake_count drops to 0 without checking if timer already armed. During normal GPU operation forcewake get/put cycles complete well within 1ms timeout causing arm_timer while previous systimer still on queue. Attacker local access to i915 hardware triggers via any GPU operation requiring forcewake. Impact: corrupted systimer queue causes systimer_intr infinite-loop (system hang) NULL-deref (kernel panic) or traverse stale pointers into freed/reused memory (corruption potential code execution).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2175 Β· 6 files
FileTypeDescriptionSize
VERDICT.md verdict source-level analysis with path:line citations 1.9 KB ↓ raw
reachability.txt environment guest PCI/device survey proving no required HW 1.6 KB view raw
fix.diff suggested-fix git-apply-able fix (validated: applies clean) 328 B view raw
build.sh build-log documents HW requirement 550 B view raw
run.sh run-log documents HW requirement 272 B view raw
env.txt environment guest uname and environment 491 B view raw
VERDICT.md verdict source-level analysis with path:line citations
↓ download raw

DF-2175: hrtimer_start_range_ns corrupts per-CPU systimer queue

Verdict: NOT REPRODUCED (HW-gated) β€” source-confirmed real bug

Reachability

NOT reachable on this QEMU guest. hrtimer_start_range_ns() is in sys/dev/drm/linux_hrtimer.c, part of drm.ko. Used by DRM GPU drivers. Without GPU hardware, no hrtimers are started via this path.

Mechanism (source-confirmed)

hrtimer_start_range_ns() at linux_hrtimer.c:87-119:

void hrtimer_start_range_ns(struct hrtimer *timer, ...) {
    ...
    lwkt_gettoken(&timer->timer_token);
    timer->cancel = false;
    timer->running = false;
    timer->active = true;
    timer->gd = mycpu;
    systimer_init_oneshot(&timer->st, __hrtimer_function, timer,
        timer->timeout_us);    // ← line 115: no prior systimer_del!
    lwkt_reltoken(&timer->timer_token);
}

systimer_init_oneshot() at kern_systimer.c:360 does bzero(info, sizeof(struct systimer)) which zeroes the TAILQ_ENTRY linkage fields of timer->st. If timer->st was already enqueued in a per-CPU systimer queue (from a previous hrtimer_start call), this bzero corrupts the queue by severing the linked-list node without removing it from the queue.

Effects: - The per-CPU systimer list is corrupted (dangling pointers in TAILQ) - The old systimer entry is orphaned (may fire with garbage data) - Subsequent systimer operations on that CPU may panic or loop

This happens whenever hrtimer_start is called on a timer that's already armed β€” e.g. re-scheduling a display vblank timer or a hardware poll timer.

Primitive

  • Class: memory corruption (per-CPU systimer queue corruption via bzero of linked node)
  • Corrupts TAILQ_ENTRY links β†’ linked list corruption β†’ potential arbitrary code execution when the corrupted list is traversed

Fix

fix.diff: Call systimer_del(&timer->st) before systimer_init_oneshot() if the timer was previously active:

if (timer->active)
    systimer_del(&timer->st);

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

git apply --check clean + drm.ko compiles

git apply --check clean + drm.ko compiles

Confirmed kernel references

β€”

Detail

Exploit chain

none (HW-gated)

Evidence (decisive lines)

HW-GATED (no GPU). Source-confirmed: hrtimer_start_range_ns systimer_init_oneshot without prior systimer_del -> bzero of queued systimer TAILQ_ENTRY -> queue corruption.

Verified recommended fix

HW-GATED (no GPU). Source-confirmed: hrtimer_start_range_ns systimer_init_oneshot without prior systimer_del -> bzero of queued systimer TAILQ_ENTRY -> queue corruption.

Verdict

HW-GATED (no GPU). Source-confirmed: hrtimer_start_range_ns systimer_init_oneshot without prior systimer_del -> bzero of queued systimer TAILQ_ENTRY -> queue corruption.