From 7739d1863cb6ea5de819e1ae1c1ee10e8109d32b Mon Sep 17 00:00:00 2001 From: "Alex Xu (Hello71)" Date: Tue, 21 Apr 2020 23:10:07 -0400 Subject: POSIXify, add docs, other changes --- Makefile | 29 ++++++++++++++++------------- README | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ comp_bench | 21 +++++++++++++++++++++ cpio_list.txt | 12 ++++++++---- init | 2 +- make | 33 +++++++++++++++++++++++++-------- unlock | 2 +- 7 files changed, 128 insertions(+), 27 deletions(-) create mode 100644 README create mode 100755 comp_bench diff --git a/Makefile b/Makefile index 6832bbd..3a2f16b 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,27 @@ -CC = gcc -CFLAGS ?= -O2 -pipe -MAKEFLAGS += -L -R -r - all: initramfs.img -initramfs.img: gen_init_cpio +initramfs.img: gen_init_cpio dropbear_rsa_host_key dropbear_ecdsa_host_key ./make --include initramfs.d - gen_init_cpio: gen_init_cpio.c - $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) gen_init_cpio.c -o $@ + +dropbear_rsa_host_key: + dropbearkey -t rsa -f $@ + +dropbear_ecdsa_host_key: + dropbearkey -t ecdsa -f $@ install: initramfs.img - rm -f /boot/$<.old /boot/$<.new - cp $< /boot/$<.new || rm -f /boot/$<.new - if [ -e /boot/$< ]; then mv /boot/$< /boot/$<.old; fi - mv /boot/$<.new /boot/$< + rm -f /boot/initramfs.img.old /boot/initramfs.img.new + cp initramfs.img /boot/initramfs.img.new || rm -f /boot/initramfs.img.new + if [ -e /boot/initramfs.img ]; then mv /boot/initramfs.img /boot/initramfs.img.old; fi + mv /boot/initramfs.img.new /boot/initramfs.img clean: - rm -f -r initramfs.img initramfs.d gen_init_cpio + rm -f initramfs.img initramfs.d gen_init_cpio + +-include initramfs.d .PHONY: all install clean +MAKEFLAGS += -r # slightly faster diff --git a/README b/README new file mode 100644 index 0000000..4630f38 --- /dev/null +++ b/README @@ -0,0 +1,56 @@ +This is my initramfs generator. I use this on my desktop Gentoo system. For my +laptop Arch system, I use mkinitcpio. + +Basically, it's a suckless initramfs generator: it does exactly what I need. +You need something else? Patch it, it's only 117 lines. + +Features: + +- password LUKS unlock +- SSH remote unlock +- firmware loading +- extremely fast initramfs creation: compression off: ~70ms cold cache, ~30ms + warm; lz4 --best: 1.6s +- extremely fast initramfs runtime: ~zero overhead compared to direct kernel + loading +- minimal code: 117 SLOC total (init + make + Makefile + unlock) +- pure POSIX shell + POSIX Makefile + +Drawbacks: + +- no modprobe support. custom kernel is required to use myinitramfs. if you + want configurability, probably better to use mkinitcpio or dracut. +- pure POSIX shell + POSIX Makefile + +Usage: + +0. Read (skim) https://wiki.gentoo.org/wiki/Custom_Initramfs. + +1. Install busybox, dropbear, e2fsprogs (if you use ext4). + +2. Adjust ./init as required: + a) Adjust networking as required (e.g. maybe static IP instead of DHCP, or + you don't use eth0) + b) Adjust UUID (probably yours is not the same as mine) + c) Adjust fsck as needed (if you are not using ext4) + d) Put whatever you want: + +3. Adjust ./make as required: + a) Put your needed commands in gen_cpio_list. + b) Select your desired compressor at the end. Try make comp_bench for a comparison. + summary: lz4 is usually best, xz if storage is important above all (saves + a few MB but adds ~0.5s to boot), gzip is mediocre on both size and + speed, lzo is almost always worse than lz4, never use bzip2 or lzma. + +4. Customize cpio_list.txt with your required files. Remember that commands + must go in ./make (for library detection), and device files except + /dev/console and non-empty directories can be omitted. + +5. Add your public keys to authorized_keys. Note that dropbear only supports + RSA and ECDSA keys. + +6. make + +7. sudo make install + +8. Configure your boot loader/boot manager to use initramfs.img. diff --git a/comp_bench b/comp_bench new file mode 100755 index 0000000..01387da --- /dev/null +++ b/comp_bench @@ -0,0 +1,21 @@ +#!/bin/sh + +set -e + +do_bench() { + tmpfile=$(mktemp) + trap 'rm -f "$tmpfile"' EXIT + compressor=cat outfile=/proc/self/fd/1 ./make | "$@" -c < initramfs.img > "$tmpfile" + printf '%s: %s bytes\n' "$1" "$(wc -c < "$tmpfile")" + time $1 -dc < "$tmpfile" >/dev/null + rm "$tmpfile" + trap '' EXIT + echo +} + +do_bench gzip -9 +do_bench bzip2 -9 +do_bench lzma -9e --check=crc32 +do_bench xz --check=crc32 --x86 --lzma2=preset=9e +do_bench lzop -9 +do_bench lz4 --best --favor-decSpeed -l diff --git a/cpio_list.txt b/cpio_list.txt index 79b38f0..016170f 100644 --- a/cpio_list.txt +++ b/cpio_list.txt @@ -1,5 +1,8 @@ -# basic directories. note that parent directories for files will be -# auto-generated by make script, and everything will be sorted afterwards +# myinitramfs cpio_list.txt +# see ./gen_init_cpio for syntax + +# basic directories. note that all required parent directories will be +# auto-generated by make, and everything will be sorted afterwards dir /dev 0755 0 0 dir /mnt 0755 0 0 dir /proc 0755 0 0 @@ -7,7 +10,8 @@ dir /run 0755 0 0 dir /run/cryptsetup 0755 0 0 dir /sys 0755 0 0 -# kernel needs this to be available before /init +# kernel does /init <>/dev/console and fails if it doesn't exist in initramfs +# devtmpfs will provide other devices nod /dev/console 0600 0 0 c 5 1 # symlinks @@ -34,7 +38,7 @@ file /lib/firmware/amdgpu/polaris10_uvd.bin /lib/firmware/amdgpu/polaris10_uvd.b file /lib/firmware/amdgpu/polaris10_vce.bin /lib/firmware/amdgpu/polaris10_vce.bin 0644 0 0 file /lib/firmware/rtl_nic/rtl8168h-2.fw /lib/firmware/rtl_nic/rtl8168h-2.fw 0644 0 0 -# dropbear support +# remote unlock file /etc/dropbear/dropbear_ecdsa_host_key ./dropbear_ecdsa_host_key 0600 0 0 file /etc/dropbear/dropbear_rsa_host_key ./dropbear_rsa_host_key 0600 0 0 file /etc/passwd ./passwd 0644 0 0 diff --git a/init b/init index 8df2dda..de10111 100644 --- a/init +++ b/init @@ -18,7 +18,7 @@ udhcpc -i eth0 dropbear -p 2222 ) >/dev/null 2>&1 & -root=$(findfs UUID=26748575-d7a7-418b-8f68-21be7c937500) || exit +root=$(findfs UUID=ec8fb072-1200-4275-9494-f6f869187806) || exit cryptsetup open --tries 65535 --allow-discards "$root" root # in case of /sbin/unlock [ -e /dev/mapper/root ] || exit diff --git a/make b/make index 9f35483..1abf52b 100755 --- a/make +++ b/make @@ -1,17 +1,27 @@ #!/bin/sh -set -e +[ -n "$compressor" ] || compressor="lz4 --best --favor-decSpeed -l" +#[ -n "$compressor" ] || compressor="xz -c --check=crc32 --x86 --lzma2=preset=9e" -compressor="lz4 --best --favor-decSpeed -l" +# for comp_bench +[ -n "$outfile" ] || outfile=initramfs.img + +toppid=$$ +die() { + fmt=$1 + shift + printf "error building initramfs: $fmt\n" "$@" >&2 + kill "$toppid" + trap '' EXIT + exit 1 +} # generate a cpio entry for a command gen_cmd() { cmd=$1 - cmdp="$(command -v "$cmd")" - # builtin - if [ "$cmd" = "$cmdp" ]; then - return - fi + cmdp="$(command -v "$cmd")" || die 'command not found: %s' "$cmd" + # ignore builtins + [ "$cmd" != "$cmdp" ] || return printf 'file %s %s 0755 0 0\n' "$cmdp" "$cmdp" ldd "$cmdp" | grep / | while read line; do tmp=${line% *} @@ -26,8 +36,11 @@ gen_cpio_list() { sed -e '/^#/d' cpio_list.txt gen_cmd e2fsck gen_cmd dropbear + # cryptsetup argon2 uses pthread_cancel, glibc dlopens libgcc_s.so.1 + # ldd will find the correct libgcc_s.so.1 based on ld.so.conf export LD_PRELOAD=libgcc_s.so.1 gen_cmd cryptsetup + # LD_PRELOAD unset at end of subshell } # filter the list and insert parent directory entries @@ -65,9 +78,13 @@ if ! [ -e cpio_list.txt ] || ! [ -e gen_init_cpio ]; then cd "${0%/*}" fi +trap 'test -L initramfs.img || test -f initramfs.img && rm -f initramfs.img; exit 1' HUP INT QUIT TERM EXIT + gen_cpio_list | \ gen_dir_ents | \ sort -u | \ gen_depfile 3>initramfs.d | \ ./gen_init_cpio -t 0 - | \ -$compressor > initramfs.img +$compressor > $outfile + +trap '' EXIT diff --git a/unlock b/unlock index 50d282b..42e30d2 100644 --- a/unlock +++ b/unlock @@ -1,5 +1,5 @@ #!/bin/sh -root=$(findfs UUID=26748575-d7a7-418b-8f68-21be7c937500) || exit +root=$(findfs UUID=ec8fb072-1200-4275-9494-f6f869187806) || exit cryptsetup open --allow-discards "$root" root || exit pkill cryptsetup -- cgit v1.2.3-54-g00ecf