Early boot: Difference between revisions
Line 92: | Line 92: | ||
== Upgrade procedure == |
== Upgrade procedure == |
||
Upgrade procedure, creating new b from a (w.l.o.g) |
|||
Suppose that we want to create a new OS tree named ''$b'' where ''$b'' cryptographically identifies the [[contents manifest specification|contents]] of the desired OS tree.) |
|||
Rainbow: (ATC gives <version> <hash> <priority>) |
|||
# Check that /versions/pristine/<hash> doesn't already exist. |
|||
⚫ | |||
⚫ | |||
⚫ | |||
1. Create /versions/configs/$c/current -> ../../pristine/`basename(readlink /versions/running)` |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
# Create /versions/configs/$c/current -> ../../pristine/$a |
|||
⚫ | |||
/versions/running (revisit when multiple trees) |
|||
3b. Delete corresponding members of /boot-versions if using a boot partition |
|||
''(If partitioned: Make /boot/alt point to ../$a.)'' |
|||
⚫ | |||
4b. Delete corresponding member of /boot-versions if using a boot partition. |
|||
Afterward, we should: |
|||
5. Invoke 'olpc-updater <version>' |
|||
# Delete the tree(s) pointed to from ''/versions/configs/$old'' which are: |
|||
in new container: |
|||
#* not pointed to by ''/versions/running'' |
|||
[MICHAEL WILL REWRITE STARTING FROM HERE] |
|||
#* not pointed to by a symlink in ''/versions/sticky'' |
|||
NOTE THAT /upgrade must live in same bind-mount as /current if we're to be able to clone it. |
|||
MORE LIKELY THAT RAINBOW WILL CREATE /upgrade FOR US AS CLONE OF /current |
|||
''(If partitioned and if using a boot partition: delete corresponding members of /boot-versions.)'' |
|||
/current (ro-bind mount from /versions/a) |
|||
/upgrade (initially empty) |
|||
⚫ | |||
OLPC updater: |
|||
''(If partitioned and if using a boot partition: delete corresponding member of /boot-versions.)'' |
|||
6. clone /current to /upgrade |
|||
# '''Shallow-copy''' ''/versions/pristine/$a'' into a tmpdir ''$d'' on the same file system. (To ''shallow-copy'' a tree is to copy its directory structure, then to hardlink all its inodes into the new empty tree.) |
|||
7. upgrade /upgrade by hook or crook |
|||
# Modify the contents of ''$d'' by any means that breaks hardlinks before writing through them. When finished, |
|||
[END MICHAEL REWRITES] |
|||
# Cryptographically [[Olpc-contents|verify]] that ''$b'' identifies the contents of the tmpdir ''$d''. |
|||
8. exit |
|||
#* If verification fails, destroy ''$d'' and return failure. Otherwise... |
|||
Rainbow: |
|||
# Move ''$d'' to ''/versions/pristine/$b''. |
|||
# Create ''/versions/run/$b'' from ''/versions/pristine/$b'' according to the current [[OLPC Bitfrost:P_SF_RUN|P_SF_RUN]] setting. |
|||
10b. Create /versions/run/<hash> from /versions/pristine/<hash> according to P_SF_RUN setting |
|||
Then, if unpartitioned: |
|||
11. Make a new config /versions/configs/$d (d = mkdtemp) |
|||
# Make a new config in ''/versions/configs/$e'' with ''mkdtemp''. |
|||
# Point its 'current' symlink to ''/versions/pristine/$b''. |
|||
# Point its 'alt' symlink to ''(realpath /versions/running)''. |
|||
# ATOMICALLY swing ''/versions/boot'' to ''/versions/configs/$e''. |
|||
(atomic! iff we do file move of new symlink) |
|||
#* (To atomically swing a symlink $s, make a new symlink $t on the same filesystem pointing to the desired location and then rename ''$t'' on top of ''$s''.) |
|||
# Delete /versions/configs/$c |
|||
If partitioned: |
|||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
16. If <priority> reboot. (Ask Eben & sugar folks) |
|||
⚫ | |||
⚫ | |||
Finally, execute any post-update instructions. |
|||
==Open Questions== |
==Open Questions== |
Revision as of 00:19, 23 June 2008
NOTE: The contents of this page are not set in stone, and are subject to change! This page is a draft in active flux ... |
Draft of early boot upgrade/init procedures designed by Michael Stone and C. Scott Ananian.
Early userland startup steps
Stage 1: Initramfs
See the source code for more details. Instructions are available for building initramfsen.
- Control is passed to the initramfs' /init program.
- This program runs python2.5 as PID 1.
- /init executes the theft deterrence protocol, checking its 'am I stolen?' flag and looking for a valid activation lease.
- /init will decide whether to fail the boot.
- If the boot should stop, then a graphical error message will be displayed.
- If the boot should continue, then /init will fork and will prepare to execute the userland init program.
Stage 2: NAND
Since /init forked, we are now running as PID NNN rather than PID 1.
- Mount /sysroot and unmount our USB or SD devices so that our userland can make its own decisions about how to handle them.
- Fail the boot if we think we're stolen.
- If requested, swing /versions/current to point at the backup OS tree.
- If necessary, make the filesystem upgradable.
- Start the boot animation.
- Make a minimal userland context (e.g. mount --move /sysroot /).
- Take any measures that might help protect PID 1 and the real-time clock (RTC).
Stage 3: Userland
- make new config w/ swapped current and alt
- (ie. create a /versions/configs/XXX w/ new current, alt)
- then swing /versions/boot symlink
If multiple partitions are present:
- Make boot:/boot/alt/alt point to ../`basename(readlink boot:/boot)`
- Make boot:/boot point to boot-versions/`basename(readlinke boot:/boot/alt)`
In either case:
- Make the /versions/running symlink point to pristine/<hash>
- Set $current equal to the basename of readlink of /versions/running (which should be a hash)
- Make appropriate bind-mounts:
- mount /home /versions/run/$current/home (or /home from home partition)
- mount /security /versions/run/$current/security (or /security from boot partition)
- mount /versions /versions/run/$current/versions
- chroot or mount --move into /versions/run/$current
Finally, run the userland init program.
- Import and run the run() function from /sbin/olpc_init.py if it exists; otherwise,
- Exec /sbin/init.
Notes on P_SF_RUN
P_SF_RUN is a Bitfrost protection intended to control when running programs may modify the 'run' image of the current OS tree. (P_SF_CORE controls modifications to the pristine versions of OS trees.)
Suppose we're going to boot an OS tree named X.
- When P_SF_RUN is switched off, we should make /versions/run/X copy-on-write.
- When P_SF_RUN is switched on, we should boot from an immutable copy of the pristine version of X.
These rules mean that:
- If P_SF_RUN is off then we should allow modifications.
- If P_SF_RUN is on then we should prohibit modifications.
List of directories in boot partition
/boot -> boot-versions/<hash> /boot-alt -> boot/alt /boot-versions/<version>/{runos.zip,runrd.zip,etc} /boot-versions/<version>/alt -> ../<alternate version> /security
List of directories in root partition
/sys, /proc, /ofw vfs /versions/pristine/{hashes} /versions/contents/{hashes} (contents files for the corresponding pristine tree) /versions/configs/`mkdtemp`/current -> ../../pristine/<hash> (backwards compatibility; don't use) /versions/configs/`mkdtemp`/alt -> ../../pristine/<hash> (backwards compatibility; don't use) /versions/boot -> configs/<something> (backwards compatibility; don't use) /versions/running -> pristine/<hash> (version we booted from; hash matches /boot symlink from boot partition) /versions/updates/<hash> (temporary space for updates, preserved in case update net connection drops & updater is restarted) /versions/run/{hashes} /security /boot -> versions/boot/current/boot (backwards compatibility; don't use) /boot-alt -> versions/boot/alt/boot (backwards compatibility; don't use)
List of directories in home partition
/home
Upgrade procedure
Suppose that we want to create a new OS tree named $b where $b cryptographically identifies the contents of the desired OS tree.)
- Check that /versions/pristine/<hash> doesn't already exist.
- Let $a = `basename(readlink /versions/running)`.
If we are unpartitioned, then we may:
- Create new /versions/configs/$c <- where $c = mkdtemp
- Create /versions/configs/$c/current -> ../../pristine/$a
- Swing /versions/boot to point to configs/$c, save old contents in $old
(If partitioned: Make /boot/alt point to ../$a.)
Afterward, we should:
- Delete the tree(s) pointed to from /versions/configs/$old which are:
- not pointed to by /versions/running
- not pointed to by a symlink in /versions/sticky
(If partitioned and if using a boot partition: delete corresponding members of /boot-versions.)
- Delete /versions/configs/$old.
(If partitioned and if using a boot partition: delete corresponding member of /boot-versions.)
- Shallow-copy /versions/pristine/$a into a tmpdir $d on the same file system. (To shallow-copy a tree is to copy its directory structure, then to hardlink all its inodes into the new empty tree.)
- Modify the contents of $d by any means that breaks hardlinks before writing through them. When finished,
- Cryptographically verify that $b identifies the contents of the tmpdir $d.
- If verification fails, destroy $d and return failure. Otherwise...
- Move $d to /versions/pristine/$b.
- Create /versions/run/$b from /versions/pristine/$b according to the current P_SF_RUN setting.
Then, if unpartitioned:
- Make a new config in /versions/configs/$e with mkdtemp.
- Point its 'current' symlink to /versions/pristine/$b.
- Point its 'alt' symlink to (realpath /versions/running).
- ATOMICALLY swing /versions/boot to /versions/configs/$e.
- (To atomically swing a symlink $s, make a new symlink $t on the same filesystem pointing to the desired location and then rename $t on top of $s.)
- Delete /versions/configs/$c
If partitioned:
- Copy /versions/pristine/$b/boot to boot:/boot-versions/$b
- Make boot:/boot-versions/$b/alt point to (realpath boot:/boot).
- Atomically swing boot:/boot to point to boot:/boot-versions/%b
Finally, execute any post-update instructions.
Open Questions
- Are thawed trees persistent?
- when I use a frozen tree?
- when I upgrade
- Is "thawness" global? Or per-OS-version?
- Can thawed trees be frozen for temporary read-only use?
- Space limits for upgrader?
- UI for:
- P_SF_RUN
- which image you boot (esp if more than two)
- Rest of security UI
- Configuration versioning / globalness
- do security settings persist across updates
- do we inherit a security configuration from the 'old' version when upgrading?
- Loadable kernel modules
- Bind-mount /lib/modules read-only? (Doesn't fix the problem, really)