Skip to content

Commit 65eb33b

Browse files
committed
Add make-boot-image service
Signed-off-by: Richard Oliver <[email protected]>
1 parent 05c40b5 commit 65eb33b

File tree

8 files changed

+317
-1
lines changed

8 files changed

+317
-1
lines changed

host-support/config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ RPI_DEVICE_EEPROM_WP_SET=
99
DEVICE_SERIAL_STORE=/usr/local/etc/rpi-sb-provisioner/seen
1010
DEMO_MODE_ONLY=
1111
RPI_SB_WORKDIR=
12+
BOOT_IMAGE_VENDOR=
13+
BOOT_IMAGE_MAINTAINER=

host-support/ramdisk_cmdline.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rootwait console=tty0 console=serial0,115200 root=/dev/ram0
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[all]
2+
kernel=zImage
3+
arm_64bit=1
4+
initramfs rootfs.cpio.zst
5+
enable_uart=1
6+
uart_2ndstage=1
7+
disable_overscan=1
8+
cmdline=cmdline.txt
9+
10+
[cm4]
11+
dtoverlay=dwc2,dr_mode=host
12+
13+
[none]

host-support/terminal-functions.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ get_fastboot_config_file() {
132132
fi
133133
}
134134

135+
get_internal_config_file() {
136+
if [ -f /etc/rpi-sb-provisioner/ramdisk_internal_config.txt ]; then
137+
echo "/etc/rpi-sb-provisioner/ramdisk_internal_config.txt"
138+
else
139+
echo "/var/lib/rpi-sb-provisioner/ramdisk_internal_config.txt"
140+
fi
141+
}
142+
143+
get_ramdisk_cmdline_file() {
144+
if [ -f /etc/rpi-sb-provisioner/ramdisk_cmdline.txt ]; then
145+
echo "/etc/rpi-sb-provisioner/ramdisk_cmdline.txt"
146+
else
147+
echo "/var/lib/rpi-sb-provisioner/ramdisk_cmdline.txt"
148+
fi
149+
}
150+
135151
get_signing_directives() {
136152
if [ -n "${CUSTOMER_KEY_PKCS11_NAME}" ]; then
137153
echo "${CUSTOMER_KEY_PKCS11_NAME} -engine pkcs11 -keyform engine"
@@ -148,4 +164,4 @@ get_signing_directives() {
148164
exit 1
149165
fi
150166
fi
151-
}
167+
}

