Compare commits

...

2 Commits

Author SHA1 Message Date
Lance Vick d737fce6ea
Working EFI/Bios Stagex boot 2024-06-18 01:45:21 -07:00
Lance Vick e886bc51fa
working vm-bios and vm-efi targets 2024-06-17 11:56:18 -07:00
15 changed files with 482 additions and 85 deletions

View File

@ -6,16 +6,38 @@ FROM stagex/cpio AS cpio
FROM stagex/linux-airgap AS linux
FROM stagex/mtools AS mtools
FROM stagex/xz AS xz
FROM stagex/eudev AS eudev
FROM stagex/keyfork AS keyfork
FROM stagex/openpgp-card-tools AS openpgp-card-tools
FROM stagex/gpg AS gpg
FROM stagex/bash AS bash
FROM stagex/grub:local AS grub
FROM stagex/npth AS npth
FROM stagex/libksba AS libksba
FROM stagex/libgpg-error AS libgpg-error
FROM stagex/libassuan AS libassuan
FROM stagex/libgcrypt AS libgcrypt
FROM stagex/jq AS jq
FROM stagex/bc AS bc
FROM stagex/git AS git
FROM stagex/zlib AS zlib
FROM stagex/tpm2-tools AS tpm2-tools
FROM stagex/tpm2-tss AS tpm2-tss
FROM stagex/openssl AS openssl
FROM stagex/pcsc-lite AS pcsc-lite
FROM stagex/flashtools AS flashtools
FROM scratch AS base
ARG VERSION development
ARG GIT_TIMESTAMP null
ARG GIT_AUTHOR null
ARG GIT_REF null
ARG GIT_KEY null
COPY --from=busybox . /
COPY --from=musl . /
COPY --from=xorriso . /
COPY --from=cpio . /
COPY --from=mtools . /
COPY --from=linux . /
COPY --from=syslinux . /
COPY --from=xz . /
COPY --from=grub . /
@ -25,41 +47,55 @@ FROM base AS build
COPY --from=linux /bzImage iso/boot/vmlinuz
## Initramfs
COPY --from=stagex/busybox . initramfs
COPY --chmod=0755 <<-EOF initramfs/init
#!/bin/sh
/bin/sh
COPY --from=busybox . initramfs
COPY --from=eudev . initramfs
COPY --from=musl . initramfs
COPY --from=zlib . initramfs
COPY --from=npth . initramfs
COPY --from=libksba . initramfs
COPY --from=libgpg-error . initramfs
COPY --from=libassuan . initramfs
COPY --from=libgcrypt . initramfs
COPY --from=keyfork . initramfs
COPY --from=bash . initramfs
COPY --from=gpg . initramfs
COPY --from=jq . initramfs
COPY --from=bc . initramfs
COPY --from=git . initramfs
COPY --from=flashtools . initramfs
COPY --from=tpm2-tools . initramfs
COPY --from=tpm2-tss . initramfs
COPY --from=openssl . initramfs
COPY --from=pcsc-lite . initramfs
COPY --from=openpgp-card-tools . initramfs
COPY rootfs/ initramfs
COPY <<-EOF initramfs/etc/environment
export VERSION="$VERSION"
export GIT_TIMESTAMP="$GIT_TIMESTAMP"
export GIT_AUTHOR="$GIT_AUTHOR"
export GIT_REF="$GIT_REF"
export GIT_KEY="$GIT_KEY"
EOF
RUN <<-EOF
set -eux
cd initramfs
find . \
| cpio -o -H newc \
| gzip -9 \
> ../iso/boot/initramfs
cd initramfs
find . -print0 \
| cpio --null --create --verbose --format=newc \
| gzip --best > ../iso/boot/initramfs
EOF
## Grub (EFI Boot)
COPY <<-EOF iso/boot/grub/grub.cfg
menuentry "Linux Airgap" {
linux /boot/vmlinuz
initrd /boot/initramfs
}
EOF
COPY <<-EOF grub_early.cfg
search --no-floppy --set=root --label "Airgap"
set prefix=(\$root)/boot/grub
EOF
COPY config/grub.cfg iso/boot/grub/grub.cfg
COPY config/grub_early.cfg grub_early.cfg
RUN <<-EOF
set -eux
mkdir -p iso/efi/boot
mkdir -p efi/boot
grub-mkimage \
--config="grub_early.cfg" \
--prefix="/boot/grub" \
--output="iso/efi/boot/bootx64.efi" \
--format="x86_64-efi" \
--config="grub_early.cfg" \
--prefix="/boot/grub" \
--output="efi/boot/bootx64.efi" \
--format="x86_64-efi" \
--compression="xz" \
all_video \
all_video \
disk \
part_gpt \
part_msdos \
@ -71,44 +107,24 @@ RUN <<-EOF
efi_gop \
fat \
iso9660 \
cat \
echo \
ls \
test \
true \
help \
gzio
EOF
RUN <<-EOF
gzio \
serial \
terminal
mformat -i iso/boot/grub/efi.img -C -f 1440 -N 0 ::
mcopy -i iso/boot/grub/efi.img iso/efi
mcopy -i iso/boot/grub/efi.img -s efi ::
touch -md "@0" iso/boot/grub/efi.img
EOF
## Syslinux (BIOS Boot)
COPY <<-EOF iso/boot/syslinux/syslinux.cfg
TIMEOUT 2
PROMPT -1
DEFAULT Airgap
LABEL Airgap
MENU LABEL Linux Airgap
KERNEL /boot/vmlinuz
INITRD /boot/initramfs
EOF
RUN <<-EOF
mkdir -p iso/boot/syslinux
for file in \
isohdpfx.bin \
isolinux.bin \
ldlinux.c32 \
libutil.c32 \
libcom32.c32 \
mboot.c32; \
do
mv /usr/share/syslinux/$file iso/boot/syslinux/$file || return 1
done
EOF
COPY config/syslinux.cfg iso/boot/syslinux/
COPY --from=syslinux \
/usr/share/syslinux/isohdpfx.bin \
/usr/share/syslinux/isolinux.bin \
/usr/share/syslinux/ldlinux.c32 \
/usr/share/syslinux/libutil.c32 \
/usr/share/syslinux/libcom32.c32 \
/usr/share/syslinux/mboot.c32 \
iso/boot/syslinux/
## Build Hybrid EFI/BIOS ISO
FROM build AS install
@ -118,6 +134,7 @@ RUN xorrisofs \
-joliet \
-rational-rock \
-sysid LINUX \
-volid "airgap" \
-isohybrid-mbr iso/boot/syslinux/isohdpfx.bin \
-eltorito-boot boot/syslinux/isolinux.bin \
-eltorito-catalog boot/syslinux/boot.cat \
@ -132,5 +149,5 @@ RUN xorrisofs \
iso/
FROM scratch AS package
COPY --from=install /iso /iso
COPY --from=install /initramfs /initramfs
COPY --from=install /airgap.iso /

