Home · ASPLOS 2025 · Security, Privacy & Trusted Execution

TaintEMU: Decoupling Tracking from Functional Domains for Architecture-Agnostic and Efficient Whole-System Taint Tracking

Lei Cui, Youquan Xian, Peng Liu and Longjin Lu

Conference
ASPLOS 2025
Published
2025
Pages
1235-1250
Citations
0

To watch how untrusted data flows through a whole running system, security tools run it inside an emulator and shadow every operation with taint-propagation logic — but that tracking logic is usually tangled into the emulator's own machinery, which ties it to one guest CPU architecture and makes it several times slower; this paper (Lei Cui, Youquan Xian, Peng Liu, Long Lu) presents TaintEMU, which fully separates the tracking from the functional emulation inside QEMU — pinning shadow state to host registers so it works for any guest architecture, and dedicating the host's idle vector units to tracking so it does not fight the real computation — cutting overhead from 301 percent down to 101 percent.

The argument in one glance

  1. Problem

    Watching untrusted data flow through a whole system is vital but slow and inflexible

    Many security analyses need to answer a flow question: if some data is untrusted — say it arrived from the network — where does it go as the system runs, and does it ever reach a place it should not, like a return address or a system call argument? Dynamic taint tracking answers this by marking that data as tainted and following it: every operation that consumes tainted data produces a tainted result, so the taint spreads through registers and memory exactly as the real data does. Whole-system taint tracking does this across the entire machine at once — the kernel, every process, drivers — not just one program, which is what lets it catch attacks and analyze malware that cross process and kernel boundaries. Because it must observe every instruction, it is built on a system emulator like QEMU: QEMU translates each guest instruction into host instructions to execute it, and the taint tracker piggybacks on that translation to also emit instructions that propagate taint. The problem is that this is both slow — often several times slower than plain emulation, because every operation now does double duty — and tied to specific guest CPU architectures, so a tool built for one does not easily work for another. Both limits trace back to how the tracking is built into the emulator.

  2. What people did

    Weave taint propagation into the emulator alongside the real computation

    The established way to build whole-system taint tracking is to instrument the emulator's translation process. As QEMU lowers each guest instruction through its intermediate representation into host code, the tracker adds extra operations that update shadow state — a parallel copy of memory and registers that stores a taint label for every real byte. Systems like DECAF and its successors follow this pattern, tightly interleaving the functional work (actually computing the program's result) with the tracking work (propagating taint), so that both happen together as the guest runs.

  3. Why it fell short

    Tightly coupling functional and tracking work makes it architecture-bound and heavy

    Interleaving the two kinds of work so tightly is the root of both problems. First, compatibility: the shadow state that holds taint labels is typically tied to the guest's registers, so the tracking machinery is written against a particular guest architecture's register layout and instruction set. Supporting a new guest architecture then means re-doing much of the tracking, which is why existing tools cover only a few architectures. Second, performance: the functional and tracking instructions share the same host resources — the same general-purpose registers and execution units — so they contend with each other. Every taint-propagation operation competes for the registers and issue slots the real computation needs, and the extra instructions must themselves be translated and scheduled through the emulator, piling overhead on overhead. The result is systems that can be several times slower than emulation alone — the paper cites a state-of-the-art baseline at 301 percent overhead — and that work only on a handful of guest CPUs. The two domains, functional and tracking, were never truly separated, and that entanglement is exactly what caps both their portability and their speed.

  4. This paper's idea

    Fully separate tracking from functional work, and give it its own host resources

    TaintEMU makes whole-system taint tracking architecture-agnostic and efficient by fully decoupling the two domains. It draws the separation at QEMU's TCG layer — the Tiny Code Generator, QEMU's intermediate representation between guest and host code. The key compatibility move is to map the shadow registers that hold taint to the host's registers rather than the guest's: because the taint state now lives against the fixed host architecture instead of the varying guest one, the same tracking machinery works no matter which guest CPU is being emulated. The key performance move is to physically isolate the two domains on the host: general-purpose instructions and registers are left to the functional domain (the real computation), while the host's vector resources — its wide SIMD registers and instructions, which the emulated program rarely needs — are dedicated to the tracking domain. Because tracking no longer reuses the same host resources as the real work, the two stop contending and tracking runs faster. Finally, TaintEMU generates the tracking instructions directly from TCG operations on the host, bypassing an extra round of translation and cutting overhead further. Implemented on an AMD64 host on QEMU 8.2.2, TaintEMU supports a wide range of guest architectures (x86, ARM, MIPS, RISC-V, PowerPC, and more), reduces performance overhead from 301 percent for a state-of-the-art baseline to 101 percent, and detects all vulnerabilities in tests covering 8 CVEs across 7 applications.

