Skip to content

Commit 54dce9a

Browse files
committed
chore: updated readme for block level provenance
1 parent dcaf6cc commit 54dce9a

1 file changed

Lines changed: 84 additions & 57 deletions

File tree

README.md

Lines changed: 84 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,51 @@
1-
This repository reflects the v0.3.0-alpha research prototype described in the submitted manuscript.
1+
This repository reflects the v0.3.0-alpha research prototype described in the submitted manuscript
2+
*"Proportional-Cost Per-Read Provenance: Making Continuous File Integrity Verification Affordable on Edge Hardware."*
23

34
# Axiom OS
45

5-
A bare-metal OS kernel in Rust enforcing BLAKE3 cryptographic
6-
provenance on every file readnot just at load time.
6+
A bare-metal `no_std` Rust kernel that enforces BLAKE3 file-integrity provenance on **every read**
7+
not just at load timeand makes that affordable by verifying only the file blocks a read actually touches.
78

89
## Core Contribution
910

10-
Every `read()` call unconditionally recomputes the BLAKE3 hash
11-
and compares it against the stored provenance record before
12-
returning data. There is no API to bypass this check. The
13-
verification IS the read path.
11+
Most integrity mechanisms verify once: at boot, at open, or when a page is first read from storage
12+
(e.g. fs-verity, dm-verity, IMA). After that, the cached in-memory copy is trusted. Axiom re-verifies
13+
the in-memory data on **every** read, so tampering that happens *after* the initial check (a memory bug,
14+
DMA, a row-hammer flip) is caught on the next read.
1415

15-
This differs architecturally from Linux IMA, which verifies
16-
at file open/exec time only. A file modified in memory after
17-
load is invisible to IMA but blocked by Axiom OS on the next
18-
read.
16+
The naive way to do this — re-hash the whole file on every read — costs O(file size) per read and is
17+
impractical on small devices. Axiom instead uses **block-level provenance**:
18+
19+
- A file is split into fixed 4 KiB blocks; each block has its own stored BLAKE3 leaf hash.
20+
- A ranged read `read_range(offset, len)` maps to the blocks it overlaps and re-hashes **only those blocks**,
21+
comparing each against its stored leaf in constant time. Per-read cost becomes O(bytes read), not O(file size).
22+
- A **lazy Merkle root** over the block leaves gives a single 32-byte commitment to the file; a single-block
23+
write updates one leaf and defers the root recomputation, so writes cost one block hash instead of a full rehash.
24+
25+
This is the affordability result: per-read verification cost stays flat regardless of file size (see Results).
26+
27+
## How it differs from fs-verity / IMA
28+
29+
fs-verity and IMA bind verification to the storage-access path — a page is checked when read from the device,
30+
then trusted in the page cache. They do not re-verify the cached copy on subsequent reads. Axiom's check *is*
31+
the read path, on every read, against per-block hashes. See Table II of the paper for the full comparison.
1932

2033
## Architecture
2134

22-
- **Target:** x86_64 (primary) + ARM64 (QEMU virt)
23-
- **Language:** Rust (no_std, no libc)
24-
- **Lines:** ~3,200
25-
- **Release:** v0.3.0-alpha
35+
- **Target:** x86_64 (primary) + ARM64 (QEMU `virt`)
36+
- **Language:** Rust (`no_std`, no libc)
37+
- **Source:** ~3,600 lines across 36 files
38+
- **Release:** v0.3.0-alpha (research prototype)
2639

27-
**Kernel subsystems:**
28-
GDT/IDT, 8MB linked-list heap, priority scheduler,
29-
per-process page tables (CR3 isolation), IPC message queues,
30-
ATA PIO driver, syscall interface (INT 0x80), 28-command shell
40+
**Kernel subsystems:** GDT/IDT, 8 MB linked-list heap, priority scheduler, per-process page tables
41+
(CR3 isolation), IPC message queues, ATA PIO driver, syscall interface (INT 0x80), interactive shell.
3142

3243
**Provenance layer:**
33-
- VFS: per-read BLAKE3 verify, constant_time_eq comparison
34-
- FAT32: 32-byte hash store at sector 1, full 256-bit comparison
35-
- Mitra DSL: `trusted_data` type routes through kernel read path
44+
- `vfs.rs` — per-block BLAKE3 leaves, `read_range`/`verify_range` (verify only touched blocks),
45+
`write_block` + lazy `merkle_root`, `constant_time_eq` comparison.
46+
- `provenance.rs``provenance_hash` (BLAKE3) and constant-time comparison primitive.
47+
- `fat32.rs` — on-disk hash store for the persistent path.
48+
- `mitra/` — small DSL whose `trusted_data` type routes through the verified read path.
3649

3750
## Quick Start
3851

@@ -43,66 +56,80 @@ rustup target add aarch64-unknown-none
4356
cargo install bootimage
4457
sudo apt install qemu-system-x86 qemu-system-arm nasm
4558

46-
# Boot x86_64
59+
# Boot x86_64 (use the bin target; plain `cargo build` also tries the ARM bin)
4760
cargo run --bin axiom_os
4861

