volume-manager: the flip — fat is spawned, confined, and handed its channel (V3b)
The load-bearing step. The FAT service stops acquiring its own volume: the volume manager spawns it (per volume), defines its partition range on the storage driver BEFORE it runs, and answers its startup hello with the range-confined block channel over a new volume-manager protocol. fat never finds its storage by name and never sees the whole device — establishment by lineage, one layer up from the driver tree. - New library/protocol/volume-manager: one verb, hello(volume-id) -> the block channel as the reply capability (the P0 reply-cap path). - The volume manager becomes the confinement CONTROLLER: it defines the first range on usb-storage, so no other party can confine a filesystem. It supervises the filesystems it spawns and respawns one on death (the reap- and-rebuild the device manager proved, one layer up). - fat: drops acquireVolume(device-manager); hellos the volume manager for its channel; reads its volume id from argv[1]. main takes process.Init now. - init.csv no longer spawns fat (the volume manager does); protocol.csv rewires fat to be supervised by the volume manager (bind vfs, open volume-manager) and drops fat open device-manager. - The block-range fixture boots registry + device-manager only (not the full tree), so the volume manager is absent and the fixture stays the sole confinement definer — otherwise the volume manager would take the controller first and refuse it. Verified end to end (VM probes -> spawns fat -> confines it -> hands over the channel -> fat mounts) and neutral: 18/18 across the fat family, logging, shutdown, both IOMMU variants, usb restart, vfs, conformance, confinement.
This commit is contained in:
@@ -3036,11 +3036,13 @@ fn fatMountTest(boot_information: *const BootInformation) void {
|
||||
result();
|
||||
}
|
||||
|
||||
/// Per-sender range confinement (V2a, docs/volume-manager-plan.md): boot the
|
||||
/// full tree so the USB storage chain is up, then spawn block-range-test, which
|
||||
/// Per-sender range confinement (V2a, docs/volume-manager-plan.md): the fixture
|
||||
/// acquires the block channel, confines ITSELF to a sub-range, and asserts it
|
||||
/// cannot read past that range or widen it. The fixture's markers are the
|
||||
/// assertion (the QEMU expect regex matches them); this only boots and spawns.
|
||||
/// cannot read past that range or widen it. Boots init in REGISTRY-ONLY mode
|
||||
/// plus the device manager (which brings up the USB storage chain) — deliberately
|
||||
/// NOT the full tree, because the volume manager would take the confinement
|
||||
/// controller first and refuse the fixture's define_range. Without it the fixture
|
||||
/// is the sole definer, exactly as the volume manager is in a real boot.
|
||||
fn blockRangeTest(boot_information: *const BootInformation) void {
|
||||
log("DANOS-TEST-BEGIN: block-range\n", .{});
|
||||
if (boot_information.initial_ramdisk_len == 0) {
|
||||
@@ -3055,8 +3057,8 @@ fn blockRangeTest(boot_information: *const BootInformation) void {
|
||||
return;
|
||||
};
|
||||
process.setInitialRamdisk(ramdisk);
|
||||
const spawned = if (process.spawnBundled("/system/services/init")) true else |_| false;
|
||||
check("init spawned (boots the USB storage chain)", spawned);
|
||||
check("registry (init) spawned", spawnRegistry(rd));
|
||||
check("device-manager spawned (boots the USB storage chain)", spawnNamed(rd, "device-manager"));
|
||||
check("block-range-test spawned", spawnNamedWithArg(rd, "block-range-test", "run"));
|
||||
result();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user