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
5 changes: 5 additions & 0 deletions docs/design/microvm-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ Each is its own branch, tested before the next.
`4a6755ac…`, rootfs `bf06cedb…` (aarch64) and `4f4e67cb…` (x86_64), and the layers over them. The
kernels, agent-init and berth-init rebuilt unchanged. This will recur until the apk cache is pinned
(open problem 10 in `microvm-runtime.md`).
- **Re-pinned for the agent-init log fix, 2026-10-25.** agent-init's `eprintln!` wrote each line in
pieces, so two apps sharing a stderr spliced their lines together and the Multi-App check failed about
one run in three. Both manifests now pin agent-init to the fix (`0204e8f2…`), which also carries main's
libc, tokio and sqlite bumps. `update_pins` runs 40198606357 (aarch64) and 40198603422 (x86_64) give
rootfs `e6017262…` (aarch64) and `0c623b43…` (x86_64); the kernels are unchanged.
- **Linux arm64 booted**, 2026-10-24, on a nested-KVM Lima VM (Ubuntu 24.04, Linux 6.8, VZ on an M4) with
the published linux-arm64 berth-vmm `a3cf2a09…` and its libkrun, rootfs `62f96e1b…`: host sandbox
Landlock ABI 4 with TCP rules and seccomp; `e2e.mjs` single 18/18, multi 17/17, enforce 12/12, stdio 3/3,
Expand Down
6 changes: 3 additions & 3 deletions docs/local-vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ By default, from the GitHub release that [`.github/workflows/vm-artifacts.yml`](
| File | Asset | sha256 (this CLI) | Size |
|---|---|---|---|
| `~/.berth/vm/kernel/sha256/<sha>/Image` | `Image-<sha>` | `8f79e8dae97ebc0ab8fcdc4ad209bb025ec967be82c713503e0612cfdd340ec8` | 23,668,744 B |
| `~/.berth/vm/rootfs/rootfs-<sha>.erofs` | `rootfs-<sha>.erofs` | `bf06cedb9b40c5f23a74e2b2fe87458cd43b81a7d65ce09a65730b1e7cf590fa` | 107,937,792 B |
| `~/.berth/vm/rootfs/rootfs-<sha>.erofs` | `rootfs-<sha>.erofs` | `e60172628d1bbc5d36f3df44d81e4b9cf79b02fd87a974621d15e51dec570522` | 108,072,960 B |
| `~/.berth/vm/bin/berth-vmm` | `berth-vmm-darwin-arm64-<sha>`, `berth-vmm-linux-arm64-<sha>` | `VMM_PINS` in `packages/cli/src/vm/pins.ts` | about 700 KB (macOS), 2.7 MB (Linux) |
| `~/.berth/vm/bin/libkrun.1.19.6.dylib`, `libkrun.so.1.19.6` | `libkrun-darwin-arm64-<sha>.dylib`, `libkrun-linux-arm64-<sha>.so` | `LIBKRUN_PINS` in the same file | about 4.7 MB |

That is `https://github.com/Ash20pk/BerthOS/releases/download/vm-artifacts-8f79e8da-bf06cedb/`. The x86_64 one is `vm-artifacts-10d4b54c-4f4e67cb`: kernel `10d4b54c0896668a93f9d26d0a701aac4a14ce813f3ed4d3b4d26e50d7b7b8d1` (an ELF `vmlinux`, 27,928,992 B), rootfs `4f4e67cb49a1b07e96412e802bd2c6e42cfabee95d7c126b8589b1048a79a538` (108,765,184 B), and `berth-vmm-linux-x64-<sha>` with `libkrun-linux-x64-<sha>.so`. CI rebuilds each architecture's kernel and rootfs from source on GitHub's Linux runners of that architecture, and publishes the release only if they match the pins bit for bit. The release also carries `SHA256SUMS`, each rootfs's input record, berth-vmm's build record, and the kernel's GPL sources (the exact linux and libkrunfw tarballs, the config delta, the resolved config and the build script; see `SOURCES.md` there).
That is `https://github.com/Ash20pk/BerthOS/releases/download/vm-artifacts-8f79e8da-e6017262/`. The x86_64 one is `vm-artifacts-10d4b54c-0c623b43`: kernel `10d4b54c0896668a93f9d26d0a701aac4a14ce813f3ed4d3b4d26e50d7b7b8d1` (an ELF `vmlinux`, 27,928,992 B), rootfs `0c623b43a2c2852fd156d1ea6d4f00a8612143299ec7381cf2d1516607d0a9f6` (108,904,448 B), and `berth-vmm-linux-x64-<sha>` with `libkrun-linux-x64-<sha>.so`. CI rebuilds each architecture's kernel and rootfs from source on GitHub's Linux runners of that architecture, and publishes the release only if they match the pins bit for bit. The release also carries `SHA256SUMS`, each rootfs's input record, berth-vmm's build record, and the kernel's GPL sources (the exact linux and libkrunfw tarballs, the config delta, the resolved config and the build script; see `SOURCES.md` there).

berth-vmm and its libkrun are downloaded only when the CLI pins their sha256 for your platform (macOS arm64, Linux arm64 and Linux x86_64). A build from CI can't be pinned until CI has built it, so a CLI released before the first artifacts release has no pin, and says so. Then build berth-vmm and pass `--vmm`, or download it by hand (below).

Expand All @@ -95,7 +95,7 @@ If the kernel and rootfs aren't installed, `berth dev --runtime vm` installs the
#### Verifying by hand

```bash
tag=vm-artifacts-8f79e8da-bf06cedb
tag=vm-artifacts-8f79e8da-e6017262
gh release download "$tag" -R Ash20pk/BerthOS -p 'Image-*' -p 'rootfs-*.erofs' -p 'berth-vmm-darwin-arm64-*' -p 'libkrun-darwin-arm64-*' -p SHA256SUMS
shasum -a 256 -c --ignore-missing SHA256SUMS # each asset against the list
shasum -a 256 Image-* rootfs-*.erofs # and against the pins above, which are also in
Expand Down
14 changes: 14 additions & 0 deletions packages/agent-init/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,20 @@ use landlock::{
};
use serde::Deserialize;

// Shadows std's eprintln! for this crate (seccomp.rs included, since it is
// declared below). std's version writes each piece of the format string with
// its own write(2), so when two apps' agent-init share one stderr their lines
// interleave mid-line. Formatting first and writing once keeps each line
// whole: a single write under PIPE_BUF to a pipe is atomic.
macro_rules! eprintln {
($($arg:tt)*) => {{
use std::io::Write as _;
let mut line = format!($($arg)*);
line.push('\n');
let _ = std::io::stderr().write_all(line.as_bytes());
}};
}

mod seccomp;

#[derive(Deserialize)]
Expand Down
18 changes: 9 additions & 9 deletions packages/cli/src/vm/pins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ export interface GuestPins {
export const GUEST_PINS: Partial<Record<GuestArch, GuestPins>> = {
aarch64: {
kernel: { sha256: "8f79e8dae97ebc0ab8fcdc4ad209bb025ec967be82c713503e0612cfdd340ec8", size: 23668744, linux: "6.12.109", configSha256: "e3f33c2bd4bffa16e52a066c325967e4bde091f20063e6eb5b81e8a2efac4dc8" },
rootfs: { sha256: "bf06cedb9b40c5f23a74e2b2fe87458cd43b81a7d65ce09a65730b1e7cf590fa", size: 107937792 },
rootfs: { sha256: "e60172628d1bbc5d36f3df44d81e4b9cf79b02fd87a974621d15e51dec570522", size: 108072960 },
},
x86_64: {
kernel: { sha256: "10d4b54c0896668a93f9d26d0a701aac4a14ce813f3ed4d3b4d26e50d7b7b8d1", size: 27928992, linux: "6.12.109", configSha256: "6e0fd31c75cd563f8bf650765504d97989316f70e9bbb333fb0230db78fe4283" },
rootfs: { sha256: "4f4e67cb49a1b07e96412e802bd2c6e42cfabee95d7c126b8589b1048a79a538", size: 108765184 },
rootfs: { sha256: "0c623b43a2c2852fd156d1ea6d4f00a8612143299ec7381cf2d1516607d0a9f6", size: 108904448 },
},
};

Expand Down Expand Up @@ -121,15 +121,15 @@ export type VmmPlatform = "darwin-arm64" | "linux-arm64" | "linux-x64";
* `berth vm install` refuses any other bytes, and clears macOS's quarantine
* attribute only on a file that matched.
*
* All three are from the per-architecture releases vm-artifacts-8f79e8da-bf06cedb
* (aarch64: darwin-arm64, linux-arm64) and vm-artifacts-10d4b54c-4f4e67cb
* (x86_64: linux-x64). Runs 40103596964 / 40103557191 and 40104945503 built
* each of them to the same bytes.
* All three are from the per-architecture releases vm-artifacts-8f79e8da-e6017262
* (aarch64: darwin-arm64, linux-arm64) and vm-artifacts-10d4b54c-0c623b43
* (x86_64: linux-x64). Run 40200731376 built all three; it also rebuilt both
* rootfs images to their pins and passed the x86_64 e2e under KVM.
*/
export const VMM_PINS: Partial<Record<VmmPlatform, { sha256: string; size: number }>> = {
"darwin-arm64": { sha256: "92fd7ae2a97e029f1689cfd626600dfcbef39e8933ed304b0e2466a385c167ae", size: 700608 },
"linux-arm64": { sha256: "2ecc29d88ea0fd1abadc7a142bb0f7b53de5f8e104860ef2e24ce3c487646dc6", size: 725632 },
"linux-x64": { sha256: "e5809f8c43281b1e821be4b48003855a7913fe5905d2f32a52c7bf377b91e6d1", size: 742152 },
"darwin-arm64": { sha256: "628e6ac16dde4657a2c177a0614ee89de91f9d47db631b8c8d59e111fc2904f0", size: 700608 },
"linux-arm64": { sha256: "1b72e4966c5c96c0ff89eab64bb868e8ee9a2cac75640f8b3ee65ec2c53e7fd1", size: 725632 },
"linux-x64": { sha256: "308dd7d8a6e7a0cb5c821dcd2c2eefe7775d3a3859c7891ea5154ed8582cb0dd", size: 742152 },
};

export function vmmPin(platform: string = `${process.platform}-${process.arch}`, pins: Partial<Record<string, { sha256: string; size: number }>> = VMM_PINS): ArtifactPin | undefined {
Expand Down
8 changes: 4 additions & 4 deletions packages/vmm/rootfs/layers/browser/aarch64.apk.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ e2fsprogs-1.47.4-r0
e2fsprogs-libs-1.47.4-r0
encodings-1.1.0-r0
eudev-libs-3.2.14-r6
ffmpeg-libavcodec-8.1.2-r0
ffmpeg-libavformat-8.1.2-r0
ffmpeg-libavutil-8.1.2-r0
ffmpeg-libswresample-8.1.2-r0
ffmpeg-libavcodec-8.1.3-r0
ffmpeg-libavformat-8.1.3-r0
ffmpeg-libavutil-8.1.3-r0
ffmpeg-libswresample-8.1.3-r0
file-5.47-r2
font-alias-1.0.6-r0
font-cursor-misc-1.0.4-r1
Expand Down
8 changes: 4 additions & 4 deletions packages/vmm/rootfs/layers/browser/x86_64.apk.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ e2fsprogs-1.47.4-r0
e2fsprogs-libs-1.47.4-r0
encodings-1.1.0-r0
eudev-libs-3.2.14-r6
ffmpeg-libavcodec-8.1.2-r0
ffmpeg-libavformat-8.1.2-r0
ffmpeg-libavutil-8.1.2-r0
ffmpeg-libswresample-8.1.2-r0
ffmpeg-libavcodec-8.1.3-r0
ffmpeg-libavformat-8.1.3-r0
ffmpeg-libavutil-8.1.3-r0
ffmpeg-libswresample-8.1.3-r0
file-5.47-r2
font-alias-1.0.6-r0
font-cursor-misc-1.0.4-r1
Expand Down
22 changes: 11 additions & 11 deletions packages/vmm/rootfs/manifest-aarch64.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ packages = "rootfs/packages.txt"
source_date_epoch = 1790812800
# /usr/local/bin/agent-init and berth-probe: build-agent-init.sh, from
# packages/agent-init at this commit (main contains it).
agent_init_ref = "fix/seccomp-io-uring-vsock"
agent_init_commit = "c558ef85a920eece0413f2c08345a67396342153"
agent_init_sha256 = "9ec8b25e38d31ee82a28155304f730c0ec589b057d11fce2a56c661455929483"
agent_init_ref = "fix/agent-init-atomic-log"
agent_init_commit = "0204e8f2c9b924d8fe2f20c7390fe43689b4b2fa"
agent_init_sha256 = "0c1d011166a4e35167c4023cc65fb89a9aa2087ba7681c4c597cfd4111f9148f"
probe_sha256 = "6ec735d885b58861b33abdd70a5a4d48ecad803cc92bd94c02f876a3346453d0"
# /sbin/berth-init and /usr/local/bin/context-bus-daemon: build-berth-init.sh,
# from this tree (packages/vmm/init, packages/context-bus-daemon).
berth_init_sha256 = "eb9f699e91a4a1aba01d6778f346c279a9f6f1f5cdaa85d999b9e6b400c323ed"
context_bus_daemon_sha256 = "1138c3595142a3235145b530d0cf1157b0971aa2230d417befe0a6e783477544"
context_bus_daemon_sha256 = "401eec5ecd99024fdca5cbaee626947f47be2075e04b8b30013951b5e5a5055f"
# /usr/local/bin/semantic-fs-daemon: build-semantic-fs.sh, from
# packages/semantic-fs-daemon at HEAD: the daemon that serves /context
# (docs/design/microvm-semantic-fs.md).
semantic_fs_daemon_sha256 = "957bb9632d4faa4a3cd92436a95d18e07f7a01ea0314cf1553d72137b40c023a"
semantic_fs_daemon_sha256 = "ef1a0d0c62b6e0f10120de5ceb947fad1b975f48fa999f54343de504244d4b78"
# /usr/local/bin/berth-github-api-broker.cjs: packages/docker-orchestrator/docker/github-api-broker.cjs.
github_api_broker_sha256 = "0a809855c067d76b2074746b2390f6b204d1d80a7cafdc8cea4371efa624baaa"
# /usr/local/bin/berth-egress-broker.cjs: packages/docker-orchestrator/docker/egress-broker.cjs.
Expand Down Expand Up @@ -56,13 +56,13 @@ terminal = "tmux"
# builder.apk.lock the builder's (erofs-utils). .github/workflows/vm-artifacts.yml
# rebuilds it on a Linux runner and fails on any other hash. berth-vmm
# compiles this in; berth-vmm run boots it by default.
image_sha256 = "bf06cedb9b40c5f23a74e2b2fe87458cd43b81a7d65ce09a65730b1e7cf590fa"
image_size = 107937792
image_sha256 = "e60172628d1bbc5d36f3df44d81e4b9cf79b02fd87a974621d15e51dec570522"
image_size = 108072960
# Optional layer example (rootfs/layers/example, build-layer.sh), built for the base above.
layer_example_sha256 = "707d1c9ea2b77472954ae2cddb281dbbd1ca2e8f45b1bd191ba8c1f1ee3359c6"
layer_example_size = 471040
layer_example_base = "bf06cedb9b40c5f23a74e2b2fe87458cd43b81a7d65ce09a65730b1e7cf590fa"
layer_example_base = "e60172628d1bbc5d36f3df44d81e4b9cf79b02fd87a974621d15e51dec570522"
# Optional layer browser (rootfs/layers/browser, build-layer.sh), built for the base above.
layer_browser_sha256 = "92ad1a7b184bdc844c4611918930834c831d5cfed54e1e3c48100e1a794eb827"
layer_browser_size = 485199872
layer_browser_base = "bf06cedb9b40c5f23a74e2b2fe87458cd43b81a7d65ce09a65730b1e7cf590fa"
layer_browser_sha256 = "643b36055173d7698bfcd103646ec09d0c57b9f61977d4c30e29bef3d5957ce8"
layer_browser_size = 485203968
layer_browser_base = "e60172628d1bbc5d36f3df44d81e4b9cf79b02fd87a974621d15e51dec570522"
22 changes: 11 additions & 11 deletions packages/vmm/rootfs/manifest-x86_64.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ packages = "rootfs/packages.txt"
source_date_epoch = 1790812800
# /usr/local/bin/agent-init and berth-probe: build-agent-init.sh, from
# packages/agent-init at this commit (main contains it).
agent_init_ref = "fix/seccomp-io-uring-vsock"
agent_init_commit = "c558ef85a920eece0413f2c08345a67396342153"
agent_init_sha256 = "112c5f4ff89706e810b867da2e3121196e1294247a876c80b10de1ab337ec129"
agent_init_ref = "fix/agent-init-atomic-log"
agent_init_commit = "0204e8f2c9b924d8fe2f20c7390fe43689b4b2fa"
agent_init_sha256 = "e8ba190c2b317d574eebfc99aa04e867ed1e5aa8cca562eb153f34a78672348a"
probe_sha256 = "c722bb79589e8fa0f89d75ff3cdd47763aefdf2034ae15bb70baa2ddfcea9d80"
# /sbin/berth-init and /usr/local/bin/context-bus-daemon: build-berth-init.sh,
# from this tree (packages/vmm/init, packages/context-bus-daemon).
berth_init_sha256 = "8fbcb33c88edf01d3e863d82a477b2c9a19c1f2c3d35ba4ad027a48ca3a6ac44"
context_bus_daemon_sha256 = "29b094f36cfd578eb72241a4fc8beb4688e856e95bd434db9bd51c6e36bf5f69"
context_bus_daemon_sha256 = "c9f32a6f42f18c48b3647c5c06b03fc87611f123d2642f33dcf5dea10928edcf"
# /usr/local/bin/semantic-fs-daemon: build-semantic-fs.sh, from
# packages/semantic-fs-daemon at HEAD: the daemon that serves /context
# (docs/design/microvm-semantic-fs.md).
semantic_fs_daemon_sha256 = "4a6755ac4d3e6bd7233f895f1ea35aa11394961d63ad59faec0b2faa3f2d88f9"
semantic_fs_daemon_sha256 = "fbf507612ce1714172e103d2fa3df2dc524ccd2dd899d047970ce7e8a0761deb"
# /usr/local/bin/berth-github-api-broker.cjs: packages/docker-orchestrator/docker/github-api-broker.cjs.
github_api_broker_sha256 = "0a809855c067d76b2074746b2390f6b204d1d80a7cafdc8cea4371efa624baaa"
# /usr/local/bin/berth-egress-broker.cjs: packages/docker-orchestrator/docker/egress-broker.cjs.
Expand Down Expand Up @@ -56,13 +56,13 @@ terminal = "tmux"
# builder.apk.lock the builder's (erofs-utils). .github/workflows/vm-artifacts.yml
# rebuilds it on a Linux runner and fails on any other hash. berth-vmm
# compiles this in; berth-vmm run boots it by default.
image_sha256 = "4f4e67cb49a1b07e96412e802bd2c6e42cfabee95d7c126b8589b1048a79a538"
image_size = 108765184
image_sha256 = "0c623b43a2c2852fd156d1ea6d4f00a8612143299ec7381cf2d1516607d0a9f6"
image_size = 108904448
# Optional layer example (rootfs/layers/example, build-layer.sh), built for the base above.
layer_example_sha256 = "a79169aeed42b12ecb28cf40427439d5870056362ea8728036354137cd6d273d"
layer_example_size = 475136
layer_example_base = "4f4e67cb49a1b07e96412e802bd2c6e42cfabee95d7c126b8589b1048a79a538"
layer_example_base = "0c623b43a2c2852fd156d1ea6d4f00a8612143299ec7381cf2d1516607d0a9f6"
# Optional layer browser (rootfs/layers/browser, build-layer.sh), built for the base above.
layer_browser_sha256 = "ed05e3d09c5de3a01184333174215c4f8a4fe9c1f2f227590290a68724b48641"
layer_browser_size = 511881216
layer_browser_base = "4f4e67cb49a1b07e96412e802bd2c6e42cfabee95d7c126b8589b1048a79a538"
layer_browser_sha256 = "b02cec7e83efe1dcb39b78ebbef5bf30e8ebda082c7b87a4bd30e7375d976fb2"
layer_browser_size = 511885312
layer_browser_base = "0c623b43a2c2852fd156d1ea6d4f00a8612143299ec7381cf2d1516607d0a9f6"
Loading