Repository navigation
CosmoOS 1.0.8
Upgrades can be fully undone
From this release on, cosmo-upgrade takes a snapshot of the root
before it writes anything -- a boot environment, be-<release> --
and pairs it with the boot set it ran on, in \cosmo\be on the system
partition. cosmo-upgrade --rollback then returns both halves: the boot
set at once, and the root -- packages, /etc and the base system,
byte for byte as they were -- at the reboot it starts itself.
- What you wrote is kept. Files added or changed under
/root,
/homeand/var/logsince the environment was taken are copied,
before any service starts, into/var/lib/cosmo/rollback/<the replaced tree>/. If they cannot all be copied, the replaced tree stays held
(it cannot be deleted) and the next boot tries again. - The replaced tree is an environment too: rolling back again goes
forward to it.cosmo-upgrade --listshows the environments and the
set each one pairs with; the newest two are kept, and--prune
deletes older ones. - A crash at any step boots. The intent is recorded in
\cosmo\be
before anything moves; whatever the machine boots afterwards -- the
newer kernel on the older root, or the older kernel on the newer one --
cosmo-upgrade --repairfinishes what was meant.--statussays when
a repair is needed. - Refused, with nothing written: an upgrade on a root without room
for the environment (the sentence names what is needed and what is
free), while a rollback of the root is pending, and when the root is
not the current set's.
There are no environments for v1.0.7 and earlier, and the upgrade to
v1.0.8 takes none. Those releases keep no snapshots, and their
cosmo-upgrade refuses a system partition that records environments,
which a rollback to one of them would leave behind. The first upgrade
that can be fully undone is the one made from v1.0.8. Rolling back
from v1.0.8 to v1.0.7 returns the boot set and the base system, as
before; packages pkg upgrade changed stay changed.
Package transactions
pkg install, upgrade, remove and rollback are each one
transaction: pkg snapshots the root first and deletes the snapshot when
it is done. If the machine stops in the middle -- pkg install a b with
a in place and b not -- the next boot rolls the root back to the
moment the transaction began, and reboots once to do so. pkg refuses
before changing anything when the root lacks the room.
pkg rollback NAME returns one package to the version installed
before the current one, with its files; the last two versions of each
package are kept in /var/cache/pkg/kept.
While \cosmo\prev holds v1.0.7 or older -- right after upgrading from
it -- pkg takes no snapshot and says so (no transaction: ...): the
first snapshot raises the root to cosmofs format 12, which those kernels
cannot mount. The same rule keeps the upgrade to v1.0.8 from taking an
environment.
Snapshots and rollback from the shell
cosmo-snap takes snapshots of the installed root, lists what each one
holds alone, shows what changed since (cosmo-snap diff), rolls the
system back to one, and makes writable clones. A rollback keeps the tree
it replaces as a snapshot, applies at the next mount, and holds that
snapshot -- it cannot be deleted -- until the boot completes. The guide's "Snapshots and rollback" page has the steps.
Fixes
- A write-back that fails partway keeps what it wrote. On a full
disk, a file closed while its last write-back failed could leave
blocks no file named (fsctl check: leaked) and, for a file
overwritten in place, free blocks the file still named. The inode is
now stored after every write-back, failed or not. - A foreground job owns the terminal from its first instruction. A
shell started fromcosmo-shcould stop itself withSIGTTINbefore
cosmo-shhanded it the terminal.
Known
pkg install -f NAME=VERSION to an older version says it is
"upgraded"; it is a downgrade (backlog PKG-9).
Rolling back and then forward leaves upgrades refused. After
cosmo-upgrade --rollback to v1.0.7 and v1.0.7's own cosmo-upgrade --rollback forward again, the root's record of its base system
(/var/lib/cosmo-upgrade/root-set) still names v1.0.7's set. This
release trusts that record: it refuses every later upgrade ("the root
holds another set's base system than the current set's (a rollback half
done)"), and its own --repair finds nothing to do. Nothing on the
system is wrong but the record. Run CosmoOS 1.0.9's cosmo-upgrade --repair once, from that release's signed cosmo-upgrade package, then
upgrade: see the v1.0.9 notes
and the guide's upgrading page.
Upgrading from v1.0.7
cosmo-upgrade --fetch v1.0.8, reboot, then pkg update && pkg upgrade. No boot environment is taken by this upgrade (above); the
next one is.
Tested: on every change and on both architectures, make test-upgrade
(the published v1.0.3 upgraded to this build and back; then
test-pkgtx's killed transactions and full root, and test-be: an
upgrade, pkg upgrade and a changed /etc rolled back byte for byte,
the operator's files kept, and a crash after each step), and make test-snapshot (a broken system rolled back, three kills during a
rollback, a clone).
About CosmoOS
CosmoOS 1.0.8: the 1.0 roadmap completed. CosmoOS installs to a disk, reboots into it, is used through BusyBox ash, keeps files across reboots, reaches the network by name, accepts an ssh login, and has a verified boot chain and sound randomness, on x86-64 and AArch64 under QEMU.
Start with the user guide. Each architecture's files: cosmoos-ARCH.img (the signed live image), its UEFI loader, kernel.elf, boot.tar, cmdline, the signed manifest, cosmo-upgrade and its signed package. SHA256SUMS.sig is SHA256SUMS's detached signature with the release key below (scripts/modsign.py verify-detached, or cosmo-verify on an installed system); check the files with sha256sum --ignore-missing -c SHA256SUMS.
Release signing key
The loader in these images verifies the kernel, boot archive and command line against this Ed25519 key (and the kernel trusts it for modules and packages):
- public key:
d2c778bcb38775790b6b6e843631bd2e76d6a29ec52296ece6e2d67c1bef41f8 - key id:
36ae7bb4947896ab(the first 8 bytes of SHA-512 of the key; the boot log prints it:verified boot, key 36ae7bb4947896ab) - in the repository:
tools/keys/release-2026.pub
Toolchain
Built and tested in the project's CI images (ci/Dockerfile), pinned by digest:
- toolchain:
ghcr.io/vkuttyp/cosmoos-ci@sha256:f6aee1470b952bdb426b8d55cfcccb734c9c1f4dac50c89edefba4e8be3be385 - litmus:
ghcr.io/vkuttyp/cosmoos-ci@sha256:c8b16f9c652cd99e4a557c08adc451528cc9cd36ba0e9e37b2973feffb15a5a9 - clang 1:19.0-63
- lld 1:19.0-63
- llvm 1:19.0-63
- qemu-system-x86 1:10.0.13+ds-0+deb13u1
- qemu-system-arm 1:10.0.13+ds-0+deb13u1
- ovmf 2025.02-8+deb13u1
- qemu-efi-aarch64 2025.02-8+deb13u1
- mtools 4.0.48-1
- python3 3.13.5-1
- clang-19 1:19.1.7-3+b1
- lld-19 1:19.1.7-3+b1
- llvm-19 1:19.1.7-3+b1
Third-party sources
Fetched and checked against these SHA-256 digests (ports/busybox/busybox.mk, ports/dropbear/dropbear.mk, ports/openssh/openssh.mk, ports/mbedtls/mbedtls.mk):
| Source | Version | SHA-256 |
|---|---|---|
| BusyBox | 1.37.0 | 3311dff32e746499f4df0d5df04d7eb396382d7e108bb9250e7b519b837043a4 |
| musl | 1.2.5 | a9a118bbe84d8764da0ea0d28b3ab3fae8477fc7e4085d90102b8596fc7c75e4 |
| compiler-rt | 19.1.7 | c12b6e764202c615c1a3af9a13d477846878757ae0e29e5f8979215a6958fffc |
| dropbear | 2026.94 | e098034a843699200c8c977a991fff73159735bf795d5f72ef672c41a6b1ae81 |
| OpenSSH portable (sftp-server only) | 10.6p1 | a9dc9565dffe8640f64d863cd29a32bc4a3dbdec0566a7fc44c5d6ee767d5f39 |
| mbedTLS | 3.6.7 | a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6 |
| CA certificates (curl's extract of Mozilla's) | 2026-09-25 | a41b5d356aea97a529fe27e0f7316d2f9d946d75927476cf9cf1b90637d00505 |
Reproducibility
Each architecture was built twice from the tag v1.0.8, in two fresh containers of the toolchain image above, with the release key; every file below was identical in both:
- x86_64: two builds, 10 files each, identical; cosmoos-x86_64.img sha256 b8fcb78fb088847bd0c650d1814415e20be86437b091704079a62435a68a5282
- aarch64: two builds, 10 files each, identical; cosmoos-aarch64.img sha256 02e33a872c0d76cd23f4f80ebc09445f19694c469aabb03b06b58b2194ff22c8
To rebuild: check out the tag, run the toolchain image above, and make ARCH=<arch> SIGNING=release MODSIGN_KEY=<key> KEYRING_PUBS=tools/keys/release-2026.pub release. Without the private key, a build with your own key differs in what the key reaches: the key ring compiled into the kernel and loader, the signatures on modules, packages and the manifest, and the archive and image that hold them.
SHA256SUMS
b8fcb78fb088847bd0c650d1814415e20be86437b091704079a62435a68a5282 cosmoos-x86_64.img
115ef94c7916d2ba01ed3127701506beb2cc8199f6835a4e4489966fa34ffb67 cosmoos-x86_64-BOOTX64.EFI
f3c02a3b09d120ccdaba2ebb9d4bb7ced18dc555e5b338399d2e0861c3fdd291 cosmoos-x86_64-kernel.elf
829c5c632a62c5a1ce0de459bca8d2409ba8f6d2e096f53e9250da78e68dbcc1 cosmoos-x86_64-boot.tar
7a77470be4312a22db40932c6cd8ddcd6d42a29b07101cbbe135cbfa1fc1aa14 cosmoos-x86_64-cmdline
31c126b5c87115fb2748066194fc3e61bebd1b0b2b9fb858c7ad568105f6b548 cosmoos-x86_64-manifest
5752a899f9a7c7ea8f7836a9dd723ae70c12dd9187a4e0ab7048d57fd75056f4 cosmoos-x86_64-cosmo-upgrade
43e701eb448e992c5d29988b788a8429417c8e909fbbeb623f8c3970fc2119a9 cosmoos-x86_64-cosmo-upgrade.cpk
02e33a872c0d76cd23f4f80ebc09445f19694c469aabb03b06b58b2194ff22c8 cosmoos-aarch64.img
0d00053d85654789deaf9fa0edc5cb8231d8d142140c1198bcb38cfedc8ff87e cosmoos-aarch64-BOOTAA64.EFI
6946cae370e62bc093b6d2b50e823db108daded3c8c9ccc6fdfdff976ca6b702 cosmoos-aarch64-kernel.elf
4241b632e933b27d93207f690cbbb7c0da164e1854611b5e736ff80e843e58eb cosmoos-aarch64-boot.tar
7a77470be4312a22db40932c6cd8ddcd6d42a29b07101cbbe135cbfa1fc1aa14 cosmoos-aarch64-cmdline
95962f05c37942724276698823e02ee95f19f3757e5a018ca0789dacb6ab5c1a cosmoos-aarch64-manifest
70ca5968498f87b5fe64582fffbf8c690b352dd8515e3a9874858334ae56613d cosmoos-aarch64-cosmo-upgrade
855e4132dcef40ea42ff05e9a196a5a14a4ff16df946162ba7703028c58d0ff3 cosmoos-aarch64-cosmo-upgrade.cpk
Known limitations
What CosmoOS 1.0 does not do, or does differently from what you may
expect. Each item names where it is recorded; the work that remains
after 1.0 is in docs/plan.md, and the full list of known
gaps in the deferred-work inventory.
Machines
- QEMU is the tested platform. x86-64 on
q35and AArch64 onvirt
are tested by CI; there is no physical hardware matrix. Since v1.0.1
the AArch64 image boots on Parallels Desktop 27 on Apple Silicon, and
since v1.0.3 installs on its NVMe disks and has a network there; its
SATA disks are not seen (Tested platforms). Out of scope for 1.0
(roadmap): GPU and display beyond a text console (on
the firmware's framebuffer, or a virtio-gpu adapter at the display's
own size: no 3D, cursor or display interface for programs), hotplug, NUMA, more than 64 CPUs, huge pages, live migration,
RAID-Z, eBPF, and the Intel VMX backend on hardware. - Randomness from the weakest source last. The pool seeds from the
CPU's random instructions, the firmware'sEFI_RNG_PROTOCOLor a
virtio-rng; with none of them (Parallels Desktop) a timing-jitter source
seeds it, credited conservatively (docs/kernel/security/design.md §6).
random.jitter=offon the command line turns that off, and the pool
then never seeds there. The commands in this guide add-device virtio-rng-pci. - The clock is stepped, not slewed. The wall clock is set at boot
from the RTC or, with none (Parallels), the firmware's time. Since
v1.0.4 root can set it (date -s,hwclock -wwhere there is an RTC)
andntpd -qsteps it once from a server; there is no NTP daemon,
becauseadjtimexis not implemented, and no time zone. - No Wi-Fi, Bluetooth or sound.
Boot and security
- Verified boot covers the loader's three files (kernel, boot archive,
command line). The root filesystem is not verified; the loader is
not signed for UEFI Secure Boot; there is no TPM measurement
and no rollback protection for manifests or modules (inventory
2.9). - No KASLR: the kernel is at a fixed address. User-space ASLR covers
the stack, heap,mmapand PIE executables; a non-PIE (ET_EXEC)
program loads at its fixed address. - One user, root. Privileges, not uids, separate what processes may
do (Privileges). A root session holding fewer
privileges can still rewrite files in/etcthat a later boot runs
with all of them (M5 report, inventory 2.9).
Shell and commands
- The commands are the BusyBox applets listed in the shell
page: noping6; no hard links; no/sys. /prochas the process directories and a fixed set of system files
(meminfo,stat,loadavg,uptime,mounts,version,
cpuinfo). A process has no nice value and no user/system split of its
CPU time;ps'sTTcolumn is a pair of Linux device numbers (5,1
for the console), since devices here have none of their own; and a
process'senvironis what exec gave it, not what it has since written
over (inventory §13).- The terminal driver honours the common modes (canonical input, echo,
signals, raw mode, window size); most other termios flags and control
characters are accepted and ignored (inventory 1.4). - No swap.
Networking
wget's certificate authorities are fixed in the image
(/etc/ssl/certs/ca-certificates.crt, as built); nothing updates them,
and there is no certificate revocation check
(Networking).- The address comes from DHCP. There is no runtime tool to set one by
hand;/etc/resolv.confis written once per boot, not on lease
renewal; the DHCP client does no ARP probe or DECLINE, no INIT-REBOOT,
no RELEASE, and ignores classless routes (option 121) (inventory 2.5). - IPv6 is link-local; there is no IPv6 routing beyond the link, no IP
fragmentation, and no TCP SACK, window scaling or timestamps
(inventory 2.5). - ssh is dropbear with key login only (Ed25519 or RSA), root only;
no port forwarding (ssh).
Storage
- cosmofs files are capped at 516128 blocks of 4 KiB (about 1.97 GiB),
64516 blocks (252 MiB) when encrypted; a larger write fails with
EFBIG. - A read-only mount still writes the replay of an interrupted free or
orphan record, as a journalling filesystem replays its journal. - A rollback to a snapshot takes effect at the next boot (or the next
mount of another filesystem), not in the running system
(Snapshots and rollback); a clone of a clone, and a
snapshot of a clone, are not possible; no RAID-Z, no resilvering
(backlog CFS-9, CFS-13). - A root disk that appears late (USB storage) is not waited for: init
stays on the live root and says so.
Packages
- A network repository is fetched whole, file by file: no mirrors, no
delta updates. Its index's freshness is only as good as the clock, which
is stepped by hand or byntpd -q, with no NTP daemon
(Packages). cosmo-upgrade --rollbackreturns packages and/etconly to a boot
environment, which upgrades made by v1.0.8'scosmo-upgradeand later
take; past an upgrade made by v1.0.7 or older it returns the boot set and
the base system only (Upgrading). Only
files under/root,/homeand/var/logwritten after the upgrade
are kept across a rollback; the root is rolled back at the next boot,
never while it runs; one pool.
Linux programs
- Static and PIE Linux binaries for x86-64 and AArch64 run under the
Linux personality; it is a subset of Linux's system calls, so a
program that needs a missing one getsENOSYS. Dynamically linked
musl programs run through musl's own linker,/lib/ld-musl-$ARCH.so.1,
withlibc.soanddlopen; glibc's has not been
tried. A library with text relocations is refused (W^X); build it
-fPIC. Native CosmoOS programs stay static.
No containers or desktop software (docs/plan.md).