vmlinux.h is the generated header that exposes the kernel’s type definitions to your program. libbpf CO:RE is the portability layer that helps the program adapt when those definitions shift on a different machine. In practice, the header provides the schema, while CO:RE keeps field access resilient across kernel versions.
What each one is responsible for in an eBPF build
vmlinux.h and libbpf CO:RE solve different parts of the same portability problem. The kernel type view gives your program the symbols and struct layouts it needs to compile against, while CO:RE makes those accesses survive kernel drift at runtime. One is a generated description of the target kernel, the other is a relocation strategy that keeps the program portable.
That split matters because eBPF programs are tightly coupled to kernel data structures. If you write against raw offsets, even a small field move can break correctness. vmlinux.h reduces that friction at build time by exposing type information, but it does not by itself solve cross-kernel compatibility.
How they work together in practice
Most CO:RE-based workflows use both pieces together. vmlinux.h is produced from the running kernel’s BTF metadata and lets clang understand types such as task_struct, skb, or inode. libbpf CO:RE then records field references in a relocatable form and adjusts them when the target kernel’s BTF shows the layout has shifted.
The practical consequence is that you usually do not choose one instead of the other. You use vmlinux.h to compile a type-aware program, then rely on CO:RE to map those type-aware accesses onto the destination kernel. That is why a program can compile once and still load cleanly across different distributions and kernel versions, as long as the relevant BTF data is available.
For readers comparing the concepts, the simplest way to think about it is: vmlinux.h is compile-time type exposure, and CO:RE is runtime field relocation. The header tells the compiler what exists; CO:RE keeps the compiled access pattern aligned with what actually exists on the host kernel.
Where portability breaks and what to check first
Portability fails when the program assumes a stable layout that the kernel no longer guarantees. Typical failure points include missing BTF, hand-written offsets, or code that reaches into fields without letting libbpf resolve them through CO:RE. The result is usually not a syntax problem, but a semantic one: the program loads and then reads the wrong field, or fails to attach on an incompatible kernel.
Failure mechanism: A vmlinux.h-based build can still become brittle if the program bypasses CO:RE and hard-codes layout assumptions, because the compiled offsets no longer match the target kernel’s BTF-described types.
Impact: The program may misread kernel state, silently produce incorrect telemetry, or fail to load on other systems, which undermines the main reason eBPF is attractive for fleet-wide observability and policy enforcement.
Standards & Framework Alignment
This section maps relevant standards and security frameworks to the operational risks and controls described in this guidance.
NIST CSF 2.0 and CIS Controls v8 set the governance and control requirements practitioners need to meet.
| Framework | Control / Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.IP-1 — Configuration Management | Kernel-type portability depends on controlled build and deployment inputs. |
| PR.DS-5 — Data, Software, and Information Integrity | CO:RE depends on preserving object integrity through compilation and load time. | |
| Recommendation — Track kernel-BTF and build artifacts so eBPF releases remain reproducible across hosts. Verify the compiled eBPF object and BTF inputs before loading them. | ||
| CIS Controls v8 | 16 — Application Software Security | eBPF programs are software artifacts whose portability and correctness depend on secure build practices. |
| 4 — Secure Configuration of Enterprise Assets and Software | Kernel-specific type data and runtime compatibility are configuration-sensitive deployment concerns. | |
| Recommendation — Build eBPF programs with reproducible, reviewable compilation and test them across target kernels. Standardise kernel and BTF baselines for environments that load CO:RE-based eBPF. | ||
Practitioner Guidance
What to verify: Confirm that your build pipeline is generating vmlinux.h from the same BTF-backed kernel type source you intend to target, and that the final object is using CO:RE relocations rather than fixed offsets. If you need to support multiple kernel families, test on the oldest and newest kernels you expect to see, because layout drift is often where assumptions fail.
Common mistake: Treating vmlinux.h as a portability feature by itself. It is only the type input to the compiler; the portability guarantee comes from libbpf’s relocation logic plus valid kernel BTF on the target host.
Practitioner takeaway: Use vmlinux.h to make kernel types visible at build time, but depend on CO:RE to make those type references survive real kernel variation at runtime.
Related resources from NHI Mgmt Group
- What is the difference between local MCP development and production trust?
- What is the difference between agentic assistance and autonomous execution in development tools?
- What is the difference between governing AI model development and governing shadow AI use?
- What is the difference between secure-by-design development and retrofitting security onto AI-generated code?
Deepen Your Knowledge
Reviewed and updated by the NHIMG editorial team on September 20, 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org