-
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
22276dc
commit fe4467c
Showing
11 changed files
with
377 additions
and
1 deletion.
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 |
---|---|---|
|
@@ -182,6 +182,20 @@ Set to `1` to allow the service to run without actually writing keys or OS image | |
|
||
WARNING: Setting `DEMO_MODE_ONLY` will cause your seen-devices storage location to change to a subdirectory of the one specified by `RPI_DEVICE_SERIAL_STORE`, `demo/` | ||
|
||
=== BOOT_IMAGE_VENDOR | ||
*Mandatory* for make-boot-image | ||
|
||
Lower-case single-word representation of your organisation name. Used by | ||
make-boot-image service. e.g. `acme` would be appropriate for "Acme | ||
Corporation". | ||
|
||
=== BOOT_IMAGE_MAINTAINER | ||
*Mandatory* for make-boot-image | ||
|
||
A display name and email address in RFC 5322 mailbox format of the individual / | ||
team responsible for creating your boot-image packages. e.g. | ||
`Packaging Team <[email protected]>' | ||
|
||
== Using rpi-sb-provisioner | ||
`rpi-sb-provisioner` is composed of three `systemd` services that are triggered by the connection of a device in RPIBoot mode to a USB port. With `rpi-sb-provisioner` configured to your requirements, all that is therefore required is to connect your target Raspberry Pi device in RPIBoot mode. | ||
|
||
|
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 |
---|---|---|
@@ -1,5 +1,6 @@ | ||
## Format of return will be [Happy: bool, error: str] | ||
from os import path | ||
from email.utils import parseaddr, formataddr | ||
import subprocess | ||
|
||
def validate_CUSTOMER_KEY_FILE_PEM(text) -> tuple[bool, str]: | ||
|
@@ -69,3 +70,26 @@ def validate_RPI_SB_WORKDIR(text) -> tuple[bool, str]: | |
else: | ||
return (False, "Please specify absolute path, beginning with /") | ||
return (True, "") | ||
|
||
def validate_BOOT_IMAGE_VENDOR(text) -> tuple[bool, str]: | ||
if len(text) > 0: | ||
if text.isalpha() and text.islower(): | ||
return (True, "") | ||
else: | ||
return (False, "BOOT_IMAGE_VENDOR must contain only lowercase letters") | ||
else: | ||
return (False, "Please specify a boot image vendor, e.g. \"acme\"") | ||
|
||
def validate_BOOT_IMAGE_MAINTAINER(text) -> tuple[bool, str]: | ||
# TODO: parseaddr/formataddr is now a legacy API. | ||
# Switch to python3-email-validator once v2.2.0 is available in Debian. | ||
# | ||
# parseaddr supports many formats but formataddr always uses RFC 5322 | ||
# mailbox. | ||
# Ensure that both display name and addr-spec address enclosed in angle | ||
# brackets are present. | ||
maint_addr = parseaddr(text) | ||
if all(maint_addr) and formataddr(maint_addr) == text: | ||
return (True, "") | ||
else: | ||
return (False, "BOOT_IMAGE_MAINTAINER must be an RFC 5322 mailbox, e.g. \"Able Maintainer <[email protected]>\"") |
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,6 @@ | ||
#!/bin/sh | ||
|
||
if [ "$1" = install ] | ||
then | ||
rm -f /boot/firmware/config.txt | ||
fi |
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
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 @@ | ||
rootwait console=tty0 console=serial0,115200 root=/dev/ram0 |
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,13 @@ | ||
[all] | ||
kernel=zImage | ||
arm_64bit=1 | ||
initramfs rootfs.cpio.zst | ||
enable_uart=1 | ||
uart_2ndstage=1 | ||
disable_overscan=1 | ||
cmdline=cmdline.txt | ||
|
||
[cm4] | ||
dtoverlay=dwc2,dr_mode=host | ||
|
||
[none] |
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
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 v8 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-v8 | ||
``` | ||
systemctl start make-boot-image@$(systemd-escape 6.6.31+rpt-rpi-v8).service | ||
``` | ||
|
||
To determine the latest v8 linux image (in order to run the service as | ||
suggested above) | ||
``` | ||
META_PKG=linux-image-rpi-v8 | ||
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\x2dv8.service/boot-image-<vendor>-6.6.31+rpt-rpi-v8_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,230 @@ | ||
#!/bin/sh | ||
|
||
set -e | ||
|
||
# deps: | ||
# - dpkg (dpkg-deb) | ||
# - openssl | ||
# - zstd | ||
# - cpio | ||
# - findutils (xargs) | ||
|
||
. /usr/local/bin/terminal-functions.sh | ||
|
||
read_config | ||
|
||
TMPDIR="${TMPDIR:=/tmp}" | ||
|
||
if [ -z "${1}" ]; then | ||
>&2 echo "No linux image specified" | ||
exit 1 | ||
fi | ||
|
||
if [ -z "${RPI_DEVICE_FAMILY}" ]; then | ||
>&2 echo "'RPI_DEVICE_FAMILY' not specified" | ||
exit 1 | ||
fi | ||
|
||
if [ -z "${BOOT_IMAGE_VENDOR}" ]; then | ||
>&2 echo "'BOOT_IMAGE_VENDOR' not specified" | ||
exit 1 | ||
fi | ||
|
||
if [ -z "${BOOT_IMAGE_MAINTAINER}" ]; then | ||
>&2 echo "'BOOT_IMAGE_MAINTAINER' not specified" | ||
exit 1 | ||
fi | ||
|
||
if [ -z "${OPENSSL}" ] || [ ! -f "${OPENSSL}" ]; then | ||
>&2 echo "'OPENSSL' not set or binary 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}}" | ||
|
||
# TODO: Might be interesting to start rpi-package-download with --no-block to | ||
# allow multiple simultaneous downloads. | ||
download_package() { | ||
systemctl start \ | ||
--wait \ | ||
rpi-package-download@"$(systemd-escape "${1}")".service | ||
} | ||
|
||
KERNEL_2711="linux-image-${LINUX_IMAGE}" | ||
>&2 echo "Downloading ${KERNEL_2711}" | ||
download_package "$KERNEL_2711" | ||
|
||
PACKAGE_NAME="boot-image-${BOOT_IMAGE_VENDOR}-${LINUX_IMAGE}" | ||
|
||
# Temp directory cleanup | ||
TEMP_DIRS_LIST=$(mktemp make_boot_image_temp_dirs_list.XXX) | ||
:> "${TEMP_DIRS_LIST}" | ||
remove_temp_dirs() { | ||
>&2 echo "Removing temporary directories" | ||
xargs --null rm -rf < "${TEMP_DIRS_LIST}" | ||
rm -f "${TEMP_DIRS_LIST}" | ||
} | ||
trap remove_temp_dirs EXIT | ||
|
||
>&2 printf "Creating filesystem hierarchy for deb package: " | ||
DEB_HIER="$(mktemp --directory --tmpdir debhier.XXX)" | ||
printf "%s\0" "${DEB_HIER}" >> "${TEMP_DIRS_LIST}" | ||
>&2 echo "${DEB_HIER}" | ||
|
||
>&2 printf "Create rootfs working directory: " | ||
WORK_DIR="$(mktemp --directory --tmpdir boot-image-rootfs.XXX)" | ||
printf "%s\0" "${WORK_DIR}" >> "${TEMP_DIRS_LIST}" | ||
>&2 echo "${WORK_DIR}" | ||
|
||
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_2711")/package.deb" "${WORK_DIR}" | ||
|
||
get_dctrl_field() { | ||
grep-dctrl \ | ||
--field=Package \ | ||
--exact-match "${2}" \ | ||
--no-field-names \ | ||
--show-field="${3}" \ | ||
"${1}" | ||
} | ||
|
||
# Determine package version for later reuse | ||
KERNEL_2711_VERSION="$(get_dctrl_field "${WORK_DIR}/DEBIAN/control" "${KERNEL_2711}" Version)" | ||
>&2 echo "Extracted ${KERNEL_2711}, version ${KERNEL_2711_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 printf "Create ramdisk working directory: " | ||
BFS_DIR="$(mktemp --directory --tmpdir boot-image-bootfs.XXX)" | ||
printf "%s\0" "${BFS_DIR}" >> "${TEMP_DIRS_LIST}" | ||
>&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_2711}/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_2711}/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)" | ||
printf "%s\0" "${INITRAMFS_EXTRACT}" >> "${TEMP_DIRS_LIST}" | ||
zstd -q -d "$(get_cryptroot)" -o "${INITRAMFS_EXTRACT}/initramfs.cpio" | ||
mkdir -p "${INITRAMFS_EXTRACT}/initramfs" | ||
cd "${INITRAMFS_EXTRACT}/initramfs" | ||
RETURN_DIR="${OLDPWD}" | ||
cpio --quiet -id < ../initramfs.cpio > /dev/null | ||
rm ../initramfs.cpio | ||
cd "${WORK_DIR}" | ||
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/" \; | ||
cd - | ||
find . -print0 | cpio --quiet --null -ov --format=newc > ../initramfs.cpio 2> /dev/null | ||
cd "${RETURN_DIR}" | ||
unset RETURN_DIR | ||
zstd -q -6 "${INITRAMFS_EXTRACT}/initramfs.cpio" -o "${BFS_DIR}/rootfs.cpio.zst" | ||
|
||
# raspi-firmware | ||
>&2 echo "Downloading raspi-firmware" | ||
download_package raspi-firmware | ||
|
||
>&2 printf "Create temp directory to extract firmware: " | ||
FW_EXTRACT_DIR="$(mktemp --directory --tmpdir boot-image-firmware.XXX)" | ||
printf "%s\0" "${FW_EXTRACT_DIR}" >> "${TEMP_DIRS_LIST}" | ||
>&2 echo "${FW_EXTRACT_DIR}" | ||
|
||
>&2 echo "Extracting firmware package contents" | ||
dpkg-deb --raw-extract "$(latest_pkg_dir raspi-firmware)/package.deb" "${FW_EXTRACT_DIR}" | ||
|
||
>&2 echo "Add firmware to ramdisk" | ||
rsync -v -crt "${FW_EXTRACT_DIR}/usr/lib/raspi-firmware/" "${BFS_DIR}" | ||
|
||
# cmdline.txt | ||
>&2 echo "Add cmdline.txt to ramdisk" | ||
cp "$(get_ramdisk_cmdline_file)" "${BFS_DIR}/cmdline.txt" | ||
|
||
# Inner config.txt | ||
>&2 echo "Add config.txt to ramdisk" | ||
cp "$(get_internal_config_file)" "${BFS_DIR}/config.txt" | ||
|
||
# Invoke make-boot-image | ||
>&2 echo "Finalise ramdisk in deb package (boot.img)" | ||
mkdir -p "${DEB_HIER}/boot/firmware" | ||
make-boot-image \ | ||
-b "pi${RPI_DEVICE_FAMILY}" \ | ||
-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 "$(get_fastboot_config_file)" "${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" | ||
printf "rsa2048: " >> "${DEB_HIER}/boot/firmware/boot.sig" | ||
# shellcheck disable=SC2046 | ||
${OPENSSL} dgst \ | ||
-sign $(get_signing_directives) \ | ||
-keyform PEM \ | ||
-sha256 \ | ||
"${DEB_HIER}/boot/firmware/boot.img" \ | ||
| xxd -c 4096 -p >> "${DEB_HIER}/boot/firmware/boot.sig" | ||
|
||
# Insert control file | ||
mkdir "${DEB_HIER}/DEBIAN" | ||
echo \ | ||
"Package: ${PACKAGE_NAME} | ||
Source: linux | ||
Version: ${KERNEL_2711_VERSION} | ||
Architecture: arm64 | ||
Maintainer: ${BOOT_IMAGE_MAINTAINER} | ||
Section: kernel | ||
Priority: optional | ||
Homepage: https://github.com/raspberrypi/linux/ | ||
Provides: ${KERNEL_2711} | ||
Conflicts: ${KERNEL_2711} | ||
Replaces: ${KERNEL_2711} | ||
Description: Repackaged ${KERNEL_2711} for signed/cryptroot boot" \ | ||
> "${DEB_HIER}/DEBIAN/control" | ||
|
||
# Insert preinst script to remove /boot/firmware/config.txt (otherwise dpkg | ||
# attempt to create a ".dpkg-tmp" hardlink. | ||
cp "$(get_bootimg_preinst_file)" "${DEB_HIER}/DEBIAN/preinst" | ||
|
||
# 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,10 @@ | ||
[Unit] | ||
Description=Creates a signed boot image using a Raspberry Pi OS kernel / bootloader | ||
|
||
[Service] | ||
Type=oneshot | ||
ExecStart=/usr/local/bin/make-boot-image-from-kernel "%I" | ||
CacheDirectory=%n | ||
|
||
[Install] | ||
WantedBy=multi-user.target |
Oops, something went wrong.