make-boot-image/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# make-boot-image
2+
A oneshot service to download the specified Raspberry Pi linux-image- and
3+
create a replacement boot-image- package. This replacement package contains a
4+
signed boot.img with a cryptroot-enabled initramfs. The kernel modules are
5+
retained in the replacement package. Necessary firmware file are inserted into
6+
the signed boot.img where appropriate (via raspi-firmware package).
7+
8+
> [!CAUTION]
9+
> Support only exists for v8 kernels at this time.
10+
11+
## Configuration
12+
- VENDOR
13+
- OPENSSL
14+
- CUSTOMER\_KEY\_FILE\_PEM
15+
16+
## Usage
17+
To create a replacement boot-image- package for linux-image-6.6.31+rpt-rpi-v8
18+
```
19+
systemctl start make-boot-image@$(systemd-escape 6.6.31+rpt-rpi-v8).service
20+
```
21+
22+
To determine the latest v8 linux image (in order to run the service as
23+
suggested above)
24+
```
25+
META_PKG=linux-image-rpi-v8
26+
SRV=rpi-package-download@$(systemd-escape $META_PKG).service
27+
systemctl start --wait $SRV \
28+
&& grep-dctrl -F Package -X $META_PKG -n -s Depends /var/cache/$SRV/latest/Packages \
29+
| grep -o '^[[:graph:]]*'
30+
```
31+
32+
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:
33+
```
34+
/var/cache/[email protected]\x2brpt\x2drpi\x2dv8.service/boot-image-<vendor>-6.6.31+rpt-rpi-v8_6.6.31-1+rpt1_arm64.deb
35+
```
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
# deps:
6+
# - dpkg (dpkg-deb)
7+
# - openssl
8+
# - zstd
9+
# - cpio
10+
# - findutils (xargs)
11+
12+
. /usr/local/bin/terminal-functions.sh
13+
14+
read_config
15+
16+
TMPDIR="${TMPDIR:=/tmp}"
17+
18+
if [ -z "${1}" ]; then
19+
>&2 echo "No linux image specified"
20+
exit 1
21+
fi
22+
23+
if [ -z "${RPI_DEVICE_FAMILY}" ]; then
24+
>&2 echo "'RPI_DEVICE_FAMILY' not specified"
25+
exit 1
26+
fi
27+
28+
if [ -z "${BOOT_IMAGE_VENDOR}" ]; then
29+
>&2 echo "'BOOT_IMAGE_VENDOR' not specified"
30+
exit 1
31+
fi
32+
33+
if [ -z "${BOOT_IMAGE_MAINTAINER}" ]; then
34+
>&2 echo "'BOOT_IMAGE_MAINTAINER' not specified"
35+
exit 1
36+
fi
37+
38+
if [ -z "${OPENSSL}" ] || [ ! -f "${OPENSSL}" ]; then
39+
>&2 echo "'OPENSSL' not set or binary does not exist"
40+
exit 1
41+
fi
42+
43+
LINUX_IMAGE="${1}"
44+
45+
# Should be set by systemd
46+
SERVICE_NAME="make-boot-image@$(systemd-escape "$LINUX_IMAGE").service"
47+
CACHE_DIRECTORY="${CACHE_DIRECTORY:=/var/cache/${SERVICE_NAME}}"
48+
49+
# TODO: Might be interesting to start rpi-package-download with --no-block to
50+
# allow multiple simultaneous downloads.
51+
download_package() {
52+
systemctl start \
53+
--wait \
54+
rpi-package-download@"$(systemd-escape "${1}")".service
55+
}
56+
57+
KERNEL_2711="linux-image-${LINUX_IMAGE}"
58+
>&2 echo "Downloading ${KERNEL_2711}"
59+
download_package "$KERNEL_2711"
60+
61+
PACKAGE_NAME="boot-image-${BOOT_IMAGE_VENDOR}-${LINUX_IMAGE}"
62+
63+
# Temp directory cleanup
64+
TEMP_DIRS_LIST=$(mktemp make_boot_image_temp_dirs_list.XXX)
65+
:> "${TEMP_DIRS_LIST}"
66+
remove_temp_dirs() {
67+
>&2 echo "Removing temporary directories"
68+
xargs --null rm -rf < "${TEMP_DIRS_LIST}"
69+
rm -f "${TEMP_DIRS_LIST}"
70+
}
71+
trap remove_temp_dirs EXIT
72+
73+
>&2 printf "Creating filesystem hierarchy for deb package: "
74+
DEB_HIER="$(mktemp --directory --tmpdir debhier.XXX)"
75+
printf "%s\0" "${DEB_HIER}" >> "${TEMP_DIRS_LIST}"
76+
>&2 echo "${DEB_HIER}"
77+
78+
>&2 printf "Create rootfs working directory: "
79+
WORK_DIR="$(mktemp --directory --tmpdir boot-image-rootfs.XXX)"
80+
printf "%s\0" "${WORK_DIR}" >> "${TEMP_DIRS_LIST}"
81+
>&2 echo "${WORK_DIR}"
82+
83+
latest_pkg_dir() {
84+
echo /var/cache/rpi-package-download@"$(systemd-escape "${1}")".service/latest
85+
}
86+
87+
>&2 echo "Extracting package contents"
88+
dpkg-deb --raw-extract "$(latest_pkg_dir "$KERNEL_2711")/package.deb" "${WORK_DIR}"
89+
90+
get_dctrl_field() {
91+
grep-dctrl \
92+
--field=Package \
93+
--exact-match "${2}" \
94+
--no-field-names \
95+
--show-field="${3}" \
96+
"${1}"
97+
}
98+
99+
# Determine package version for later reuse
100+
KERNEL_2711_VERSION="$(get_dctrl_field "${WORK_DIR}/DEBIAN/control" "${KERNEL_2711}" Version)"
101+
>&2 echo "Extracted ${KERNEL_2711}, version ${KERNEL_2711_VERSION}"
102+
103+
# rootfs kernel modules
104+
>&2 echo "Copy kernel modules into deb package"
105+
mkdir -p "${DEB_HIER}/lib/modules"
106+
rsync -crt "${WORK_DIR}/lib/modules/"* "${DEB_HIER}/lib/modules"
107+
108+
>&2 printf "Create ramdisk working directory: "
109+
BFS_DIR="$(mktemp --directory --tmpdir boot-image-bootfs.XXX)"
110+
printf "%s\0" "${BFS_DIR}" >> "${TEMP_DIRS_LIST}"
111+
>&2 echo "${BFS_DIR}"
112+
113+
# Kernel Images
114+
>&2 echo "Copy kernel to ramdisk"
115+
cp "${WORK_DIR}/boot/vmlinuz-${LINUX_IMAGE}" "${BFS_DIR}/zImage"
116+
117+
# Overlays
118+
>&2 echo "Copy overlays to ramdisk"
119+
OVERLAY_PATH="${WORK_DIR}/usr/lib/${KERNEL_2711}/overlays"
120+
rsync -crt "${OVERLAY_PATH}"/*.dtb* "${OVERLAY_PATH}/README" "${BFS_DIR}/overlays"
121+
122+
# DTBs
123+
>&2 echo "Copy DTBs to ramdisk"
124+
DTB_PATH="${WORK_DIR}/usr/lib/${KERNEL_2711}/broadcom"
125+
rsync -crt "${DTB_PATH}"/bcm27*.dtb "${BFS_DIR}"
126+
127+
# Insert an initramfs
128+
>&2 echo "Add cryptoot initramfs to ramdisk (with necessary kernel modules)"
129+
INITRAMFS_EXTRACT="$(mktemp --directory --tmpdir initramfs-extract.XXX)"
130+
printf "%s\0" "${INITRAMFS_EXTRACT}" >> "${TEMP_DIRS_LIST}"
131+
zstd -q -d "$(get_cryptroot)" -o "${INITRAMFS_EXTRACT}/initramfs.cpio"
132+
mkdir -p "${INITRAMFS_EXTRACT}/initramfs"
133+
cd "${INITRAMFS_EXTRACT}/initramfs"
134+
RETURN_DIR="${OLDPWD}"
135+
cpio --quiet -id < ../initramfs.cpio > /dev/null
136+
rm ../initramfs.cpio
137+
cd "${WORK_DIR}"
138+
find lib/modules \
139+
\( \
140+
-name 'dm-mod.*' \
141+
-o \
142+
-name 'dm-crypt.*' \
143+
-o \
144+
-name 'af_alg.*' \
145+
-o \
146+
-name 'algif_skcipher.*' \
147+
-o \
148+
-name 'libaes.*' \
149+
-o \
150+
-name 'aes_generic.*' \
151+
-o \
152+
-name 'aes-arm64.*' \
153+
\) \
154+
-exec cp -r --parents "{}" "${INITRAMFS_EXTRACT}/initramfs/usr/" \;
155+
cd -
156+
find . -print0 | cpio --quiet --null -ov --format=newc > ../initramfs.cpio 2> /dev/null
157+
cd "${RETURN_DIR}"
158+
unset RETURN_DIR
159+
zstd -q -6 "${INITRAMFS_EXTRACT}/initramfs.cpio" -o "${BFS_DIR}/rootfs.cpio.zst"
160+
161+
# raspi-firmware
162+
>&2 echo "Downloading raspi-firmware"
163+
download_package raspi-firmware
164+
165+
>&2 printf "Create temp directory to extract firmware: "
166+
FW_EXTRACT_DIR="$(mktemp --directory --tmpdir boot-image-firmware.XXX)"
167+
printf "%s\0" "${FW_EXTRACT_DIR}" >> "${TEMP_DIRS_LIST}"
168+
>&2 echo "${FW_EXTRACT_DIR}"
169+
170+
>&2 echo "Extracting firmware package contents"
171+
dpkg-deb --raw-extract "$(latest_pkg_dir raspi-firmware)/package.deb" "${FW_EXTRACT_DIR}"
172+
173+
>&2 echo "Add firmware to ramdisk"
174+
rsync -v -crt "${FW_EXTRACT_DIR}/usr/lib/raspi-firmware/" "${BFS_DIR}"
175+
176+
# cmdline.txt
177+
>&2 echo "Add cmdline.txt to ramdisk"
178+
cp "$(get_ramdisk_cmdline_file)" "${BFS_DIR}/cmdline.txt"
179+
180+
# Inner config.txt
181+
>&2 echo "Add config.txt to ramdisk"
182+
cp "$(get_internal_config_file)" "${BFS_DIR}/config.txt"
183+
184+
# Invoke make-boot-image
185+
>&2 echo "Finalise ramdisk in deb package (boot.img)"
186+
mkdir -p "${DEB_HIER}/boot/firmware"
187+
make-boot-image \
188+
-b "pi${RPI_DEVICE_FAMILY}" \
189+
-d "${BFS_DIR}" \
190+
-o "${DEB_HIER}/boot/firmware/boot.img" > /dev/null
191+
192+
# Outer config.txt
193+
>&2 echo "Add config.txt to deb package (ensure boot.img is used)"
194+
cp "$(get_fastboot_config_file)" "${DEB_HIER}/boot/firmware/config.txt"
195+
196+
# boot.sig generation
197+
>&2 echo "Signing ramdisk image"
198+
sha256sum "${DEB_HIER}/boot/firmware/boot.img" | awk '{print $1}' > "${DEB_HIER}/boot/firmware/boot.sig"
199+
printf "rsa2048: " >> "${DEB_HIER}/boot/firmware/boot.sig"
200+
${OPENSSL} dgst \
201+
-sign "$(get_signing_directives)" \
202+
-keyform PEM \
203+
-sha256 \
204+
"${DEB_HIER}/boot/firmware/boot.img" \
205+
| xxd -c 4096 -p >> "${DEB_HIER}/boot/firmware/boot.sig"
206+
207+
# Insert control file
208+
mkdir "${DEB_HIER}/DEBIAN"
209+
echo \
210+
"Package: ${PACKAGE_NAME}
211+
Source: linux
212+
Version: ${KERNEL_2711_VERSION}
213+
Architecture: arm64
214+
Maintainer: ${BOOT_IMAGE_MAINTAINER}
215+
Section: kernel
216+
Priority: optional
217+
Homepage: https://github.com/raspberrypi/linux/
218+
Provides: ${KERNEL_2711}
219+
Conflicts: ${KERNEL_2711}
220+
Replaces: ${KERNEL_2711}
221+
Description: Repackaged ${KERNEL_2711} for signed/cryptroot boot" \
222+
> "${DEB_HIER}/DEBIAN/control"
223+
224+
# Create Debian package
225+
dpkg-deb --build "${DEB_HIER}" "${CACHE_DIRECTORY}"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[Unit]
2+
Description=Creates a signed boot image using a Raspberry Pi OS kernel / bootloader
3+
4+
[Service]
5+
Type=oneshot
6+
ExecStart=/usr/local/bin/make-boot-image-from-kernel "%I"
7+
CacheDirectory=%n
8+
9+
[Install]
10+
WantedBy=multi-user.target

nfpm.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ depends:
147147
- libengine-pkcs11-openssl
148148
- libp11-kit-dev
149149
- gnutls-bin
150+
- dpkg
151+
- zstd
150152

151153
# Recommended packages. (overridable)
152154
# This will expand any env var you set in the field, e.g. ${RECOMMENDS_BLA}
@@ -204,6 +206,12 @@ contents:
204206
- src: host-support/fastboot-gadget.img
205207
dst: /var/lib/rpi-sb-provisioner/fastboot-gadget.img
206208

209+
- src: host-support/ramdisk_internal_config.txt
210+
dst: /var/lib/rpi-sb-provisioner/ramdisk_internal_config.txt
211+
212+
- src: host-support/ramdisk_cmdline.txt
213+
dst: /var/lib/rpi-sb-provisioner/ramdisk_cmdline.txt
214+
207215
- src: host-support/make-boot-image
208216
dst: /usr/local/bin/make-boot-image
209217

@@ -228,6 +236,12 @@ contents:
228236
- src: rpi-package-download/rpi-package-download
229237
dst: /usr/local/bin/rpi-package-download
230238

239+
- src: make-boot-image/make-boot-image.service
240+
dst: /usr/local/lib/systemd/system/[email protected]
241+
242+
- src: make-boot-image/make-boot-image-from-kernel
243+
dst: /usr/local/bin/make-boot-image-from-kernel
244+
231245
- src: monitor/monitor.sh
232246
dst: /usr/local/bin/monitor.sh
233247

0 commit comments

Comments
 (0)