-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Richard Oliver <[email protected]>
- Loading branch information
1 parent
7afb239
commit 9f8ea1e
Showing
4 changed files
with
276 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# make-boot-image | ||
A oneshot service to download the specified Raspberry Pi linux-image- and | ||
create a replacement boot-image- package. This replacement package contains a | ||
signed boot.img with a cryptroot-enabled initramfs. The kernel modules are | ||
retained in the replacement package. Necessary firmware file are inserted into | ||
the signed boot.img where appropriate (via raspi-firmware package). | ||
|
||
> [!CAUTION] | ||
> Support only exists for 2712 kernels at this time. | ||
## Configuration | ||
- VENDOR | ||
- OPENSSL | ||
- CUSTOMER\_KEY\_FILE\_PEM | ||
|
||
## Usage | ||
To create a replacement boot-image- package for linux-image-6.6.31+rpt-rpi-2712 | ||
``` | ||
systemctl start make-boot-image@$(systemd-escape 6.6.31+rpt-rpi-2712).service | ||
``` | ||
|
||
To determine the latest 2712 linux image (in order to run the service as | ||
suggested above) | ||
``` | ||
META_PKG=linux-image-rpi-2712 | ||
SRV=rpi-package-download@$(systemd-escape $META_PKG).service | ||
systemctl start --wait $SRV \ | ||
&& grep-dctrl -F Package -X $META_PKG -n -s Depends /var/cache/$SRV/latest/Packages \ | ||
| grep -o '^[[:graph:]]*' | ||
``` | ||
|
||
The service makes use of systemd's CacheDirectory during execution. The boot-image- package created by the example given above would typically be found at: | ||
``` | ||
/var/cache/[email protected]\x2brpt\x2drpi\x2d2712.service/boot-image-<vendor>-6.6.31+rpi-rpi-2712_6.6.31-1+rpt1_arm64.deb | ||
``` |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
|
||
# deps: | ||
# - dpkg (dpkg-deb) | ||
# - openssl | ||
# - zstd | ||
# - cpio | ||
|
||
# TODO: Currently, we just assume we're Pi5/2712. | ||
# There is currently no functionality to insert firmware for Pi4 and earlier. | ||
|
||
TMPDIR="${TMPDIR:=/tmp}" | ||
|
||
if [[ -z "${1}" ]]; then | ||
>&2 echo "No linux image specified" | ||
exit 1 | ||
fi | ||
|
||
if [[ -z "${VENDOR}" ]]; then | ||
>&2 echo "'VENDOR' not specified" | ||
exit 1 | ||
fi | ||
|
||
if [[ -z "${OPENSSL}" || ! -f "${OPENSSL}" ]]; then | ||
>&2 echo "'OPENSSL' not set or binary does not exist" | ||
exit 1 | ||
fi | ||
|
||
if [[ -z "${CUSTOMER_KEY_FILE_PEM}" || ! -f "${CUSTOMER_KEY_FILE_PEM}" ]]; then | ||
>&2 echo "'CUSTOMER_KEY_FILE_PEM' not set or file does not exist" | ||
exit 1 | ||
fi | ||
|
||
LINUX_IMAGE="${1}" | ||
|
||
# Should be set by systemd | ||
SERVICE_NAME="make-boot-image@$(systemd-escape $LINUX_IMAGE).service" | ||
CACHE_DIRECTORY="${CACHE_DIRECTORY:=/var/cache/${SERVICE_NAME}}" | ||
RUNTUME_DIRECTORY="${RUNTIME_DIRECTORY:=/run/${SERVICE_NAME}}" | ||
|
||
# TODO: Might be interesting to start rpi-package-download with --no-block to | ||
# allow multiple simultaneous downloads. | ||
function download_package() { | ||
systemctl start \ | ||
--wait \ | ||
rpi-package-download@$(systemd-escape ${1}).service | ||
} | ||
|
||
KERNEL_2712="linux-image-${LINUX_IMAGE}" | ||
>&2 echo "Downloading ${KERNEL_2712}" | ||
download_package "$KERNEL_2712" | ||
|
||
PACKAGE_NAME="boot-image-${VENDOR}-${LINUX_IMAGE}" | ||
|
||
# Temp directory cleanup | ||
TEMP_DIRS=() | ||
function remove_temp_dirs() { | ||
>&2 echo "Removing temporary directories" | ||
for dir in "${TEMP_DIRS[@]}" | ||
do | ||
rm -rf "$dir" | ||
done | ||
} | ||
trap remove_temp_dirs EXIT | ||
|
||
>&2 echo -n "Creating filesystem hierarchy for deb package: " | ||
DEB_HIER="$(mktemp --directory --tmpdir debhier.XXX)" | ||
TEMP_DIRS+=("${DEB_HIER}") | ||
>&2 echo "${DEB_HIER}" | ||
|
||
>&2 echo -n "Create rootfs working directory: " | ||
WORK_DIR="$(mktemp --directory --tmpdir boot-image-rootfs.XXX)" | ||
TEMP_DIRS+=("${WORK_DIR}") | ||
>&2 echo "${WORK_DIR}" | ||
|
||
function latest_pkg_dir() { | ||
echo "/var/cache/rpi-package-download@$(systemd-escape ${1}).service/latest" | ||
} | ||
|
||
>&2 echo "Extracting package contents" | ||
dpkg-deb --raw-extract "$(latest_pkg_dir $KERNEL_2712)/package.deb" "${WORK_DIR}" | ||
|
||
function get_dctrl_field() { | ||
grep-dctrl \ | ||
--field=Package \ | ||
--exact-match "${2}" \ | ||
--no-field-names \ | ||
--show-field="${3}" \ | ||
"${1}" | ||
} | ||
|
||
# Determine package version for later reuse | ||
KERNEL_2712_VERSION="$(get_dctrl_field ${WORK_DIR}/DEBIAN/control ${KERNEL_2712} Version)" | ||
>&2 echo "Extracted ${KERNEL_2712}, version ${KERNEL_2712_VERSION}" | ||
|
||
# rootfs kernel modules | ||
>&2 echo "Copy kernel modules into deb package" | ||
mkdir -p "${DEB_HIER}/lib/modules" | ||
rsync -crt "${WORK_DIR}/lib/modules/"* "${DEB_HIER}/lib/modules" | ||
|
||
>&2 echo -n "Create ramdisk working directory: " | ||
BFS_DIR="$(mktemp --directory --tmpdir boot-image-bootfs.XXX)" | ||
TEMP_DIRS+=("${BFS_DIR}") | ||
>&2 echo "${BFS_DIR}" | ||
|
||
# Kernel Images | ||
>&2 echo "Copy kernel to ramdisk" | ||
cp "${WORK_DIR}/boot/vmlinuz-${LINUX_IMAGE}" "${BFS_DIR}/zImage" | ||
|
||
# Overlays | ||
>&2 echo "Copy overlays to ramdisk" | ||
OVERLAY_PATH="${WORK_DIR}/usr/lib/${KERNEL_2712}/overlays" | ||
rsync -crt "${OVERLAY_PATH}"/*.dtb* "${OVERLAY_PATH}/README" "${BFS_DIR}/overlays" | ||
|
||
# DTBs | ||
>&2 echo "Copy DTBs to ramdisk" | ||
DTB_PATH="${WORK_DIR}/usr/lib/${KERNEL_2712}/broadcom" | ||
rsync -crt "${DTB_PATH}"/bcm27*.dtb "${BFS_DIR}" | ||
|
||
# Insert an initramfs | ||
>&2 echo "Add cryptoot initramfs to ramdisk (with necessary kernel modules)" | ||
INITRAMFS_EXTRACT="$(mktemp --directory --tmpdir initramfs-extract.XXX)" | ||
TEMP_DIRS+=("${INITRAMFS_EXTRACT}") | ||
zstd -q -d /usr/share/misc/cryptroot_initramfs -o "${INITRAMFS_EXTRACT}/initramfs.cpio" | ||
mkdir -p "${INITRAMFS_EXTRACT}/initramfs" | ||
pushd "${INITRAMFS_EXTRACT}/initramfs" > /dev/null | ||
cpio --quiet -id < ../initramfs.cpio > /dev/null | ||
rm ../initramfs.cpio | ||
pushd "${WORK_DIR}" > /dev/null | ||
find lib/modules \ | ||
\( \ | ||
-name 'dm-mod.*' \ | ||
-o \ | ||
-name 'dm-crypt.*' \ | ||
-o \ | ||
-name 'af_alg.*' \ | ||
-o \ | ||
-name 'algif_skcipher.*' \ | ||
-o \ | ||
-name 'libaes.*' \ | ||
-o \ | ||
-name 'aes_generic.*' \ | ||
-o \ | ||
-name 'aes-arm64.*' \ | ||
\) \ | ||
-exec cp -r --parents "{}" "${INITRAMFS_EXTRACT}/initramfs/usr/" \; | ||
popd > /dev/null | ||
find . -print0 | cpio --quiet --null -ov --format=newc > ../initramfs.cpio 2> /dev/null | ||
popd > /dev/null | ||
zstd -q -6 "${INITRAMFS_EXTRACT}/initramfs.cpio" -o "${BFS_DIR}/rootfs.cpio.zst" | ||
|
||
# cmdline.txt | ||
>&2 echo "Add cmdline.txt to ramdisk" | ||
# TODO: Needs to be user-modifiable | ||
echo "rootwait console=tty0 console=serial0,115200 root=/dev/ram0" > "${BFS_DIR}/cmdline.txt" | ||
|
||
# Inner config.txt | ||
>&2 echo "Add config.txt to ramdisk" | ||
# TODO: Needs to be user-modifiable | ||
echo \ | ||
'[all] | ||
kernel=zImage | ||
initramfs rootfs.cpio.zst | ||
enable_uart=1 | ||
uart_2ndstage=1 | ||
disable_overscan=1 | ||
cmdline=cmdline.txt | ||
[cm4] | ||
dtoverlay=dwc2,dr_mode=host | ||
[none] | ||
' > "${BFS_DIR}/config.txt" | ||
|
||
# Invoke make-boot-image | ||
>&2 echo "Finalise ramdisk in deb package (boot.img)" | ||
mkdir -p "${DEB_HIER}/boot/firmware" | ||
# TODO: Assuming pi5 here | ||
make-boot-image \ | ||
-b pi5 \ | ||
-d "${BFS_DIR}" \ | ||
-o "${DEB_HIER}/boot/firmware/boot.img" > /dev/null | ||
|
||
# Outer config.txt | ||
>&2 echo "Add config.txt to deb package (ensure boot.img is used)" | ||
cp /usr/share/misc/boot_ramdisk_config.txt "${DEB_HIER}/boot/firmware/config.txt" | ||
|
||
# boot.sig generation | ||
>&2 echo "Signing ramdisk image" | ||
sha256sum "${DEB_HIER}/boot/firmware/boot.img" | awk '{print $1}' > "${DEB_HIER}/boot/firmware/boot.sig" | ||
echo -n "rsa2048: " >> "${DEB_HIER}/boot/firmware/boot.sig" | ||
${OPENSSL} dgst \ | ||
-sign "${CUSTOMER_KEY_FILE_PEM}" \ | ||
-keyform PEM \ | ||
-sha256 \ | ||
"${DEB_HIER}/boot/firmware/boot.img" \ | ||
| xxd -c 4096 -p >> "${DEB_HIER}/boot/firmware/boot.sig" | ||
|
||
# Insert control file | ||
# TODO: Needs to be user modifiable | ||
# TODO: depends on kmod, linux-base, etc? | ||
# TODO: breaks for fwupdate, initramfs-tools, etc? | ||
mkdir "${DEB_HIER}/DEBIAN" | ||
echo \ | ||
"Package: ${PACKAGE_NAME} | ||
Source: linux | ||
Version: ${KERNEL_2712_VERSION} | ||
Architecture: arm64 | ||
Maintainer: John Smith <[email protected]> | ||
Section: kernel | ||
Priority: optional | ||
Homepage: https://github.com/raspberrypi/linux/ | ||
Provides: ${KERNEL_2712} | ||
Conflicts: ${KERNEL_2712} | ||
Replaces: ${KERNEL_2712} | ||
Description: TODO: Provide a better description" \ | ||
> "${DEB_HIER}/DEBIAN/control" | ||
|
||
# Create Debian package | ||
dpkg-deb --build "${DEB_HIER}" "${CACHE_DIRECTORY}" |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[Unit] | ||
Description=Creates a signed boot image using a Raspberry Pi OS kernel / bootloader | ||
|
||
[Service] | ||
Type=oneshot | ||
EnvironmentFile=/etc/rpi-sb-provisioner/config | ||
ExecStart=/usr/local/bin/make-boot-image-from-kernel "%I" | ||
CacheDirectory=%n | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -143,6 +143,8 @@ depends: | |
- dctrl-tools | ||
- diffutils | ||
- findutils | ||
- dpkg | ||
- zstd | ||
|
||
# Recommended packages. (overridable) | ||
# This will expand any env var you set in the field, e.g. ${RECOMMENDS_BLA} | ||
|
@@ -228,6 +230,12 @@ contents: | |
- src: rpi-package-download/rpi-package-download | ||
dst: /usr/local/bin/rpi-package-download | ||
|
||
- src: make-boot-image/make-boot-image.service | ||
dst: /usr/local/lib/systemd/system/[email protected] | ||
|
||
- src: make-boot-image/make-boot-image-from-kernel | ||
dst: /usr/local/bin/make-boot-image-from-kernel | ||
|
||
# This will add all files in some/directory or in subdirectories at the | ||
# same level under the directory /etc. This means the tree structure in | ||
# some/directory will not be replicated. | ||
|