Why this problem is worth solving

Whole-system taint tracking is one of the most powerful lenses in security analysis, and its usefulness is bounded almost entirely by whether it is fast enough and portable enough to use.

Tracking how untrusted data propagates through an entire running machine is uniquely revealing. It can catch an exploit at the moment tainted input reaches a control-flow-sensitive location, expose how malware moves data between processes and the kernel, and reveal information leaks that span the whole system rather than one program. Doing this at whole-system scope, across kernel and user space together, is what makes it catch behaviors that single-process tools miss. But that power comes with two costs that directly limit adoption. The first is speed: because the analysis must shadow every instruction with taint propagation, a naive design multiplies the work of every operation, and running an entire operating system several times slower than normal makes many analyses impractically slow or changes the timing enough to alter the behavior being studied. The second is portability: security researchers care about many architectures — servers on x86, phones and embedded devices on ARM, network gear on MIPS or PowerPC, new systems on RISC-V — and a taint tracker locked to one guest architecture simply cannot be pointed at the others. So the value of the technique is real but gated: reduce the overhead and remove the architecture lock-in, and a powerful analysis that was confined to a few slow setups becomes broadly usable. That is exactly the gate TaintEMU targets.

The deeper insight is that both limits come from a single architectural mistake — mixing two different jobs into one — and that separating them cleanly fixes both at once.

It is tempting to treat portability and performance as separate engineering problems, each needing its own fix. TaintEMU’s framing is that they are two symptoms of the same underlying entanglement: the functional job (emulating what the program actually computes) and the tracking job (propagating taint) are woven together, sharing both their representation and their hardware. That shared representation ties the taint state to guest registers, which is what breaks portability; that shared hardware makes tracking contend with computation, which is what kills performance. Pull the two jobs apart and both symptoms dissolve. Decoupling at the emulator’s intermediate layer lets the tracking state be defined against the host instead of the guest, so it no longer cares what guest CPU is running. Decoupling on the physical hardware lets tracking use resources the functional work does not — the idle vector units — so it no longer steals from the real computation. This is a general lesson in system design: when one mechanism is forced to serve two distinct purposes, its worst limitations often come from that overloading, and cleanly separating the purposes, each onto resources suited to it, can lift several constraints simultaneously. TaintEMU’s contribution is to identify functional-versus-tracking as exactly such an overloaded seam in whole-system analysis, and to cut it at both the software representation and the hardware.

What people did before, and where it broke

  • Instrument the emulator to propagate taint inline (DECAF and successors). As the emulator translates each guest instruction, emit extra operations that update shadow taint state alongside the real computation. Where it broke. Functional and tracking work are tightly coupled, which is the source of both the architecture lock-in and the heavy overhead.
  • Tie shadow state to guest registers. Store taint labels against the guest CPU’s registers and layout. Where it broke. The tracking logic becomes specific to one guest architecture, so supporting another means largely rewriting it — which is why tools cover only a few architectures.
  • Run tracking on the same host resources as the functional work. Let taint-propagation instructions use the same general-purpose registers and execution units as the real computation. Where it broke. The two contend for registers and issue slots, and the extra instructions add translation and scheduling cost, together pushing overhead to several times that of plain emulation.
  • Translate tracking instructions through the normal pipeline. Generate taint operations the same way as functional ones, through the full translation path. Where it broke. This adds another layer of translation overhead on top of the propagation work itself.
  • The gap. No whole-system tracker cleanly separated the functional and tracking domains — both in how taint state is represented and on which hardware it runs — so portability and performance stayed coupled to a single entangled design.