View File

@ -1,27 +1,42 @@
VERSION := $(shell git tag --points-at HEAD)
GIT_REF := $(shell git log -1 --format=%H)
GIT_AUTHOR := $(shell git log -1 --format=%an)
GIT_KEY := $(shell git log -1 --format=%GP)
GIT_TIMESTAMP := $(shell git log -1 --format=%cd --date=iso)
.DEFAULT_GOAL :=
.PHONY: default
default: \
out/airgap.iso
.PHONY: vm
vm: out/airgap.iso
qemu-system-x86_64 \
-m 512M \
-machine pc \
-nographic \
-cdrom "out/airgap.iso"
vm: vm-bios
.PHONY: vm-uefi
vm-uefi:
.PHONY: vm-bios
vm-bios: out/airgap.iso
qemu-system-x86_64 \
-m 4G \
-machine type=q35 \
-machine pc \
-serial stdio \
-cdrom "out/airgap.iso"
.PHONY: vm-efi
vm-efi: out/airgap.iso
qemu-system-x86_64 \
-m 4G \
-machine pc \
-serial stdio \
-bios /usr/share/ovmf/OVMF.fd \
-cdrom "out/airgap.iso"
out/airgap.iso: Containerfile
out/airgap.iso: Containerfile $(shell git ls-files rootfs)
docker build \
--progress=plain \
--output type=local,dest=out \
--build-arg VERSION="$(or $(VERSION),"development")" \
--build-arg GIT_REF="$(GIT_REF)" \
--build-arg GIT_AUTHOR="$(GIT_AUTHOR)" \
--build-arg GIT_KEY="$(GIT_KEY)" \
--build-arg GIT_TIMESTAMP="$(GIT_TIMESTAMP)" \
-f Containerfile \
.

5
config/grub.cfg Normal file
View File

@ -0,0 +1,5 @@
set timeout=1
menuentry "Linux Airgap" {
linux /boot/vmlinuz init=/init console=ttyS0 console=tty0 ro
initrd /boot/initramfs
}

2
config/grub_early.cfg Normal file
View File

@ -0,0 +1,2 @@
search --no-floppy --set=root --label "airgap"
set prefix=($root)/boot/grub

8
config/syslinux.cfg Normal file
View File

