How Fence2Pwn Turns Sampling Into a Reuse Signal

This chapter explains the mechanism that connects KFENCE’s production sampling to Fence2Pwn’s controlled-reuse claim. The specific question is how a technique can infer that an allocation took the KFENCE route, shape the pool’s state, and later reach a freed slot without assuming that the ordinary slab allocator has abandoned its hardening. The answer is a three-part dependency—calibration, massaging, and rotation—whose success depends on timing, pool state, object placement, and the lifecycle of a separate use-after-free.

The explanation is intentionally about causality rather than an exploit recipe. Fence2Pwn is significant because it composes properties that were introduced for diagnosis: a periodic sampling decision, a shared pool, persistent freed slots, and continued execution after reports. It is conditional because each property can be disturbed by an unsuitable vulnerability, an unexpected allocation, system load, or a configuration change.

The Sampling Pattern Becomes a Signal

KFENCE is integrated into the main allocation path, so a caller does not have to request a visibly different API when a sampled allocation occurs. Most requests continue to ordinary slab service. When the sampling gate opens, however, the next eligible request may be diverted to the KFENCE pool. That detour performs additional work: it manages pool metadata, changes page accessibility, initializes a guarded object page, and records information needed for later diagnostics. Those operations can make the sampled request take longer than a comparable slab-served request.

The paper treats this latency difference as allocation-path observability. In a privileged measurement, the researchers knew which allocator served each request and could compare the timing profiles. KFENCE-served allocations showed higher latency and recurring spikes. The cadence matched the sampling configuration in the tested desktop setup: periodic spikes appeared once per 100 allocations when allocations were issued at roughly one per millisecond, corresponding to a 100-millisecond interval.

That observation alone would not be enough if only privileged kernel code could see it. The paper therefore measured unprivileged operations that cause kernel allocations, including setgid and msgsnd. Their latency traces displayed the same kind of periodic pattern. The experiment used unprivileged cycle counters—rdtsc on x86-64 and the arm64 virtual counter on arm64—so the signal was not limited to an instrumented kernel module. The arm64 counter was less precise, but the paper reports that it was sufficient for detecting the pattern and synchronizing with allocation windows in the evaluated Android configuration.

The important word is “pattern,” not “signature.” A slow allocation can have many causes: scheduling, contention, page faults, cache effects, or unrelated allocator work. Fence2Pwn’s calibration step uses repeated observations to separate the periodic behavior associated with KFENCE from ordinary noise. The goal is to estimate when the sampling gate is likely to be useful, not to prove from one timing measurement that a particular request definitely entered the pool.

The paper models the expected activations as a recurring sequence. Once an initial sampled event has been observed, later opportunities can be estimated by adding the configured interval. In the desktop environments evaluated by the authors, that interval was 100 milliseconds; for the Android GKI configuration, the paper reports 500 milliseconds. The values demonstrate the mechanism’s dependence on configuration. They should not be treated as constants of KFENCE or as a universal timing guarantee.

Calibration therefore has two jobs. First, it estimates the period at which the global sampler creates an opportunity. Second, it accounts for the distance between that opportunity and the particular allocation of interest. A vulnerable object may be the first eligible allocation in a kernel call path, or unrelated allocations may occur before it. The attacker’s timing estimate must then be interpreted relative to the call path rather than to the start of a userspace operation alone.

The distinction between global and local state matters here. KFENCE’s sampling mechanism is global, while a userspace operation is local to one process and one kernel interface. Other processes and subsystems can consume sampled opportunities.