Last active
September 22, 2023 00:53
-
-
Save bboozzoo/010ed5e94ee0f695d1aeece43513a018 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
if [[ -n "$D" ]]; then | |
set -x | |
fi | |
##HELP: Usage: repack-kernel <command> <opts> | |
##HELP: | |
##HELP: Handle extraction of the kernel snap to a workspace directory, and later | |
##HELP: repacking it back to a snap. | |
##HELP: | |
##HELP: Commands: | |
##HELP: setup - setup system dependencies | |
##HELP: extract <snap-file> <target> - extract under <target> workspace tree | |
##HELP: prepare <target> - prepare initramfs & kernel for repacking | |
##HELP: resign <target> - resign kernel.efi with snakeoil keys | |
##HELP: use after calling 'prepare' | |
##HELP: pack <target> - pack the kernel | |
##HELP: cull-firmware <target> - remove unnecessary firmware | |
##HELP: cull-modules - remove unnecessary modules | |
##HELP: | |
setup_deps() { | |
if [[ "$UID" != "0" ]]; then | |
echo "run as root (only this command)" | |
exit 1 | |
fi | |
# carries ubuntu-core-initframfs | |
add-apt-repository ppa:snappy-dev/image -y | |
# TODO: explicitly install inux-firmware as recent u-c-i does not depend on | |
# it, but requires it for building the initrd | |
apt install ubuntu-core-initramfs linux-firmware -y | |
} | |
get_kver() { | |
kerneldir="$1" | |
( | |
cd "$kerneldir" | |
#shellcheck disable=SC2010 | |
ls "config"-* | grep -Po 'config-\K.*' | |
) | |
} | |
extract_kernel() { | |
local snap_file="$1" | |
local target="$2" | |
if [[ -z "$target" ]] || [[ -z "$snap_file" ]]; then | |
echo "usage: prepare <target-dir> <kernel-snap>" | |
exit 1 | |
fi | |
target=$(realpath "$target") | |
mkdir -p "$target" "$target/work" "$target/backup" | |
# kernel snap is huge, unpacking to current dir | |
unsquashfs -d "$target/kernel" "$snap_file" | |
kver="$(get_kver "$target/kernel")" | |
# repack initrd magic, beware | |
# assumptions: initrd is compressed with LZ4, cpio block size 512, microcode | |
# at the beginning of initrd image | |
( | |
cd "$target/kernel" | |
# XXX: ideally we should unpack the initrd, replace snap-boostrap and | |
# repack it using ubuntu-core-initramfs --skeleton=<unpacked> this does not | |
# work and the rebuilt kernel.efi panics unable to start init, but we | |
# still need the unpacked initrd to get the right kernel modules | |
objcopy -j .initrd -O binary kernel.efi "$target/work/initrd" | |
# copy out the kernel image for create-efi command | |
objcopy -j .linux -O binary kernel.efi "$target/work/vmlinuz-$kver" | |
cp -a kernel.efi "$target/backup/" | |
) | |
( | |
cd "$target/work" | |
# this works on 20.04 but not on 18.04 | |
unmkinitramfs initrd unpacked-initrd | |
) | |
# use distro skeleton | |
cp -ar /usr/lib/ubuntu-core-initramfs "$target/skeleton" | |
echo "prepared workspace at $target" | |
echo " kernel: $target/kernel ($kver)" | |
echo " kernel.efi backup: $target/backup/kernel.efi" | |
echo " temporary artifacts: $target/work" | |
echo " initramfs skeleton: $target/skeleton" | |
} | |
prepare_kernel() { | |
local target="$1" | |
if [[ -z "$target" ]]; then | |
echo "usage: repack <extract-tree>" | |
exit 1 | |
fi | |
target=$(realpath "$target") | |
kver="$(get_kver "$target/kernel")" | |
( | |
# all the skeleton edits go to a local copy of distro directory | |
skeletondir="$target/skeleton" | |
cd "$target/work" | |
# XXX: need to be careful to build an initrd using the right kernel | |
# modules from the unpacked initrd, rather than the host which may be | |
# running a different kernel | |
( | |
# accommodate assumptions about tree layout, use the unpacked initrd | |
# to pick up the right modules | |
cd unpacked-initrd/main | |
ubuntu-core-initramfs create-initrd \ | |
--kernelver "$kver" \ | |
--skeleton "$skeletondir" \ | |
--kerneldir "lib/modules/$kver" \ | |
--firmwaredir "$target/kernel/firmware" \ | |
--output "$target/work/repacked-initrd" | |
) | |
# assumes all files are named <name>-$kver | |
ubuntu-core-initramfs create-efi \ | |
--kernelver "$kver" \ | |
--initrd repacked-initrd \ | |
--kernel vmlinuz \ | |
--output repacked-kernel.efi | |
cp "repacked-kernel.efi-$kver" "$target/kernel/kernel.efi" | |
# XXX: needed? | |
chmod +x "$target/kernel/kernel.efi" | |
) | |
} | |
nested_get_snakeoil_key() { | |
local KEYNAME="PkKek-1-snakeoil" | |
if ! [ -f $KEYNAME.key ]; then | |
wget https://raw.githubusercontent.com/snapcore/pc-amd64-gadget/20/snakeoil/$KEYNAME.key | |
wget https://raw.githubusercontent.com/snapcore/pc-amd64-gadget/20/snakeoil/$KEYNAME.pem | |
fi | |
echo "$KEYNAME" | |
} | |
nested_secboot_sign_file() { | |
local FILE="$1" | |
local KEY="$2" | |
local CERT="$3" | |
sbattach --remove "$FILE" | |
sbsign --key "$KEY" --cert "$CERT" --output "$FILE" "$FILE" | |
} | |
resign_kernel() { | |
local target="$1" | |
if [[ -z "$target" ]]; then | |
echo "usage: resign <extract-tree>" | |
exit 1 | |
fi | |
( | |
set -x | |
cd "$target/kernel" | |
keyname="$(nested_get_snakeoil_key)" | |
nested_secboot_sign_file kernel.efi "$keyname.key" "$keyname.pem" | |
) | |
} | |
cull_firmware() { | |
local target="$1" | |
if [[ -z "$target" ]]; then | |
echo "usage: cull-firmware <extract-tree>" | |
exit 1 | |
fi | |
( | |
# XXX: drop ~450MB+ of firmware which should not be needed in under qemu | |
# or the cloud system | |
cd "$target/kernel" | |
rm -rf firmware/* | |
) | |
} | |
cull_modules() { | |
local target="$1" | |
if [[ -z "$target" ]]; then | |
echo "usage: cull-modules <extract-tree>" | |
exit 1 | |
fi | |
target=$(realpath "$target") | |
kver="$(get_kver "$target/kernel")" | |
( | |
cd "$target/kernel" | |
# drop unnecessary modules | |
awk '{print $1}' < /proc/modules | sort > "$target/work/current-modules" | |
#shellcheck disable=SC2044 | |
for m in $(find modules/ -name '*.ko'); do | |
noko=$(basename "$m"); noko="${noko%.ko}" | |
if echo "$noko" | grep -f "$target/work/current-modules" -q ; then | |
echo "keeping $m - $noko" | |
else | |
rm -f "$m" | |
fi | |
done | |
# depmod assumes that /lib/modules/$kver is under basepath | |
mkdir -p fake/lib | |
ln -s "$PWD/modules" fake/lib/modules | |
depmod -b "$PWD/fake" -A -v "$kver" | |
rm -rf fake | |
) | |
} | |
pack() { | |
local target="$1" | |
if [[ -z "$target" ]]; then | |
echo "usage: pack <extract-tree>" | |
exit 1 | |
fi | |
snap pack "$target/kernel" | |
} | |
show_help() { | |
grep '^##HELP:' "$0" | sed -e 's/##HELP: \?//' | |
} | |
opt="$1" | |
shift || true | |
if [[ -z "$opt" ]] || [[ "$opt" == "--help" ]]; then | |
show_help | |
exit 1 | |
fi | |
case "$opt" in | |
setup) | |
setup_deps | |
;; | |
extract) | |
extract_kernel "$@" | |
;; | |
prepare) | |
prepare_kernel "$@" | |
;; | |
cull-modules) | |
cull_modules "$@" | |
;; | |
cull-firmware) | |
cull_firmware "$@" | |
;; | |
pack) | |
pack "$@" | |
;; | |
resign) | |
resign_kernel "$@" | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you very much 💯