@ -0,0 +1,8 @@
TIMEOUT 2
PROMPT -1
DEFAULT Airgap
LABEL Airgap
MENU LABEL Linux Airgap
KERNEL /boot/vmlinuz
INITRD /boot/initramfs
APPEND init=/init console=ttyS0 console=tty0 ro

55
rootfs/etc/init.d/S01syslogd Executable file
View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="syslogd"
PIDFILE="/var/run/$DAEMON.pid"
SYSLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' syslogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/sbin/$DAEMON" \
-- -n $SYSLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

55
rootfs/etc/init.d/S02klogd Executable file
View File

@ -0,0 +1,55 @@
#!/bin/sh
DAEMON="klogd"
PIDFILE="/var/run/$DAEMON.pid"
KLOGD_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$DAEMON" ] && . "/etc/default/$DAEMON"
# BusyBox' klogd does not create a pidfile, so pass "-n" in the command line
# and use "-m" to instruct start-stop-daemon to create one.
start() {
printf 'Starting %s: ' "$DAEMON"
# shellcheck disable=SC2086 # we need the word splitting
start-stop-daemon -b -m -S -q -p "$PIDFILE" -x "/sbin/$DAEMON" \
-- -n $KLOGD_ARGS
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
stop() {
printf 'Stopping %s: ' "$DAEMON"
start-stop-daemon -K -q -p "$PIDFILE"
status=$?
if [ "$status" -eq 0 ]; then
rm -f "$PIDFILE"
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
restart() {
stop
sleep 1
start
}
case "$1" in
start|stop|restart)
"$1";;
reload)
# Restart, since there is no true "reload" feature.
restart;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

94
rootfs/etc/init.d/S02sysctl Executable file
View File

@ -0,0 +1,94 @@
#!/bin/sh
#
# This script is used by busybox and procps-ng.
#
# With procps-ng, the "--system" option of sysctl also enables "--ignore", so
# errors are not reported via syslog. Use the run_logger function to mimic the
# --system behavior, still reporting errors via syslog. Users not interested
# on error reports can add "-e" to SYSCTL_ARGS.
#
# busybox does not have a "--system" option neither reports errors via syslog,
# so the scripting provides a consistent behavior between the implementations.
# Testing the busybox sysctl exit code is fruitless, as at the moment, since
# its exit status is zero even if errors happen. Hopefully this will be fixed
# in a future busybox version.
PROGRAM="sysctl"
SYSCTL_ARGS=""
# shellcheck source=/dev/null
[ -r "/etc/default/$PROGRAM" ] && . "/etc/default/$PROGRAM"
# Files are read from directories in the SYSCTL_SOURCES list, in the given
# order. A file may be used more than once, since there can be multiple
# symlinks to it. No attempt is made to prevent this.
SYSCTL_SOURCES="/etc/sysctl.d/ /usr/local/lib/sysctl.d/ /usr/lib/sysctl.d/ /lib/sysctl.d/ /etc/sysctl.conf"
# If the logger utility is available all messages are sent to syslog, except
# for the final status. The file redirections do the following:
#
# - stdout is redirected to syslog with facility.level "kern.info"
# - stderr is redirected to syslog with facility.level "kern.err"
# - file dscriptor 4 is used to pass the result to the "start" function.
#
run_logger() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done 2>&1 >&3 | /usr/bin/logger -t sysctl -p kern.err
} 3>&1 | /usr/bin/logger -t sysctl -p kern.info
}
# If logger is not available all messages are sent to stdout/stderr.
run_std() {
# shellcheck disable=SC2086 # we need the word splitting
find $SYSCTL_SOURCES -maxdepth 1 -name '*.conf' -print0 2> /dev/null | \
xargs -0 -r -n 1 readlink -f | {
prog_status="OK"
while :; do
read -r file || {
echo "$prog_status" >&4
break
}
echo "* Applying $file ..."
/sbin/sysctl -p "$file" $SYSCTL_ARGS || prog_status="FAIL"
done
}
}
if [ -x /usr/bin/logger ]; then
run_program="run_logger"
else
run_program="run_std"
fi
start() {
printf '%s %s: ' "$1" "$PROGRAM"
status=$("$run_program" 4>&1)
echo "$status"
if [ "$status" = "OK" ]; then
return 0
fi
return 1
}
case "$1" in
start)
start "Running";;
restart|reload)
start "Rerunning";;
stop)
:;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