How TaintEMU works

From tracking tangled into emulation to fully decoupled tracking

  1. new

  2. new

  3. new

  4. new

  5. new

The idea

Track how untrusted data flows to catch security problems. At its core TaintEMU is a taint-tracking system: it marks untrusted data and follows its propagation to reveal when it reaches somewhere dangerous. Marking data as tainted and tracing its flow through a program to expose vulnerabilities and unsafe uses is the same information-flow-tracking idea the work on inferring intermediate taint sources for vulnerability detection (FITS) covered elsewhere on this site is built on, using taint propagation as a lens on security-relevant data movement. TaintEMU brings that lens to the whole system at once, and focuses its contribution on making the tracking fast and portable enough to actually run.

Decouple two jobs that were fused into one. TaintEMU’s central move is to stop interleaving functional emulation with taint tracking and instead separate them cleanly, so each can be built and run on its own terms. Splitting a monolithic mechanism into decoupled parts so that each part can be organized and resourced for what it specifically needs, instead of compromising as one unit, is the same decoupling strategy the work on a decoupled architecture for out-of-core random walks (NosWalker) covered elsewhere on this site is built on, separating concerns to lift the limits their entanglement imposed. TaintEMU decouples functional from tracking at both the representation and the hardware, and that single separation is what frees both portability and speed.

Press the machine’s idle vector units into non-numeric service. TaintEMU speeds up tracking by moving it onto the host’s SIMD vector resources, which the emulated program seldom uses, so taint propagation runs on hardware that would otherwise sit idle. Repurposing wide vector (SIMD) units to accelerate a task they were not designed for, exploiting spare parallel hardware for a non-arithmetic job, is the same use-the-vector-lanes idea the work on SIMD-accelerated matching over structured data (SIMD-accelerated JSONPath) covered elsewhere on this site pursues, turning vector units to an unconventional purpose. TaintEMU dedicates those units to taint tracking, both accelerating it and keeping it out of the functional work’s way.

Following a tainted operation through TaintEMU

From a guest instruction to its taint being propagated off to the side

An illustration, at the level the paper's abstract describes, of how TaintEMU keeps functional and tracking work separate. The full paper was not available for this explainer, so internal mechanism details are omitted.

Step 1 of 5

A guest instruction enters QEMU's translator

The guest system executes an instruction — say one that combines two values — and QEMU lowers it through its TCG intermediate representation on the way to host code, as it would for ordinary emulation.

TCG is the neutral layer where TaintEMU draws its separation.

Why it works

  • Host-relative shadow state frees it from the guest architecture. Guest-tied taint state must be rewritten per architecture → but mapping shadow registers onto the host instead → so the same tracking works for x86, ARM, MIPS, RISC-V, and PowerPC alike.
  • Separate hardware stops the two domains contending. Sharing host registers makes tracking fight the real computation → but dedicating the idle vector units to tracking → so taint propagation runs without stealing from functional work.
  • Decoupling at the TCG layer cleanly divides the jobs. Interleaved functional and tracking code entangles both concerns → but splitting them at QEMU’s intermediate representation → so each can be organized and resourced independently.
  • Direct instruction generation removes a translation layer. Routing tracking through the full pipeline adds overhead → but emitting tracking instructions straight from TCG operations → so the propagation avoids an extra round of translation.
  • Attacking the shared root fixes both symptoms at once. Portability and speed looked like separate problems → but both came from the functional-tracking entanglement → so one clean decoupling lifts both limits together.

