mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
ebc: Add ibm-sel-ebc dracut module
Add 95ibm-sel-ebc dracut module for secure boot-time customization of SEL guests. Introduce the IBM SEL EBC dracut module (95ibm-sel-ebc) that enables Early Boot Customization for SEL guests during the initramfs phase. The module implements a critical security architecture to prevent injection attacks: all EBC resources (.asr and .pol files) are copied from /boot/sics (which resides in the qcow2 image on the host filesystem) to /run/ibm-sel-ebc (a tmpfs/RAM-backed directory). Since guest RAM is protected by the Ultravisor, this prevents malicious hosts from modifying EBC resources during boot. Systemd units and their purposes: - ibm-sel-ebc.target: Groups all EBC-related units - boot.mount: Mounts /dev/disk/by-label/boot to /boot - ibm-sel-ebc-ensure-sics.service: Fallback to create /boot/sics/ if boot partition mount fails (supports Kata VM scenarios) - ibm-sel-ebc-pvebc.service: Main unit that copies EBC resources to RAM, invokes pvebc tool to verify integrity and add ASRs to UV, retrieves LUKS passphrase from UV secret store - ibm-sel-ebc-override-crypttab.service: Replaces /etc/crypttab with prepared IBM SEL EBC crypttab, reloads systemd daemon, starts cryptsetup service - ibm-sel-ebc-paes-enforce.service: Verifies root filesystem uses PAES encryption to prevent root filesystem substitution attacks All units write logs to /boot/sics/log for debugging, accessible even if root filesystem fails to mount. Units are triggered by rd.ibm-sel-ebc kernel parameter and only execute in initramfs (ConditionPathExists=/etc/initrd-release). Assisted-by: IBM Bob:1.0.1 Reviewed-by: Holger Dengler <dengler@linux.ibm.com> Signed-off-by: Finn Callies <fcallies@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
c04a0919f6
commit
3aa5c38714
@@ -10,6 +10,8 @@ CARGO_TARGETS :=
|
||||
PV_TARGETS :=
|
||||
CARGO_TEST_TARGETS :=
|
||||
|
||||
SEL_EBC_MODDIR := 95sel-ebc
|
||||
|
||||
ifneq (${HAVE_CARGO},0)
|
||||
CARGO_TARGETS := pvebc
|
||||
|
||||
@@ -29,6 +31,7 @@ ifneq (${HAVE_LIBCURL},0)
|
||||
|
||||
ifeq ($(HOST_ARCH),s390x)
|
||||
PV_TARGETS += pvapconfig pvinfo
|
||||
INSTALL_TARGETS += install-ebc-dracut-module
|
||||
else
|
||||
BUILD_TARGETS += skip-pvapconfig skip-pvinfo
|
||||
endif #HOSTARCH
|
||||
@@ -104,6 +107,23 @@ endif # CARGO
|
||||
|
||||
rust-test: $(CARGO_TEST_TARGETS)
|
||||
|
||||
install-ebc-dracut-module:
|
||||
ifneq ($(HAVE_DRACUT),0)
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/
|
||||
$(INSTALL) -m 755 -d $(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
|
||||
$(INSTALL) -m 755 pvebc/$(SEL_EBC_MODDIR)/module-setup.sh \
|
||||
pvebc/$(SEL_EBC_MODDIR)/override-crypttab.sh \
|
||||
pvebc/$(SEL_EBC_MODDIR)/pvebc-wrapper.sh \
|
||||
$(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
|
||||
$(INSTALL) -m 644 pvebc/$(SEL_EBC_MODDIR)/boot.mount \
|
||||
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-override-crypttab.service \
|
||||
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-paes-enforce.service \
|
||||
pvebc/$(SEL_EBC_MODDIR)/sel-ebc-pvebc.service \
|
||||
pvebc/$(SEL_EBC_MODDIR)/sel-ebc.crypttab \
|
||||
pvebc/$(SEL_EBC_MODDIR)/sel-ebc.target \
|
||||
$(DESTDIR)$(DRACUTMODDIR)/$(SEL_EBC_MODDIR)
|
||||
endif
|
||||
|
||||
install-rust-tools: $(BUILD_TARGETS)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||
$(foreach target,$(CARGO_TARGETS),\
|
||||
|
||||
28
rust/pvebc/95sel-ebc/boot.mount
Normal file
28
rust/pvebc/95sel-ebc/boot.mount
Normal file
@@ -0,0 +1,28 @@
|
||||
[Unit]
|
||||
Description=Mount /boot early in initramfs
|
||||
|
||||
# Initramfs requirement
|
||||
DefaultDependencies=no
|
||||
# Make absolutely sure this only runs in initramfs (and not post-pivot if the
|
||||
# unit ever appears there)
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionKernelCommandLine=root
|
||||
|
||||
# we use /dev/disk/by-label because it identifies the boot partition system
|
||||
# independently IF set up correctly
|
||||
Requires=dev-disk-by\x2dlabel-boot.device
|
||||
|
||||
# Ordering dependencies
|
||||
After=dev-disk-by\x2dlabel-boot.device
|
||||
Before=sel-ebc-pvebc.service
|
||||
|
||||
[Mount]
|
||||
# system independent identification of boot partition requires that the label
|
||||
# boot is set for the boot partition
|
||||
What=/dev/disk/by-label/boot
|
||||
Where=/boot
|
||||
Type=auto
|
||||
Options=defaults
|
||||
|
||||
[Install]
|
||||
WantedBy=sel-ebc-pvebc.service
|
||||
76
rust/pvebc/95sel-ebc/module-setup.sh
Normal file
76
rust/pvebc/95sel-ebc/module-setup.sh
Normal file
@@ -0,0 +1,76 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright IBM Corp.
|
||||
|
||||
|
||||
# Called by dracut
|
||||
check() {
|
||||
# always include
|
||||
return 0
|
||||
}
|
||||
|
||||
# Called by dracut
|
||||
depends() {
|
||||
# We need systemd in the initramfs
|
||||
echo systemd
|
||||
echo systemd-udevd
|
||||
echo crypt
|
||||
echo dm
|
||||
return 0
|
||||
}
|
||||
|
||||
# Called by dracut
|
||||
installkernel() {
|
||||
# kernel modules needed for opening an encrypted rfs
|
||||
instmods -c uvdevice
|
||||
instmods -c paes_s390
|
||||
instmods -c pkey_uv
|
||||
instmods -c pkey_pckmo
|
||||
instmods -c pkey
|
||||
}
|
||||
|
||||
# Called by dracut
|
||||
install() {
|
||||
# shellcheck disable=SC2154
|
||||
# moddir, systemdsystemunitdir, and initdir are provided by dracut
|
||||
# Copy the units into the initramfs' systemd unit dir
|
||||
inst_simple "$moddir/sel-ebc.target" \
|
||||
"$systemdsystemunitdir/sel-ebc.target"
|
||||
inst_simple "$moddir/sel-ebc-pvebc.service" \
|
||||
"$systemdsystemunitdir/sel-ebc-pvebc.service"
|
||||
inst_simple "$moddir/sel-ebc-paes-enforce.service" \
|
||||
"$systemdsystemunitdir/sel-ebc-paes-enforce.service"
|
||||
inst_simple "$moddir/sel-ebc-override-crypttab.service" \
|
||||
"$systemdsystemunitdir/sel-ebc-override-crypttab.service"
|
||||
inst_simple "$moddir/boot.mount" \
|
||||
"$systemdsystemunitdir/boot.mount"
|
||||
|
||||
# already exisitng unit we depend on for kernel modules
|
||||
inst_simple /usr/lib/systemd/system/systemd-modules-load.service \
|
||||
"$systemdsystemunitdir/systemd-modules-load.service"
|
||||
|
||||
# wrapper for sel-ebc.service
|
||||
inst_simple "$moddir/pvebc-wrapper.sh" \
|
||||
"/etc/sel-ebc/pvebc-wrapper.sh"
|
||||
|
||||
# override crypttab
|
||||
inst_simple "$moddir/override-crypttab.sh" \
|
||||
"/etc/sel-ebc/override-crypttab.sh"
|
||||
|
||||
# copy main application
|
||||
inst_binary "/usr/bin/pvebc"
|
||||
inst_binary "/usr/bin/pvsecret"
|
||||
|
||||
inst_simple "$moddir/sel-ebc.crypttab" "/etc/sel-ebc/crypttab"
|
||||
|
||||
# Create the enablement symlinks in the image using host systemctl:
|
||||
# shellcheck disable=SC2154
|
||||
inst_dir "$initdir/etc/systemd/system"
|
||||
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc.target
|
||||
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-pvebc.service
|
||||
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-override-crypttab.service
|
||||
systemctl --root "$initdir" --no-reload --quiet enable sel-ebc-paes-enforce.service
|
||||
systemctl --root "$initdir" --no-reload --quiet enable systemd-modules-load.service
|
||||
systemctl --root "$initdir" --no-reload --quiet enable boot.mount
|
||||
}
|
||||
20
rust/pvebc/95sel-ebc/override-crypttab.sh
Normal file
20
rust/pvebc/95sel-ebc/override-crypttab.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright IBM Corp.
|
||||
|
||||
IBM_RSRC_DIR="/etc/sel-ebc"
|
||||
|
||||
if [[ ! -f "${IBM_RSRC_DIR}/crypttab" ]]; then
|
||||
echo "Error: source file $IBM_RSRC_DIR/crypttab does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Unconditionally override /etc/crypttab to ensure correct EBC configuration
|
||||
cp "${IBM_RSRC_DIR}/crypttab" "/etc/crypttab"
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
systemctl restart systemd-cryptsetup@cryptroot_mapper.service
|
||||
|
||||
exit 0
|
||||
63
rust/pvebc/95sel-ebc/pvebc-wrapper.sh
Normal file
63
rust/pvebc/95sel-ebc/pvebc-wrapper.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# Copyright IBM Corp.
|
||||
|
||||
SYSFS=/sys/firmware/uv/prot_virt_guest
|
||||
SICS=/boot/sics
|
||||
EBC_TMPFS=/run/sel-ebc
|
||||
TOC=toc.asr
|
||||
ASR_NAME=luks-rfs-passphrase
|
||||
|
||||
# Early exit for non SEL guests
|
||||
if [[ ! -e $SYSFS ]]; then
|
||||
echo "Not running in a SEL guest."
|
||||
exit 1
|
||||
fi
|
||||
if [[ $(cat $SYSFS) -ne 1 ]]; then
|
||||
echo "Not running in a SEL guest."
|
||||
exit 1
|
||||
fi
|
||||
echo "Running in SEL guest."
|
||||
|
||||
# Copy EBC resources from /boot/sics to tmpfs for security
|
||||
# This protects against host injection attacks by moving resources to UV-protected RAM
|
||||
echo "Copying EBC resources from $SICS to $EBC_TMPFS"
|
||||
if ! mkdir -p "$EBC_TMPFS"; then
|
||||
echo "Failed to create $EBC_TMPFS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Copy only .asr and .pol files
|
||||
for file in "$SICS"/*.asr "$SICS"/*.pol; do
|
||||
if [[ -f "$file" && ! -L "$file" ]]; then
|
||||
cp "$file" "$EBC_TMPFS/" || {
|
||||
echo "Failed to copy $file to $EBC_TMPFS"
|
||||
exit 1
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify toc.asr was copied
|
||||
if [[ ! -f "$EBC_TMPFS/$TOC" ]]; then
|
||||
echo "Error: $EBC_TMPFS/$TOC does not exist after copy"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# execute the actual tool with the copied toc.asr
|
||||
pvebc --toc "$EBC_TMPFS/$TOC"
|
||||
rc=$?
|
||||
if [[ $rc -ne 0 ]]; then
|
||||
exit $rc
|
||||
fi
|
||||
|
||||
# Retrieve and check for dummy LUKS passphrase
|
||||
pvsecret retrieve --inform name -o "$EBC_TMPFS/$ASR_NAME" --outform bin "$ASR_NAME"
|
||||
|
||||
if [[ ! -f "$EBC_TMPFS/$ASR_NAME" ]]; then
|
||||
echo "$EBC_TMPFS/$ASR_NAME does not exist"
|
||||
fi
|
||||
|
||||
chmod 400 "$EBC_TMPFS/$ASR_NAME"
|
||||
|
||||
exit 0
|
||||
37
rust/pvebc/95sel-ebc/sel-ebc-override-crypttab.service
Normal file
37
rust/pvebc/95sel-ebc/sel-ebc-override-crypttab.service
Normal file
@@ -0,0 +1,37 @@
|
||||
[Unit]
|
||||
Description=Override crypttab
|
||||
|
||||
# boot partition contains SICS
|
||||
# Loading of kernel modules is required which are needed for protected keys
|
||||
Requires=systemd-modules-load.service
|
||||
Requires=boot.mount
|
||||
|
||||
# Ensure this runs before the handoff to the real root, if that's required:
|
||||
After=boot.mount
|
||||
After=systemd-modules-load.service
|
||||
Before=cryptsetup-pre.target
|
||||
Before=cryptsetup.target
|
||||
Before=systemd-cryptsetup@.service
|
||||
Before=initrd-root-device.target
|
||||
After=sel-ebc-pvebc.service
|
||||
|
||||
# Initramfs requirement
|
||||
DefaultDependencies=no
|
||||
# Make absolutely sure this only runs in initramfs
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionKernelCommandLine=rd.sel-ebc
|
||||
ConditionKernelCommandLine=root
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash /etc/sel-ebc/override-crypttab.sh
|
||||
RemainAfterExit=yes
|
||||
# If pvebc fails immediately abort boot
|
||||
FailureAction=poweroff-immediate
|
||||
# boot partition is unencrypted and contains SICS so we can get logs out this way
|
||||
# logs do not leek any sensitive information
|
||||
StandardOutput=file:/boot/sics/log
|
||||
StandardError=file:/boot/sics/log
|
||||
|
||||
[Install]
|
||||
RequiredBy=sel-ebc.target
|
||||
27
rust/pvebc/95sel-ebc/sel-ebc-paes-enforce.service
Normal file
27
rust/pvebc/95sel-ebc/sel-ebc-paes-enforce.service
Normal file
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=Enforce PAES encrypted root fs for SEL guests
|
||||
|
||||
# Ensure this runs before the handoff to the real root, if that's required:
|
||||
After=cryptsetup.target
|
||||
After=initrd-root-device.target
|
||||
Before=sysroot.mount
|
||||
|
||||
# Initramfs requirement
|
||||
DefaultDependencies=no
|
||||
# Make absolutely sure this only runs in initramfs
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionKernelCommandLine=rd.sel-ebc
|
||||
ConditionKernelCommandLine=root
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=bash -c 'dmsetup table /dev/disk/by-label/root | grep "paes-xts-plain64"'
|
||||
FailureAction=poweroff-immediate
|
||||
RemainAfterExit=yes
|
||||
|
||||
# logs do not leek any sensitive information
|
||||
StandardOutput=file:/boot/sics/log
|
||||
StandardError=file:/boot/sics/log
|
||||
|
||||
[Install]
|
||||
RequiredBy=sel-ebc.target
|
||||
36
rust/pvebc/95sel-ebc/sel-ebc-pvebc.service
Normal file
36
rust/pvebc/95sel-ebc/sel-ebc-pvebc.service
Normal file
@@ -0,0 +1,36 @@
|
||||
[Unit]
|
||||
Description=Run pvebc during early boot to process SICS
|
||||
|
||||
# boot partition contains SICS
|
||||
# Loading of kernel modules is required which are needed for protected keys
|
||||
Requires=systemd-modules-load.service
|
||||
Wants=boot.mount
|
||||
|
||||
# Ensure this runs before the handoff to the real root, if that's required:
|
||||
Before=initrd-root-device.target
|
||||
Before=cryptsetup-pre.target
|
||||
Before=cryptsetup.target
|
||||
After=boot.mount
|
||||
After=systemd-modules-load.service
|
||||
|
||||
# Initramfs requirement
|
||||
DefaultDependencies=no
|
||||
# Make absolutely sure this only runs in initramfs
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
AssertPathIsDirectory=/boot/sics
|
||||
ConditionKernelCommandLine=rd.sel-ebc
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# execute pvebc
|
||||
ExecStart=/bin/bash /etc/sel-ebc/pvebc-wrapper.sh
|
||||
RemainAfterExit=yes
|
||||
# If pvebc fails immediately abort boot
|
||||
FailureAction=poweroff-immediate
|
||||
# boot partition is unencrypted and contains SICS so we can get logs out this way
|
||||
# logs do not leek any sensitive information
|
||||
StandardOutput=file:/boot/sics/log
|
||||
StandardError=file:/boot/sics/log
|
||||
|
||||
[Install]
|
||||
RequiredBy=sel-ebc.target
|
||||
1
rust/pvebc/95sel-ebc/sel-ebc.crypttab
Normal file
1
rust/pvebc/95sel-ebc/sel-ebc.crypttab
Normal file
@@ -0,0 +1 @@
|
||||
cryptroot_mapper /dev/disk/by-label/cryptroot /run/sel-ebc/luks-rfs-passphrase
|
||||
27
rust/pvebc/95sel-ebc/sel-ebc.target
Normal file
27
rust/pvebc/95sel-ebc/sel-ebc.target
Normal file
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=Target unit for IBM Secure Execution for Linux early boot customization
|
||||
|
||||
# enable for use in initramfs
|
||||
DefaultDependencies=no
|
||||
|
||||
# if not met start the target without starting its dependencies
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionKernelCommandLine=rd.sel-ebc
|
||||
|
||||
# if not met the target is considered failed
|
||||
# AssertVirtualization=kvm
|
||||
|
||||
# if target fails abort immediately
|
||||
FailureAction=poweroff-immediate
|
||||
|
||||
Requires=sel-ebc-pvebc.service
|
||||
Requires=sel-ebc-override-crypttab.service
|
||||
Requires=sel-ebc-paes-enforce.service
|
||||
|
||||
# ordering dependencies
|
||||
After=systemd-modules-load.service
|
||||
Before=initrd-root-device.target
|
||||
|
||||
[Install]
|
||||
# most basic hook to start target by default
|
||||
WantedBy=initrd.target
|
||||
Reference in New Issue
Block a user