29
rootfs/etc/init.d/S10udev Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
# Check for config file and read it
UDEV_CONFIG=/etc/udev/udev.conf
test -r $UDEV_CONFIG || exit 6
. $UDEV_CONFIG
case "$1" in
start)
printf "Populating %s using udev: " "${udev_root:-/dev}"
[ -e /proc/sys/kernel/hotplug ] && printf '\000\000\000\000' > /proc/sys/kernel/hotplug
/sbin/udevd -d || { echo "FAIL"; exit 1; }
udevadm trigger --type=subsystems --action=add
udevadm trigger --type=devices --action=add
udevadm settle --timeout=30 || echo "udevadm settle failed"
echo "done"
;;
stop)
# Stop execution of events
udevadm control --stop-exec-queue
killall udevd
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

70
rootfs/etc/init.d/S20urandom Executable file
View File

@ -0,0 +1,70 @@
#! /bin/sh
#
# Preserve the random seed between reboots. See urandom(4).
#
# Quietly do nothing if /dev/urandom does not exist
[ -c /dev/urandom ] || exit 0
URANDOM_SEED="/var/lib/random-seed"
# shellcheck source=/dev/null
[ -r "/etc/default/urandom" ] && . "/etc/default/urandom"
if pool_bits=$(cat /proc/sys/kernel/random/poolsize 2> /dev/null); then
pool_size=$((pool_bits/8))
else
pool_size=512
fi
init_rng() {
[ -f "$URANDOM_SEED" ] || return 0
printf 'Initializing random number generator: '
dd if="$URANDOM_SEED" bs="$pool_size" of=/dev/urandom count=1 2> /dev/null
status=$?
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
return "$status"
}
save_random_seed() {
printf 'Saving random seed: '
status=1
if touch "$URANDOM_SEED.new" 2> /dev/null; then
old_umask=$(umask)
umask 077
dd if=/dev/urandom of="$URANDOM_SEED.tmp" bs="$pool_size" count=1 2> /dev/null
cat "$URANDOM_SEED" "$URANDOM_SEED.tmp" 2>/dev/null \
| sha256sum \
| cut -d ' ' -f 1 > "$URANDOM_SEED.new" && \
mv "$URANDOM_SEED.new" "$URANDOM_SEED" && status=0
rm -f "$URANDOM_SEED.tmp"
umask "$old_umask"
if [ "$status" -eq 0 ]; then
echo "OK"
else
echo "FAIL"
fi
else
echo "SKIP (read-only file system detected)"
fi
return "$status"
}
case "$1" in
start|restart|reload)
# Carry a random seed from start-up to start-up
# Load and then save the whole entropy pool
init_rng && save_random_seed;;
stop)
# Carry a random seed from shut-down to start-up
# Save the whole entropy pool
save_random_seed;;
*)
echo "Usage: $0 {start|stop|restart|reload}"
exit 1
esac

27
rootfs/etc/init.d/rcK Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Stop all init scripts in /etc/init.d
# executing them in reversed numerical order.
#
for i in $(ls -r /etc/init.d/S??*) ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set stop
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i stop
;;
esac
done

27
rootfs/etc/init.d/rcS Executable file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done

View File

@ -1,11 +1,5 @@
# /etc/inittab
#
# Copyright (C) 2001 Erik Andersen <andersen@codepoet.org>
#
# Note: BusyBox init doesn't support runlevels. The runlevels field is
# completely ignored by BusyBox init. If you want runlevels, use
# sysvinit.
#
# Format for each entry: <id>:<runlevels>:<action>:<process>
#
# id == tty to run on, or empty for /dev/console
@ -14,16 +8,15 @@
# process == program to run
# Startup the system
::sysinit:/bin/mount -t devtmpfs devtmpfs /dev
::sysinit:/bin/mkdir -p /proc /run /dev/pts /dev/shm
::sysinit:/bin/mount -t proc proc /proc
::sysinit:/bin/mount -o remount,rw /
::sysinit:/bin/mkdir -p /dev/pts /dev/shm
::sysinit:/bin/mount -a
::sysinit:/sbin/swapon -a
null::sysinit:/bin/ln -sf /proc/self/fd /dev/fd
null::sysinit:/bin/ln -sf /proc/self/fd/0 /dev/stdin
null::sysinit:/bin/ln -sf /proc/self/fd/1 /dev/stdout
null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts
::sysinit:/etc/init.d/rcS
@ -36,5 +29,4 @@ null::sysinit:/bin/ln -sf /proc/self/fd/2 /dev/stderr
# Stuff to do before rebooting
::shutdown:/etc/init.d/rcK
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

View File

@ -3,8 +3,7 @@ export PATH="/usr/local/bin:/bin:/sbin:/usr/bin:/usr/sbin"
export PS1="[\h \t] \\$ "
export GNUPGHOME=/.gnupg
source /etc/environment
dmesg -n1
cd /root
clear
cat << "EOF"
_ _ ___ ____

2
rootfs/init Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
exec /bin/init