Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) once a

## [Unreleased]

### Added
- `examples/preload-gate`: a complete, runnable example of using the
`pkg/bpfcompat` library — `ValidateBeforeLoad` as a bpfman-style pre-load gate
(real load on the node's own kernel, no VM). README gains a "Library mode"
section with the example and a real pass/blocked run.

### Fixed
- README install snippet pinned the stale `v0.1.6` release; bumped to `v0.2.0`.

## [0.2.0] - 2026-06-27

### Added
Expand Down
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,33 @@ different bootstrap. bpfcompat implements it (Ignition config over QEMU
image, the **RHEL / AlmaLinux 9 (5.14)** profiles are the interim kernel
approximation. Full guide: [docs/rhcos-openshift.md](docs/rhcos-openshift.md).

## Library mode: embed the pre-load gate

Beyond the CLI and the GitHub Action, bpfcompat is an embeddable Go library
([`pkg/bpfcompat`](https://github.com/Kernel-Guard/bpfcompat/tree/main/pkg/bpfcompat)).
`ValidateBeforeLoad` does a real `bpf()` load against the node's **own running
kernel** — no VM, no network — so a loader (e.g. bpfman) can refuse an object
that won't verify *before* it loads it. Host loading is gated behind the
`hostload` build tag and needs `CAP_BPF`/`CAP_SYS_ADMIN`.

A complete, real example is [`examples/preload-gate`](examples/preload-gate):

![preload-gate.go — a real program using ValidateBeforeLoad](docs/images/library/library-code.png)

```sh
go get github.com/kernel-guard/bpfcompat@v0.2.0
go build -tags hostload -o preload-gate ./examples/preload-gate
sudo ./preload-gate probe.bpf.o
```

A compatible object passes; an incompatible one is blocked with the kernel's own
verdict and a stable classification code — exit 0 vs 1:

![preload-gate real run: a good object loads, a CO-RE failure is blocked](docs/images/library/library-run.png)

See [`pkg/bpfcompat/README.md`](pkg/bpfcompat/README.md) for the full API.
(Pre-1.0 / experimental.)

## Try it in CI without your own KVM box

GitHub-hosted Linux runners now expose `/dev/kvm`, so the full QEMU VM
Expand Down Expand Up @@ -227,7 +254,7 @@ guest-side validator binary and the kernel matrices that ship in this repo.
the static validator, checksum-verified:

```bash
VER=v0.1.6
VER=v0.2.0
base="https://github.com/Kernel-Guard/bpfcompat/releases/download/$VER"
curl -fsSLO "$base/bpfcompat-linux-amd64"
curl -fsSLO "$base/bpfcompat-validator-static-linux-amd64"
Expand Down
Binary file added docs/images/library/library-code.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/library/library-run.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
45 changes: 45 additions & 0 deletions examples/preload-gate/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Command preload-gate is a minimal, real example of using bpfcompat as a
// library: validate a compiled eBPF object against the node's own running
// kernel before loading it. This is the bpfman-style pre-load path — a real
// bpf() load, no VM, no network.
//
// Build with the hostload tag (host-kernel loading is gated off by default):
//
// go build -tags hostload -o preload-gate ./examples/preload-gate
// sudo ./preload-gate probe.bpf.o
//
// Exit code: 0 if it would load, 1 if the gate blocks it (or on error).
package main

import (
"context"
"fmt"
"os"

"github.com/kernel-guard/bpfcompat/pkg/bpfcompat"
)

// preloadGate refuses to load a BPF object that won't verify on THIS kernel.
func preloadGate(ctx context.Context, path string) error {
res, err := bpfcompat.ValidateBeforeLoad(ctx, path)
if err != nil {
return err
}
if !res.OK() {
return fmt.Errorf("refusing to load on %s: [%s] %s",
res.Kernel.Release, res.Classification.Code, res.Classification.Reason)
}
fmt.Printf("ok: loads on %s (%s)\n", res.Kernel.Release, res.Load.Status)
return nil
}

func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "usage: preload-gate <artifact.bpf.o>")
os.Exit(2)
}
if err := preloadGate(context.Background(), os.Args[1]); err != nil {
fmt.Fprintln(os.Stderr, "blocked:", err)
os.Exit(1)
}
}
Loading