cubelinux: the kernel records its own boot
The second half of "the OS stores itself". The store was already the kernel's; what was missing was the kernel *saying* something of its own rather than a client doing it. At its first write of a boot the driver now appends one record describing the boot it is having — its own version banner, the wall-clock time, and the store device it resolved — to a reserved space, through the same append path every other mutation uses. Three things had to be decided, and each had a wrong answer that looked right: WHERE IT HOOKS. "At store init" does not exist and must not be invented: there is no init-time open, deliberately, so there is no ordering to get wrong against the block driver that provides the device. An __initcall appending a record would reintroduce exactly that ordering problem. The moment is the FIRST WRITE, which needs no ordering at all and is the semantically right one — the kernel records itself when it becomes the writer. A boot in which the kernel only reads writes no record, which is honest rather than a gap. WHICH SPACE. 0xFD was the first choice, following the convention that a reserved space is one repeated byte. 0xFD is the OS KEYSTORE — the space the kill switch exists to destroy — and writing boot records into it would have been a serious bug. Only the userspace name table catches this (format_space in crates/cube-command) because the kernel keeps no table of space names, so the table is now written down where the constant is: 0x00 root, 0xFF edges, 0xFE portal, 0xFD keystore, 0xFC boot. The record lives at (0,0,0) in 0xFC: one record, the current boot. WHAT IT SAYS. boot=<epoch seconds> device=<resolved path> kernel=<the version banner>, banner last and unquoted so everything after the final = is the kernel's own words rather than a field this code parsed. Raw epoch seconds rather than a date: rendering a calendar date in the kernel is date arithmetic, and a caller with a clock can do it without a kernel bug being the reason a timestamp is wrong. The banner comes from linux_banner and the time from ktime_get_real_ts64. WHY IT IS OFF BY DEFAULT. Not caution, but an invariant. The gates' method is that the store the kernel produces is comparable, byte for byte, with the store userspace produces from the same mutations; a record the kernel injects that the caller never asked for would turn those comparisons into non-comparisons. So it is cube_boot_record=1 on the kernel command line, parsed in C beside cube_store= for the reason that parameter is in C (this kernel's Rust cannot express a string parameter), and kernel/verify-boot-record.sh is the gate that turns it on. A failure to record is logged and never propagated: the record is worth having and is not a precondition for the caller's write. It is attempted once per boot rather than retried per write, because a store that will not take it will not take it later, and one warning is information where a stream of them is noise.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cube.h>
|
||||
|
||||
@@ -84,6 +85,34 @@ const char *cubelinux_store_device(void)
|
||||
return store_device_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Whether the kernel should record its own boots in the store.
|
||||
*
|
||||
* Off unless asked for, and the reason is not caution: the gate method of this tree is that the
|
||||
* store the kernel produces is comparable, byte for byte, with the store userspace produces from the
|
||||
* same mutations. A record the kernel injects that the caller never asked for would turn two of
|
||||
* those comparisons into non-comparisons. So it is a command-line switch, beside `cube_store=`,
|
||||
* and the gate that proves it is the one that turns it on.
|
||||
*
|
||||
* cube_store=/var/lib/cubelinux/store.img cube_boot_record=1
|
||||
*
|
||||
* The hook itself is not here: it lives in the Rust driver and fires at the first write of a boot,
|
||||
* which is named and argued where it is implemented (`BOOT_SPACE` in cubelinux_store.rs).
|
||||
*/
|
||||
static bool boot_record_enabled;
|
||||
|
||||
static int __init cube_boot_record_setup(char *str)
|
||||
{
|
||||
boot_record_enabled = (str[0] == '1');
|
||||
return 1;
|
||||
}
|
||||
__setup("cube_boot_record=", cube_boot_record_setup);
|
||||
|
||||
bool cubelinux_boot_record_enabled(void)
|
||||
{
|
||||
return boot_record_enabled;
|
||||
}
|
||||
|
||||
/* No value may be larger than this in one call. A coordinate store is not a bulk-file path;
|
||||
* a caller with more than this to store has more than one record to store. */
|
||||
#define CUBE_MAX_VALUE (16u * 1024u * 1024u)
|
||||
|
||||
Reference in New Issue
Block a user