What it costs (trade-offs and scope)

  • It still roughly doubles execution time. TaintEMU cuts overhead from 301 percent to 101 percent, a large improvement, but 101 percent still means the tracked system runs about twice as slow as plain emulation — taint tracking remains expensive, just far less so.
  • Dedicating vector units assumes they are free. The performance win relies on the guest program rarely needing the host’s vector resources; a guest workload that heavily uses vector computation could contend for those units and erode the benefit.
  • It is built on and tied to QEMU’s TCG. The approach is implemented at QEMU’s TCG layer on an AMD64 host, so it is specific to that emulation framework and host architecture rather than a universal technique.
  • Guest-architecture support still requires front-end work. Being architecture-agnostic for tracking does not remove QEMU’s own need to support a guest; the claim is that the tracking machinery ports across guests, not that any guest works for free.
  • This explainer is built from the abstract only. The exact TCG-layer design, the shadow-register mapping and vector encoding of taint, the direct-generation mechanism, the benchmarks, and the CVE detection details are in the full paper, which was not available here; only the abstract’s stated design and headline numbers are reported.

The comparison

Building whole-system taint tracking on an emulator

PropertyInline coupled trackingGuest-tied shadow stateTaintEMU
Functional and tracking work
Where shadow state lives
Host resources for tracking
Guest architecture coverage
Reported overhead
A comparison of ways to build whole-system taint tracking on an emulator. Inline approaches interleave taint propagation with the functional emulation and tie shadow state to guest registers, which locks them to a few guest architectures and makes them several times slower (a state-of-the-art baseline at 301 percent overhead). TaintEMU fully decouples the two domains at QEMU's TCG layer — mapping shadow state to host registers for guest-agnostic tracking, dedicating the host's idle vector units to tracking to avoid contention, and generating tracking instructions directly — supporting many guest architectures and cutting overhead to about 101 percent while detecting all vulnerabilities across 8 CVEs and 7 applications. Exact figures should be read from the paper.Underlined values explain themselves when clicked.

Check yourself

Check your understanding

  1. 1. What is whole-system taint tracking, and why is it built on an emulator?

  2. 2. Why do existing whole-system taint trackers suffer from both limited architecture support and heavy overhead?

  3. 3. What are TaintEMU's two key decoupling moves?

  4. 4. What did TaintEMU achieve, and how should this page be read?

Sources

The paper is “TaintEMU: Decoupling Tracking from Functional Domains for Architecture-Agnostic and Efficient Whole-System Taint Tracking” by Lei Cui, Youquan Xian, Peng Liu, and Long Lu, published at ASPLOS 2025, DOI 10.1145/3676641.3716023.

This explainer is written only from the paper’s abstract and TLDR, obtained via the Semantic Scholar API; the full text was not available, because the paper is behind the ACM Digital Library and no open preprint was reachable at the time of writing. Accordingly this page is marked a draft. The abstract describes TaintEMU as an architecture-agnostic and efficient whole-system taint tracker that fully decouples the functional and tracking domains: it separates functional and tracking logic at the QEMU TCG layer and maps shadow registers to host rather than guest registers for cross-architecture compatibility; at the host layer it physically isolates the domains, dedicating general-purpose resources to functional work and vector resources to tracking to avoid contention; and it generates tracking instructions directly from TCG operations to bypass extra translation. Implemented on an AMD64 host on QEMU 8.2.2, it supports a range of guest architectures, reduces performance overhead from 301 percent (for the DECAF++ baseline) to 101 percent, and detects all vulnerabilities in tests with 8 CVEs across 7 applications. Background on taint tracking, QEMU, the TCG intermediate representation, and shadow memory is standard, widely-known context. All quantitative claims are the paper’s own; the internal mechanisms and full evaluation should be confirmed in the paper.

Related papers on Security, Privacy & Trusted Execution

See all 153 →