From 5a5c27ab9f646cafdb226c8fbcacb958870008df Mon Sep 17 00:00:00 2001 From: Daniel Barlow Date: Fri, 6 Sep 2024 22:37:49 +0100 Subject: [PATCH] think --- THOUGHTS.txt | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/THOUGHTS.txt b/THOUGHTS.txt index 3d0e57d..8cc0e2b 100644 --- a/THOUGHTS.txt +++ b/THOUGHTS.txt @@ -5982,3 +5982,208 @@ bordervm - set the hostname somehow on loaclhost (actually we could just hardcode the url in tangc.fnl) - export 7654 in qemu somewhow + +Mon Sep 2 21:49:05 BST 2024 + +TODO - Things we haven't done yet, ideas to consider + +[done] 1) improve popen2, maybe using coroutines for proper async chat + +2) allow on-device not-in-store netrc so it could be kept in 0700. +Could just do authFile = "/mnt/store/blah" + +[done] 3) we're not using luaposix on the host so maybe we can drop it in +write-fennel? + +[done] 4) add nodefaultroute to default ppp-options + +[done] 5) implement if-modified-since in json-to-fstree + +6) clean up some copy-paste (e.g. literal_or_output or whatever we call it) +- [done] ppp variants are consolidated, but there's still more to do here + +7) remove references to kexecboot + +8) performance testing + +9) revive ax3200 port and fix ubifs + +10) rebuild our wifi APs and lenscap to use levitate and outboard secrets + +11) [outside scope] secrets server on arthur, and oidc too? + +12) remove errors from ersatz coldplug + +13) teach anoia.svc how to write/remove .lock and state + +14) log kernel messages + +15) log shipping to something useful + +16) standardise error messages in fennel. using assert() is not good +for errors like "the file is missing or can't be opened" because +the backtrace is voluminous and usually inaccurate + +we could have something like check-ok which looks for the +common multiple-return (nil errmsg) pattern, we'd like a similar +one for the lualinux (nill errno) pattern. + +17) fix with nixpkgs unstable + +Wed Sep 4 21:45:07 BST 2024 + +blurb for audit: + +Liminix is a Linux/Nix-based OS that can be flashed to consumer WiFi +routers of the kind that OpenWrt usually runs on (usually small MIPS +or ARM SBCs). Its USP is that because it's based on Nix, the +configuration of your device is based on a text file: there's no GUI +or other imperative interface allowing you to make changes that you +will forget you did six months later and have to recreate when you +update to a new version of the system. + +tl;dr C, nftables, Lua (Fennel even better), shell, Nix. No specific +timeline from my end (unless nlnet have told you otherwise). IMO, +emphasis on network vulnerabilities rather than anything involving local +escalation: nobody is expected to be logged in locally except for +maintenance purposes in which case they're trusted by definition. + +If you want to start by seeing it running, unless you have a +supported device then your best bet would be to build it for Qemu +. It boots +to a root console shell (there is no password on the serial console +because if you have that level of physical access on a real device +it's game over anyway) so take a look at the process list and +filesystem and generally poke around. The filesystem is read-only +unless you configure it otherwise. + + +To do a "static" audit: a rough breakdown of the contents, by volume, would look like this: + +1) 95% of it is packages in the Nix package system (and the Linux +kernel). Some of the packages are built with different compilation +options to produce smaller output, and in a few cases I've patched +them, so someone with C experience might be suited to look at those +patches. + +``` +[dan@loaclhost:~/src/liminix]$ find pkgs/ -name \*.patch +pkgs/kernel/phram-allow-cached-mappings.patch # relevant to dev devices not production +pkgs/kernel/mips-malta-fdt-from-bootloader.patch # for qemu only +pkgs/kernel/cmdline-cookie.patch +pkgs/dropbear/add-authkeyfile-option.patch +pkgs/u-boot/0002-virtio-init-for-malta.patch # only used in tests +pkgs/u-boot/0001-add-ubifs-to-boot-targets.patch # only used in tests +pkgs/xl2tpd-exit-on-close.patch +pkgs/qemu/arm-image-friendly-load-addr.patch # only used in tests +pkgs/kernel-backport/gentree-writable-outputs.patch # unused +pkgs/openwrt/make-mtdsplit-jffs2-endian-agnostic.patch +pkgs/mtdutils/0001-mkfs.jffs2-add-graft-option.patch # can be removed +pkgs/kexec-map-file.patch # can be removed +``` + +dropbear (ssh) and xl2tpd (l2tp) are network-accessible. The kernel +is a high-impact target, but cmdline-cookie.patch is the only "production" +patch there so hopefully easy to review + +Significant packages with custom config options: + +* hostapd (configured for libtommath, internal TLS) +* nftables (--with-mini-gmp) +* openssl "no-threads" and patches to Configure to build on MIPS + +My assumption with all of these is that the package authors wouldn't +provide these as configuration knobs if they weren't reasonably confident +they work as advertised, but I am willing to hear otherwise. + +2) the device has a firewall using nftables. The user gets to choose +their firewall rules, but the default ruleset +https://gti.telent.net/dan/liminix/src/branch/main/modules/firewall/default-rules.nix +is based on RFC 6092 for IPv6 and "received wisdom" for IPv4: I would +very much like a second pair of eyes on this. + +3) Code which is original to Liminix: as far as possible I've used a +high-level language (Fennel, which is a Lisp syntax that transpiles to +Lua) for "original" development. There is one C package +(pkgs/preinit) and some C glue to expose interfaces to Lua. + +None of the original code listens to the network (except Unix-domain +sockets). At least, it was never intended to :-) + +Highlights: + +pkgs/devout : fills the same role as udev (listens to a kernel socket + and a unix domain socket) + +pkgs/json-to-fstree : does HTTP GET and POST requests, using a port of the +FreeBSD libfetch code (see pkgs/fetch-freebsd) + +pkgs/tangc : is a transliteration from bash script to Fennel of +https://github.com/latchset/clevis/blob/master/src/pins/tang/clevis-decrypt-tang +and +https://github.com/latchset/clevis/blob/master/src/pins/tang/clevis-encrypt-tang + +I call this one out specially because it's crypto-adjacent, but all the +actual cryptography happens in "jose" which it invokes as a subprocess + +pkgs/min-copy-closure contains some shell scripts which leverage cpio +and ssh to update a running device over the network. My shell +scripting is probably worse than my C, so take a look + +4) there is a mechanism to configure the device's secrets (PPP +password, ssh keys, etc) by fetching a JSON file from an HTTPS server, +and then generating configuration files for the various services that +use those secrets. This is mostly Fennel (so, Lua) + + +5) the init/service supervision system is based on s6/s6-rc (again, C +software). I don't know if this has ever had an external audit, but to +my eyes it looks like it's been written with security in mind. + +Thu Sep 5 10:12:11 BST 2024 + +if-modified-since and fenceposts ... + +we set the mtime of "." to last-modified on retrieve. what resolution +is the timestamp? empirically (using stat(1)), tmpfs seems to have +sub-second resolution, so no loss of data + +Thu Sep 5 11:15:24 BST 2024 + +how do we do deadlock-free popen2? need to use select or poll +on the input and output fds, and read/write a chunk when one of them is ready + +(subprocess ["/usr/games/advent" "advent"] + { + :on-stdout #(print (ll.read %1)) + :on-stderr #(print "ERR" (ll.read %1)) + :on-stdin #(ll.write %1 "go north\n") + }) + +for send/expect things, a single callback would be preferable if +it has a reason it's being called + +(subprocess ["/usr/games/advent" "advent"] + (fn talk [stream fd] + (match stream + :out (print (ll.read fd)) + :err (print "ERR" (ll.read fd)) + :in (ll.write %1 "go north\n")))) + +because it can be hooked up to a coroutine. The coroutine is then +responsible for doing things in the right order to avoid letting buffers +fill up - probably this is just a matter of dealing with the +subprocess output before sending it more that it can choke on + +wat about partial writes? the coroutine is presumably keeping some +kind of state so it can check the return of ll.write when it updates that +state + + +Fri Sep 6 19:57:37 BST 2024 + +video editing + +* there are ppp credentials onscreen at 13:00 + +* should finish at 33:00