4962
# Boot ARM64
5063
./run_arm.sh
5164
```
5265

53-
## Tamper Detection Demo
54-
55-
trust secret hello world
56-
57-
cat secret # returns: hello world
58-
59-
tamper secret # flips byte in memory
66+
## Tamper-Detection Demo
6067

61-
cat secret # READ BLOCKED: provenance violation
68+
Inside the booted shell:
6269

63-
## Benchmarks
70+
```
71+
trust secret hello world # store a file + its provenance
72+
cat secret # -> hello world
73+
tamper secret # flip a byte in memory
74+
cat secret # -> READ BLOCKED: provenance violation
75+
```
6476

65-
RDTSC bare-metal x86_64, 5 independent cold-boot runs:
77+
## Results
6678

67-
| Operation | Mean cycles/op | CV | Latency @3GHz |
68-
|---|---|---|---|
69-
| BLAKE3 hash | 424,013 | 2.9% | 0.141ms |
70-
| VFS read+verify | 2,153,973 | 3.0% | 0.718ms |
79+
The headline result is **proportional access**: block-level verification cost is constant (~3.6 µs)
80+
across file sizes, while whole-file verification grows with size. Numbers below are **median wall-clock
81+
times on real hardware** (a commodity x86-64 laptop and a mobile-class ARM64 core), produced by the
82+
standalone `bench-native` harness:
7183

72-
BLAKE3 constitutes 19.7% of total read+verify overhead.
84+
| File size | Blocks | x86-64 whole (ms) | x86-64 block (ms) | ARM64 whole (ms) | ARM64 block (ms) |
85+
|---|---|---|---|---|---|
86+
| 4 KiB | 1 | 0.0040 | 0.0037 | 0.0037 | 0.0037 |
87+
| 16 KiB | 4 | 0.0097 | 0.0033 | 0.0143 | 0.0037 |
88+
| 64 KiB | 16 | 0.046 | 0.0035 | 0.057 | 0.0037 |
89+
| 256 KiB | 64 | 0.159 | 0.0037 | 0.230 | 0.0037 |
90+
| 1 MiB | 256 | 0.580 | 0.0035 | 0.923 | 0.0037 |
91+
| 4 MiB | 1024 | 2.51 | 0.0039 | 3.74 | 0.0037 |
7392

74-
## Mitra DSL
93+
Block-level verification is >640× cheaper (x86-64) and >1000× cheaper (ARM64) than whole-file at 4 MiB.
7594

76-
Domain-specific language with kernel-enforced provenance:
95+
Reproduce the real-hardware numbers:
7796

78-
trusted_data secret = classified report
97+
```bash
98+
cd bench-native
99+
cargo run --release # prints the whole-file vs block table for this CPU
100+
```
79101

80-
verify secret → KERNEL VERIFIED
102+
Reproduce the in-kernel proportional ratio under emulation:
81103

82-
[tamper]
104+
```
105+
bench # in the booted shell; RDTSC, proportional-access size sweep
106+
```
83107

84-
verify secret → KERNEL BLOCKED
108+
**Note on QEMU:** in-kernel cycle counts are emulated and are used only to confirm the *ratio*
109+
(block-flat vs whole-file-growing). All absolute millisecond figures above come from real hardware,
110+
not emulation.
85111

86-
## Known Limitations
112+
## Limitations
87113

88-
- QEMU only — UEFI bootloader pending (v0.3.0)
89-
- Single-coreSMP planned
90-
- In-memory VFS — persistence via ATA only
91-
- Pure Rust BLAKE3 — SIMD (NEON/AVX-512) pending
92-
- ARM64 cycle benchmarks invalid on QEMU (CNTVCT_EL0)
114+
- Boots under QEMU; UEFI bootloader for bare-metal boot is pending.
115+
- Single-core; SMP and multi-core verification are future work.
116+
- BLAKE3 runs in portable mode in-kernel (no in-kernel SIMD yet); the native harness uses runtime SIMD.
117+
- Real-hardware results use a consumer laptop and phone; a dedicated embedded SoC (e.g. Raspberry Pi)
118+
measurement is the immediate next step.
93119

94120
## Threat Model
95121

96-
Defends against post-write in-memory tampering by ring-3
97-
processes within a single-core, non-DMA execution model.
98-
Does not defend against ring-0 compromise, DMA attacks,
99-
multicore races, or speculative execution side channels.
122+
Assumes an adversary who can modify a file's in-memory bytes after they were validated, but cannot forge
123+
the stored provenance record (per-block leaves + root); single-core, no DMA, no ring-0. Within this model,
124+
per-read verification **reduces** the TOCTOU window: bytes returned by `read()` are verified at the moment
125+
of return. It does **not** eliminate TOCTOU (corruption after a verified read is out of scope), nor address
126+
replay/splicing on persistent storage or hardware memory-integrity attacks.
100127

101128
## Paper
102129

103-
Under review. Data and full methodology available upon
104-
acceptance.
130+
- Earlier formulation (whole-file per-read, equity framing): Zenodo, Apr. 2026,
131+
[doi:10.5281/zenodo.19387932](https://doi.org/10.5281/zenodo.19387932).
105132

106133
## License
107134

108-
MIT, Apache-2.0
135+
MIT and Apache-2.0

0 commit comments

Comments
 (0)