Skip to content

Latest commit

 

History

19 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KBI - Kernel Bundle Image

KBI packages Linux kernels and kernel-dependent artifacts as OCI images. It makes the kernel a first-class, independently versioned artifact instead of an implicit part of an OS image.

Bootable system = Kernel artifacts (KBI OCI image) + Root filesystem (standard OCI image)

Use KBI when the kernel lifecycle must be independent from user space, when add-on compatibility must be explicit, or when the same kernel needs to be reused across bare-metal, VM, and image-build environments.

Core Concepts

Kernel Bundle

A Kernel Bundle is an OCI image containing kernel artifacts in a canonical distribution layout:

/kbi/
  vmlinuz
  initrd                optional
  modules/<kver>/       optional
  firmware/             optional
  symvers               optional
  bpf/                  optional

/kbi/* is a distribution namespace, not the runtime filesystem layout.

KBI ID

The Kernel Build Identity (KBI ID) is a deterministic identifier for a kernel build. It is computed from identity components and published as an OCI annotation:

kbi_id = "kbi:sha256:" + hex(sha256(
  join("\n", sort([
    "vmlinuz:" + hex(sha256(vmlinuz)),
    "btf:"     + hex(sha256(btf)),     // when present
    "config:"  + hex(sha256(config)),  // when present
  ]))
))

vmlinuz is always included. btf and config are included only when supplied at build time, so the same vmlinuz produces a different KBI ID depending on which identity inputs are present. Modules, initrd, firmware, and Module.symvers are bound through metadata such as kver, not through the KBI ID. This lets operational payloads change without redefining the kernel build identity.

Add-On Packs

Add-ons are separately packaged OCI artifacts that bind to a specific KBI ID:

  • ModulePack: out-of-tree kernel modules
  • BPF Pack: compiled eBPF objects plus kbi-bpf.json metadata

Pack builds are rejected unless they declare a target KBI ID, either by resolving a target image with --for or by passing --for-kbi-id directly.

Resolver

The resolver combines one KBI image with zero or more add-on packs and rejects incompatible combinations before boot or install.

Today, the resolver enforces:

  • pack for_kbi_id matches the KBI ID
  • architecture matches
  • declared pack kernel version matches when present
  • BPF packs require a target KBI with BTF
  • BPF packs include manifest metadata

Signatures are enforced separately, by the signature policy (see Signing). Module signature verification and deep eBPF verification against BTF are planned but not implemented yet.

Compatibility Model

KBI currently enforces compatibility at these layers:

Layer Current enforcement
KBI image required vmlinuz; valid artifact paths; bundled modules must match --kver and --arch and share one vermagic, recorded as the kernel's vermagic
ModulePack required KBI binding; modules must match the target architecture and vermagic; with the target's Module.symvers, the load-time symbol checks below
BPF Pack required KBI binding; required kbi-bpf.json; object references must exist; BTF required
Resolver KBI ID, architecture, kernel version, BTF, and manifest checks

Module Load Checks

The kernel can refuse a module at load time. kbi pack build --for runs the same checks at pack time, against the target KBI image:

Check Kernel counterpart Needs
ELF machine, class, and byte order match arch ELF header checks always
Full vermagic string matches the kernel's check_modinfo() bundled modules in the KBI image; otherwise only the kernel version is compared
Every undefined symbol is exported by the kernel or by another module in the pack resolve_symbol() symvers
Symbol CRCs match (__versions or __version_ext_crcs) check_version() symvers from a CONFIG_MODVERSIONS kernel
GPL-only symbols are used only by GPL-compatible modules resolve_symbol() symvers
Namespaced symbols are imported with MODULE_IMPORT_NS() verify_namespace_is_imported() symvers; relaxed when config sets CONFIG_MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS

With --for-kbi-id, only the architecture check runs, since the target image is not available. Module signatures are not checked.

KBI records declared BPF dependencies, including kfuncs and kernel types/fields, but does not yet prove kfunc signatures, CO-RE relocations, or kernel structure compatibility. Those checks belong in a deeper verifier built on the same manifest and KBI BTF.

Install

go install github.com/multikernel/kbi/cmd/kbi@latest

Or build from source:

git clone https://github.com/multikernel/kbi.git
cd kbi
go build -o kbi ./cmd/kbi

Quick Start

Build a KBI Image

--kver and --arch are required because they drive install paths and add-on compatibility checks.

kbi build \
  -k /boot/vmlinuz-$(uname -r) \
  -i /boot/initrd.img-$(uname -r) \
  -m /lib/modules/$(uname -r) \
  -b /sys/kernel/btf/vmlinux \
  -c /boot/config-$(uname -r) \
  --symvers /usr/src/linux-headers-$(uname -r)/Module.symvers \
  --kver $(uname -r) \
  --arch amd64 \
  -t registry.io/org/kernel:$(uname -r)

Inspect a KBI Image

kbi inspect registry.io/org/kernel:6.8.0
KBI ID:      kbi:sha256:3701209414c63c65...
Kernel:      6.8.0
Arch:        amd64
Components:  vmlinuz,initrd,btf,config,modules
Digest:      sha256:a3fd5977466f1c01...

Push and Pull

kbi push registry.io/org/kernel:6.8.0
kbi pull registry.io/org/kernel:6.8.0

Registry authentication uses Docker credential helpers from ~/.docker/config.json.

Sign and Verify

kbi sign --key ci.key registry.io/org/kernel:6.8.0
kbi sign --key lab.key -a stage=tested registry.io/org/kernel:6.8.0
kbi verify --key ci.pub --key lab.pub --threshold 2 registry.io/org/kernel:6.8.0

# Or sign as part of pushing
kbi push --sign-key ci.key registry.io/org/kernel:6.8.0

See Signing.

Install to a Filesystem

kbi install registry.io/org/kernel:6.8.0 --dest /

The install adapter maps KBI artifacts to the target filesystem:

/boot/vmlinuz-<kver>
/boot/initrd.img-<kver>
/boot/config-<kver>
/boot/btf-<kver>
/boot/symvers-<kver>
/lib/modules/<kver>/
/lib/firmware/

Build a ModulePack

kbi pack build \
  --type modulepack \
  --for registry.io/org/kernel:6.8.0 \
  -m /path/to/modules/ \
  -t registry.io/org/mydriver:1.0

If the target KBI image is unavailable but the KBI ID is known:

kbi pack build \
  --type modulepack \
  -m /path/to/modules/ \
  --for-kbi-id kbi:sha256:3701209414c63c65... \
  --arch amd64 \
  -t registry.io/org/mydriver:1.0

Build a BPF Pack

kbi pack build \
  --type bpfpack \
  --for registry.io/org/kernel:6.8.0 \
  --bpf /path/to/bpf/ \
  -t registry.io/org/mybpf:1.0

BPF packs must include kbi-bpf.json in the BPF directory, or pass it explicitly with --bpf-manifest.

{
  "schema_version": 1,
  "programs": [
    {
      "file": "trace.o",
      "section": "fentry/do_sys_openat2",
      "attach": "fentry",
      "target": "do_sys_openat2"
    }
  ],
  "requires": {
    "btf": true,
    "kfuncs": ["bpf_task_acquire"],
    "kernel_types": [
      {"name": "task_struct", "fields": ["pid", "comm"]}
    ]
  }
}

KBI validates that the manifest is present, well-formed, and references object files inside the pack.

Inspect a Pack

kbi pack inspect registry.io/org/mydriver:1.0
Type:        modulepack
For KBI ID:  kbi:sha256:3701209414c63c65...
For Kernel:  6.8.0
Arch:        amd64
Contents:    mydriver.ko
Digest:      sha256:ef45ab...

Resolve a Kernel View

kbi resolve \
  registry.io/org/kernel:6.8.0 \
  registry.io/org/mydriver:1.0 \
  registry.io/org/mybpf:1.0

kbi resolve is a compatibility gate, not a full eBPF verifier. It consumes pack metadata and enforces binding, architecture, kernel version, and BTF presence.

Artifact Reference

Only vmlinuz is required. All other artifacts are optional.

Artifact Flag Notes
vmlinuz -k kernel binary
initrd -i initial ramdisk
modules -m directory may be /lib/modules/<kver> or its parent; module vermagic must match --kver
Module.symvers --symvers exported symbols, CRCs, and namespaces; enables symbol checks for ModulePacks (Linux 5.10+ format)
config -c kernel .config; participates in KBI ID
BTF -b BPF Type Format data; participates in KBI ID
firmware --firmware firmware directory

OCI Format

KBI images are standard OCI images with custom media types per layer:

application/vnd.multikernel.kbi.vmlinuz.v1
application/vnd.multikernel.kbi.initrd.v1
application/vnd.multikernel.kbi.modules.v1.tar
application/vnd.multikernel.kbi.firmware.v1.tar
application/vnd.multikernel.kbi.kernelconfig.v1
application/vnd.multikernel.kbi.btf.v1
application/vnd.multikernel.kbi.symvers.v1

Pack images use pack-specific layer media types:

application/vnd.multikernel.kbi.modulepack.v1.tar
application/vnd.multikernel.kbi.bpfpack.v1.tar

KBI image annotations:

io.multikernel.kbi.id
io.multikernel.kbi.kver
io.multikernel.kbi.arch
io.multikernel.kbi.components
io.multikernel.kbi.vermagic           when modules are bundled

Generic pack annotations:

io.multikernel.kbi.pack.type
io.multikernel.kbi.pack.for_kbi_id
io.multikernel.kbi.pack.for_kver
io.multikernel.kbi.pack.contents
io.multikernel.kbi.pack.requires

BPF pack annotations:

io.multikernel.kbi.pack.bpf.manifest
io.multikernel.kbi.pack.bpf.programs
io.multikernel.kbi.pack.bpf.kfuncs
io.multikernel.kbi.pack.bpf.types

KBI does not modify the OCI specification. KBI images and packs work with OCI-compliant registries.

Execution Models

Bare metal: install KBI artifacts into /boot, /lib/modules/<kver>, and /lib/firmware, then configure the bootloader normally.

VM or image build: bake the KBI into a disk image or boot it directly through a hypervisor with an external root filesystem.

Why KBI?

Why not bootc? bootc installs whole OS images with the kernel embedded. KBI separates kernel and rootfs lifecycle.

Why not docker buildx? buildx builds generic container images. It does not understand kernel identity, typed kernel layers, module vermagic, BPF metadata, or KBI compatibility binding.

Why not LinuxKit? LinuxKit builds complete OS images. KBI makes the kernel a reusable artifact that can be composed with different root filesystems.

Why not tar plus a registry? A tarball loses typed layers, deterministic kernel identity, compatibility annotations, structured metadata, and resolver checks.

KBI’s premise is simple: the kernel is a governed resource, not an implicit dependency.

Signing

KBI and pack images are signed in their registry, after they are pushed. Signing is separate from building, so signing keys do not need to live on build machines, and an image can collect signatures over time, for example from CI when it is built and from a test lab when it passes. Signing never changes the image.

Format

Signatures use cosign's tag layout: a companion image tagged sha256-<digest>.sig in the same repository, one layer per signature. Each layer is a simple-signing payload covering the image's manifest digest, with the signature in the dev.cosignproject.cosign/signature annotation. KBI also records the image's KBI ID in the payload, and verification rejects a signature whose recorded KBI ID differs from the image's.

The layout is compatible with cosign in both directions:

cosign verify --key ci.pub --insecure-ignore-tlog=true registry.io/org/kernel:6.8.0
kbi verify --key cosign.pub registry.io/org/kernel:6.8.0

Keys are ECDSA P-256 in PEM form. Private keys must be unencrypted PKCS#8 or SEC 1; cosign's encrypted key files are not supported for signing, but cosign.pub works for verification. Transparency logs and keyless signing are not supported.

openssl ecparam -genkey -name prime256v1 -noout | openssl pkcs8 -topk8 -nocrypt -out ci.key
openssl ec -in ci.key -pubout -out ci.pub

Signature Policy

When a policy is configured, kbi pull, kbi install, kbi pack build --for, and kbi resolve refuse images that do not satisfy it. A pulled image is checked before it is cached. Without a policy, nothing is checked.

The policy is read from --policy, then $KBI_POLICY, then ~/.kbi/policy.json if it exists:

{
  "version": 1,
  "default": "reject",
  "rules": [
    {"match": "registry.io/org/kernel", "keys": ["ci.pub", "lab.pub"], "threshold": 2},
    {"match": "registry.io/org/*", "keys": ["ci.pub"]}
  ]
}
  • match is a repository, or a prefix ending in *. The first matching rule applies.
  • threshold is how many distinct keys from keys must have signed; the default is 1.
  • default decides images no rule matches: reject (the default) or allow.
  • Key paths are relative to the policy file.

Verification checks the digest of the image being used, so an image replaced in the registry, or altered in the local store, after it was signed is refused.

Security Status

Planned work:

  • kernel module signature verification at pack build and install time
  • deeper eBPF verification against BTF
  • measured boot integration

License

Copyright 2026 Multikernel Technologies, Inc.

Licensed under the Apache License, Version 2.0. See LICENSE for details.

About

KBI packages Linux kernels and kernel-dependent artifacts as standard OCI images, enabling independent kernel lifecycle management, explicit compatibility guarantees, and reuse across environments.

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages