From e027ebe68b9d91972d17a9c2d4f7d99716f6a262 Mon Sep 17 00:00:00 2001 From: ErenAri Date: Tue, 21 Jul 2026 19:10:17 +0300 Subject: [PATCH] examples: bpfman pre-load gate adapter Adapts bpfcompat to the optional PreLoadValidator hook proposed in bpfman (ErenAri/bpfman branch preload-validation-gate). bpfman defines the interface and this supplies the implementation, so bpfman itself never imports bpfcompat. The error is the deliverable: bpfman surfaces it verbatim, so a refusal carries the classification code, the verifier's reason and the errno instead of the bare EINVAL the loader would otherwise produce. Builds with and without the hostload tag; without it bpfcompat compiles to a stub that reports the feature is unavailable rather than silently passing objects. Signed-off-by: ErenAri --- examples/bpfman-gate/gate.go | 68 ++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 examples/bpfman-gate/gate.go diff --git a/examples/bpfman-gate/gate.go b/examples/bpfman-gate/gate.go new file mode 100644 index 0000000..a30a64e --- /dev/null +++ b/examples/bpfman-gate/gate.go @@ -0,0 +1,68 @@ +// Package bpfmangate adapts bpfcompat to bpfman's optional pre-load +// validation hook. +// +// bpfman defines the interface; this supplies the implementation, so bpfman +// itself never imports bpfcompat: +// +// type PreLoadValidator interface { +// ValidateBeforeLoad(ctx context.Context, objectPath string) error +// } +// +// Wire it up at construction: +// +// mgr, err := manager.New(rt, puller, store, kern, progValidator, logger) +// if err != nil { +// return err +// } +// mgr = mgr.WithPreLoadValidator(bpfmangate.New()) +// +// Build with -tags hostload so bpfcompat validates against the running +// kernel; without the tag it compiles to a stub that reports the feature is +// unavailable rather than silently passing. +package bpfmangate + +import ( + "context" + "fmt" + + "github.com/kernel-guard/bpfcompat/pkg/bpfcompat" +) + +// Gate refuses objects the running kernel's verifier will not accept. +type Gate struct { + opts []bpfcompat.Option +} + +// New returns a Gate. Options are passed through to bpfcompat, so a caller +// can select load-only versus load-and-attach checking, point at an external +// validator binary, and so on. +func New(opts ...bpfcompat.Option) *Gate { + return &Gate{opts: opts} +} + +// ValidateBeforeLoad implements bpfman's PreLoadValidator. +// +// The error is the product here: bpfman surfaces it to the caller verbatim, +// so it carries the classification and the verifier's own reason instead of +// the bare EINVAL the loader would otherwise produce. +func (g *Gate) ValidateBeforeLoad(ctx context.Context, objectPath string) error { + res, err := bpfcompat.ValidateBeforeLoad(ctx, objectPath, g.opts...) + if err != nil { + // Infrastructure failure, not a verdict: the object was never + // judged, so say so rather than implying it was rejected. + return fmt.Errorf("pre-load check could not run: %w", err) + } + if res.OK() { + return nil + } + + reason := res.Classification.Reason + if reason == "" { + reason = res.Load.LogTail + } + if reason == "" { + reason = "object rejected by the verifier" + } + return fmt.Errorf("%s on kernel %s (%s, errno %d)", + reason, res.Kernel.Release, res.Classification.Code, res.Load.Errno) +}