Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM
summary
The gist
The gist The research presents KCOV-DATAFLOW, an LLVM-based instrumentation framework that extends Linux KCOV with data-flow extraction of function arguments and return values to provide state-aware
In short
The research introduces KCOV-DATAFLOW, an LLVM-based framework that extends Linux KCOV by extracting data flow information from function arguments and return values. This provides fuzzers with state-aware feedback for better mutation guidance and gives security analysts deterministic records for root-cause analysis. It bridges the gap between coverage tracing and data flow analysis.
Key concepts
- KCOV-DATAFLOW
- A framework that extends Linux KCOV by adding data flow extraction for function arguments and return values. It generates state-aware feedback for fuzzers to guide mutations and provides deterministic records for security analysts without needing source code annotations.
- DICompositeType Metadata
- Metadata within LLVM that describes complex types like structs or unions. The framework uses this metadata to automatically extract field byte offsets and sizes, allowing it to capture struct fields during function calls without manual source annotation.
- Lock-free Per-Task Ring Buffer
- A kernel mechanism used to transport variable-length execution records from the kernel into user space safely. It operates independently of existing KCOV or syzkaller tools, ensuring that fuzzing and analysis can occur concurrently without interference.
- Boundary Contracts C(f) = (P, Q)
- A formal way to define what should happen at a function boundary. P is the precondition (what inputs are valid), and Q is the postcondition (what the return value should be). This allows for runtime verification to detect violations of expected logic.
Terminology used across episodes
This episode discusses
- Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM · Paper Radio
The paper
Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM · Read on arXiv
Ericsson Software Technology
Coverage-guided kernel fuzzers such as syzkaller rely on edge coverage trace-pc as their sole feedback signal. This context-blind approach cannot distinguish execution paths that differ only in argument values. For example, two invocations of copy from user with different size parameters hit identical basic blocks yet have vastly different security implications. I present, an LLVM-based instrumentation framework that extends Linux KCOV with data-flow extraction of function arguments and return values. A compiler pass emits lightweight callbacks that report one source-level parameter per call, passing the value itself in a register together with its index and byte size. A composite is instead reported by the address of the object holding it, paired with a constant table of field (offset, size) pairs derived from DWARF DICompositeType metadata, with zero source annotation. The callbacks carry no program counter. The kernel derives it from the return address, which also attributes records the compiler emitted from inside an inlined body to the callee that was inlined. A lock-free per-task record buffer delivers variable-length records to user space with no interference to existing KCOV or syzkaller infrastructure, carrying entry, return, and comparison-operand records in one unified stream. I demonstrate dual utility: (1) fuzzers gain state-aware feedback for mutation guidance into value-dependent state transitions, and (2) security analysts obtain deterministic argument records for root-cause analysis without printk or kprobe overhead.
Transcript
Introduction to the show: ident: Security Radio. Generated commentary on the latest security and cryptography papers.
Nadia: Today's paper: "Beyond Edge Coverage".
Elias: The gist The research presents KCOV-DATAFLOW,
Nadia: First, who's behind it and why it matters.
Title and authors: Nadia: So, we're looking at this paper called "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM." It’s about taking KCOV and adding something that looks inside the function arguments and what they return.
Elias: Exactly. The core idea is that existing coverage tools, like syzkaller, they only see the control flow edges—what code path you took. This paper suggests those edges can be misleading because two different inputs might take the same path but have totally different security consequences for things like copy from user operations.
Nadia: Right. It’s about that state awareness. They introduce KCOV-DATAFLOW, which uses LLVM to do this extraction of arguments and return values, which gives fuzzers a much better signal than just hitting the same basic block repeatedly <ref:2606.00455#pg1>.
Elias: And they build this whole system in three layers: first a compiler pass that emits callbacks, then a lock-free ring buffer for kernel communication, and finally a user space interface for both fuzzers and analysts <ref:2606.00455#pg2>. It’s designed to work without any source-level annotations.
Priya: From my side, what I’m looking at is how this data flows. The paper shows they use DWARF metadata to automatically decompose composite types, like structs or unions, which is pretty slick for capturing those field values <ref:2606.00455#pg2>.
Nadia: It means when you fuzz something, the fuzzer doesn't just see that it hit a function; it gets information about *which* specific arguments were used and what they contained, which helps guide the mutation into states that actually matter <ref:2606.00455#pg1>.
Elias: And for security analysts, this is huge because they get deterministic records of inputs and outputs without needing to add slow printk or kprobe overhead to their systems <ref:2606.00455#pg2>.
Priya: That deterministic record is what lets them check invariants, like making sure that the sum of a length field and a payload doesn't exceed the total length in a process message handler <ref:2606.00455#pg3>. That’s where the real value for auditing comes from.
Nadia: So, what they actually do is capture tuples like program counter, argument metadata, and field values at every function entry and return point <ref:2606.00455#pg2>. They show this with an example involving SMB2 protocol stages leading up to a vfs open call <ref:2606.00455#pg3>.
Title and authors: Elias: The paper highlights that edge coverage can saturate on the handshake sequence, but data-flow extraction reveals security-relevant differences inside fields like DesiredAccess in the SMB2 CREATE function <ref:2606.00455#pg3>. That’s the point they are making about what edge coverage misses.
Priya: I'm interested in how they handle the complexity of Rust, since that’s a big area for kernel work, and it seems like this framework has paths for both post-compilation and native instrumentation <ref:2606.00455#pg2>.
Nadia: They really did tackle that Rust issue because existing tools like drgn/vmcore struggle with DWARF elision when you’re running at-O2, and this paper shows how they solve that with a custom LLVM build <ref:2606.00455#pg2>.
Elias: And the performance numbers are interesting because they show a micro-benchmark result of about twenty-seven nanoseconds per individual callback when running over five thousand iterations <ref:2606.00455#pg1>. That’s pretty fast for getting this kind of detail in.
Priya: But we have to consider the overhead when you enable everything, because the global enablement shows a nine point five percent increase in vmlinux text size and a seventy-one percent increase in boot time if recording is off <ref:2606.00455#pg1>. So it’s definitely not something you can just turn on and forget about.
Nadia: It sounds like the authors are focusing on making this useful for targeted investigations and short fuzzing campaigns because of that overhead profile <ref:2606.00455#pg1>.
Elias: They also mention they verify correctness by matching their ENTRY and RET records against printk ground truth for five vulnerability classes in both C and Rust kernel modules <ref:2606.00455#pg3>. That’s a strong validation point.
Priya: And they show that this data-flow context provides information unavailable through any combination of existing tools when looking at five different classes of vulnerabilities <ref:2606.00455#pg1>. That's what really sells the utility for security analysts, giving them evidence that static review alone can’t provide at-O2.
Nadia: So, to summarize this paper "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM," it’s an LLVM framework that adds data-flow extraction to KCOV so fuzzers get state awareness and analysts get deterministic records <ref:2606.00455#pg1>.
Title and authors: Elias: And the improvements they propose are focused on making the feedback for fuzzers more useful by capturing value-dependent transitions, and giving analysts the ability to verify pre and post conditions formally <ref:2606.00455#pg3>.
Priya: The paper also suggests a way to use this structured output for offline contract verification, where you check recorded execution against formal specifications after the fact <ref:2606.00455#pg3>. That shifts the workflow toward automatically verifying known contracts instead of just waiting for observations.
Nadia: The conclusion is that KCOV-DATAFLOW bridges the gap between coverage-guided fuzzing and data-flow analysis for kernels by verifying pre and postcondition contracts at function boundaries without needing source modifications <ref:2606.00455#pg1>.
Elias: It offers reproducible evidence grounded in physical execution, which is important for empirical security research because the dataflow records are deterministic artifacts <ref:2606.00455#pg1>.
Priya: I just think the implication is that this structured output makes it amenable to automated reasoning tools, meaning you can feed these records into model checking systems instead of manually parsing logs <ref:2606.00455#pg3>.
Nadia: So, to wrap up on "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM," it’s a way to get state information from kernel functions at runtime that existing coverage tools miss <ref:2606.00455#pg1>.
Elias: It gives fuzzers better guidance by showing them how argument values change the outcome, and it gives analysts deterministic records for root-cause analysis without adding significant overhead <ref:2606.00455#pg2>.
Priya: And it lets us check cross-field invariants, like ensuring that a total length constraint is met between an entry and a return value <ref:2606.00455#pg3>.
Nadia: It’s about moving beyond just seeing what code path you took to actually understanding the data that flowed through it <ref:2606.00455#pg1>.
Elias: The paper shows this is achievable via an LLVM extension and a kernel ring buffer mechanism that works safely in process context <ref:2606.00455#pg2>.
Priya: It really bridges that semantic gap between coverage guidance and data-flow analysis for operating system kernels <ref:2606.00455#pg1>.
Nadia: That’s it for this paper, "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM." We'll be diving into something new next time.
The paper's summary: Nadia: So, this paper is about taking existing KCOV coverage data and making it smarter by digging into the actual data flowing through kernel functions, like what arguments are used and what they come back as.
Elias: Right, it’s about moving beyond just knowing which code path you took to understanding the specific inputs that caused that path. They call this KCOV-DATAFLOW, an LLVM framework for extracting argument and return values.
Priya: And what I find interesting is how they do the extraction automatically without needing any source code annotations from the developers. It uses DWARF metadata to figure out those struct fields and their sizes on its own.
Nadia: That’s a big deal because it means fuzzers get this state-aware feedback, which lets them guide mutations into places that actually matter for security <ref:2606.00455#pg1>.
Elias: And for the analysts, they get deterministic records of those inputs and outputs without having to set up slow printk or kprobe tools on top of their systems <ref:2606.00455#pg2>.
Priya: That deterministic evidence is what lets people check specific invariants, like making sure a total length calculation stays correct between an entry point and a return value <ref:2606.00455#pg3>.
Nadia: It’s not just about seeing the control flow edge, it’s about seeing which argument carried the bad value or what the function actually returned after being corrupted <ref:2606.00455#pg1>.
Elias: The authors show they verified these records against printk ground truth for five different classes of bugs in both C and Rust kernel modules, which gives them some real confidence in the method <ref:2606.00455#pg3>.
Priya: But we have to talk about the numbers too. The micro-benchmark shows each callback is only about twenty-seven nanoseconds when it’s running over five thousand iterations <ref:2606.00455#pg1>. It's fast enough for targeted investigations, but the system itself adds some overhead to the kernel startup <ref:2606.00455#pg1>.
Nadia: That overhead is something you have to manage because it’s not something you can just enable and forget about when you're running a big fuzzing campaign <ref:2606.00455#pg1>.
Elias: The authors also show this works for Rust kernel modules in two ways, either a post-compilation pipeline or by building the custom LLVM itself, which addresses some known issues with other tools like drgn and vmcore <ref:2606.00455#pg2>.
Priya: So what this means for us is that we can move toward automated verification. Instead of just reporting an observation, you can feed these structured dataflow records into a model checker to verify if the inputs actually violate the expected contracts <ref:2606.00455#pg3>.
Nadia: It shifts the workflow from waiting for feedback to automatically verifying known rules, which is a big change for how we approach finding bugs in complex systems <ref:2606.00455#pg1>.
Elias: And they suggest you can use this structured output to check cross-field invariants after the fact, which means you catch those silent bugs that static analysis misses at-O2 <ref:2606.00455#pg3>.
Priya: The real implication is that this method provides evidence grounded in physical execution, which is important because it gives you proof that the data flow record isn't just some guess <ref:2606.00455#pg1>.
Nadia: So, this paper is showing a way to get deep state information from kernel functions at runtime that existing coverage tools completely miss <ref:2606.00455#pg1>.
Elias: It bridges the gap between fuzzing and data-flow analysis by giving you that state awareness for mutation guidance, and deterministic records for root-cause analysis <ref:2606.00455#pg2>.
Priya: We'll be talking about how this structured output can be used to check cross-field invariants in our next segment.
The paper's improvements: Tom: So, we're looking at how the authors suggest you actually use this KCOV-DATAFLOW system to get better results <ref:2606.00455#pg1>.
Nadia: They are proposing moving past just capturing the data flow and starting to use it for specific checks, like defining formal boundary contracts for every function call <ref:2606.00455#pg3>.
Elias: That means you set up a precondition for what goes in and a postcondition for what comes out, and the system flags anything that breaks those rules <ref:2606.00455#pg3>.
Priya: It allows you to catch those subtle state changes, like if a struct field value shifts between when the function starts and when it returns <ref:2606.00455#pg3>.
Nadia: That’s useful because it helps find silent bugs, those kinds of errors that static analysis just can't see at low optimization levels <ref:2606.00455#pg1>.
Elias: And they suggest you can use this structured data to do offline model checking, which is like playing back the execution against a set of formal specifications <ref:2606.00455#pg3>.
Priya: That’s what I mean, it turns the workflow from just reporting observations into automatically verifying known rules before you even run the fuzzer <ref:2606.00455#pg3>.
Nadia: It makes the data machine-readable so you can feed it into automated reasoning tools instead of manually parsing logs, which is a big win for security audits <ref:2606.00455#pg3>.
Elias: They also suggest that this structured output lets you check if the actual execution matches those formal specifications after the fact <ref:2606.00455#pg3>.
Priya: So, it’s not just about finding crashes anymore, it’s about verifying correctness based on defined rules across all reachable states discovered during exploration <ref:2606.00455#pg3>.
Nadia: It sounds like this moves us toward a system where you check the contracts first and only escalate when you see something that actually violates them <ref:2606.00455#pg3>.
Elias: And they make sure this works for Rust kernel modules in two distinct ways, giving people flexibility on how they integrate the instrumentation <ref:2606.00455#pg2>.
Priya: The limitation here is that you still need to define those formal contracts yourself; the data provides the evidence, but you have to write the rules <ref:2606.00455#pg3>.
Nadia: So, this system gives us a way to ground our security hypotheses in physical execution evidence rather than just speculation <ref:2606.00455#pg1>.
Elias: And that deterministic nature of the data flow records is what makes it reproducible, which is essential for empirical security research <ref:2606.00455#pg1>.
Priya: We’ll be looking at how this evidence helps ground AI-assisted auditing in our next segment.
Conclusion: Tom: So we’re wrapping up this look at "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM."
Nadia: Basically, this framework takes coverage data and adds data flow extraction to see which specific arguments are used and what they return, giving fuzzers better guidance <ref:2606.00455#pg1>.
Elias: It’s about getting deterministic records for analysts without adding slow overhead, which is a real win for root-cause analysis <ref:2606.00455#pg2>.
Priya: The big picture here is that this moves us toward automated verification, where you check the actual data flow against formal contracts after the fact <ref:2606.00455#pg3>.
Nadia: It means we can find those silent bugs that static analysis just misses because they involve runtime struct state <ref:2606.00455#pg1>.
Elias: And the authors show this works for Rust modules in two ways, which makes it more practical for real-world kernel work <ref:2606.00455#pg2>.
Priya: The limitation is that we still have to write those formal contracts ourselves; the data just provides the evidence of what happened <ref:2606.00455#pg3>.
Nadia: But getting physical execution evidence that’s deterministic really strengthens any security hypothesis, even for AI auditing <ref:2606.00455#pg1>.
Elias: It’s about bridging the gap between fuzzing and data-flow analysis by giving you state awareness for mutation guidance <ref:2606.00455#pg2>.
Priya: That structured output is what makes it amenable to automated reasoning tools, which is a big shift in how we analyze these systems <ref:2606.00455#pg3>.
Nadia: So, this paper on "Beyond Edge Coverage: Per-Task Data-Flow Extraction at Kernel Function Boundaries via LLVM" is showing us a way to get deep state information from kernel functions that existing coverage tools miss <ref:2606.00455#pg1>.
Elias: It gives fuzzers better guidance by showing them how argument values change the outcome, and it gives analysts deterministic records for root-cause analysis without adding significant overhead <ref:2606.00455#pg2>.
Priya: And it lets us check cross-field invariants, like ensuring that a total length constraint is met between an entry and a return value <ref:2606.00455#pg3>.
Nadia: It’s about moving beyond just seeing what code path you took to actually understanding the data that flowed through it <ref:2606.00455#pg1>.
Elias: The framework itself is a clever use of LLVM extensions and kernel ring buffers to operate safely in process context <ref:2606.00455#pg2>.
Priya: We’ll be looking at how this evidence helps ground AI-assisted auditing in our next segment.
More episodes
- 2506.09956-LLMail-Inject: A Dataset from a Realistic Adaptive Prompt Injection Challenge
- 2510.11804-A Comprehensive Survey of Website Fingerprinting Attacks and Defenses in Tor: Advances and Open Challenges
- 2401.01114-Two Birds One Stone: Effective Static Detection of Resource and Communication Deadlocks in Rust Programs
- 2407.03883-Protecting Deep Learning Model Copyrights with Adversarial Example-Free Reuse Detection
- 2509.22143-The Express Lane to Spam and Centralization: An Empirical Analysis of Arbitrum's Timeboost
- 2603.17133-Identity-Based Signing Shifts, Not Solves, Usability: Evidence from Five Identity-Based Signing Ecosystems
- 2602.02744-An introduction to local differential privacy protocols using block designs
- 2510.17308-Single-Shuffle Full-Open Card-Based Secure Computation Protocols for Any Function
- 2603.00106-A Multi-Scenario UAV RF Dataset with Real-World Acquisition and Signal Processing Benchmarking
- 2601.21258-Virtualization-based Penetration Testing Study for Detecting Accessibility Abuse Vulnerabilities in Banking Apps in East and Southeast Asia