Skip to content

Commit

Permalink
Add support for creating a TCG Opal 2 PBA via 'rear mkopalbpa'
Browse files Browse the repository at this point in the history
This version works on systemd-based systems only. For optimum
usability, plymouth boot splash software should be installed on the
original system.
  • Loading branch information
OliverO2 committed Nov 22, 2017
1 parent cd34224 commit a0a3340
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 0 deletions.
@@ -0,0 +1,10 @@
# Exclude everything non-essential

COPY_AS_IS_EXCLUDE+=( /etc/ssl /etc/udev/rules.d/*.rules )
COPY_AS_IS_EXCLUDE+=( /lib/systemd/systemd-cryptsetup /lib/udev/{iphone,ipod}* )
COPY_AS_IS_EXCLUDE+=( /usr/lib/grub /usr/share/grub )
COPY_AS_IS_EXCLUDE+=( "$REAR_DIR_PREFIX" )

Log "Before exclusion: PROGS=(${PROGS[*]})"
PROGS=( $(printf '%s\n' "${PROGS[@]}" | sed -r '/^(btrfs|cryptsetup|dhclient|fsck|grub|mkfs|nslookup|scp|sftp|ssh|strace)/d') )
Log "After exclusion: PROGS=(${PROGS[*]})"
@@ -0,0 +1,5 @@
# Re-include essential files which have been previously excluded

mkdir $v -p "$ROOTFS_DIR/$REAR_DIR_PREFIX/usr/share/rear/lib"
cp $v -r "$REAR_DIR_PREFIX/usr/share/rear/lib/." "$ROOTFS_DIR/$REAR_DIR_PREFIX/usr/share/rear/lib"
StopIfError "Could not re-include essential files"
@@ -0,0 +1,16 @@
# List executables along with the shared libraries they depend on
#
# The resulting list can be used to determine which executables with a large footprint could be stripped from the
# TCG Opal pre-boot authentication (PBA) image

if is_true $KEEP_BUILD_DIR; then
executables=( $(find "$ROOTFS_DIR" -type f -executable -print | sort) )
executable_dependencies_list="$TMP_DIR/executable-dependencies"

for executable in "${executables[@]}"; do
dependents=( $(RequiredSharedOjects "$executable") )
echo "$executable: ${dependents[*]}"
done > "$executable_dependencies_list"

LogPrint "A list of executables with their dependencies has been stored in $executable_dependencies_list"
fi
32 changes: 32 additions & 0 deletions usr/share/rear/build/OPALPBA/Linux-i386/810_deduplicate_files.sh
@@ -0,0 +1,32 @@
# De-duplicates executables to minimize the file system's footprint

has_binary sha256sum || return 0

local deduplication_script="$TMP_DIR/deduplication_script"

# Calculate checksums of executables in the root file system to identify files with identical content.
# Then use hard links to cross-link such files.
find "$ROOTFS_DIR" -type f -executable -exec sha256sum --binary '{}' + | sort |
awk -v path_prefix="$ROOTFS_DIR" '
BEGIN {
path_prefix_length = length(path_prefix);
}
{
hash = $1;
sub(/^[^ ]+ ./, "");
path = $0;
if (hash in executables) {
if (substr(path, 1, path_prefix_length) == path_prefix) {
printf("Log '"'"'De-duplicating \"%s\" -> \"%s\"'"'"'\n", executables[hash], path);
printf("ln --force '"'"'%s'"'"' '"'"'%s'"'"' || Error 'De-duplication error'\n", executables[hash], path);
} else {
printf("LogUserOutput '"'"'Cannot de-duplicate \"%s\" -> \"%s\"'"'"'\n", executables[hash], path);
}
} else {
executables[hash] = path;
}
}
' > "$deduplication_script"

source "$deduplication_script"
21 changes: 21 additions & 0 deletions usr/share/rear/lib/mkopalpba-workflow.sh
@@ -0,0 +1,21 @@
# Workflow for TCG Opal pre-boot authentication (PBA) image creation
#

WORKFLOW_mkopalbpa_DESCRIPTION="create a TCG Opal pre-boot authentication (PBA) image"
WORKFLOWS+=( mkopalbpa )
WORKFLOW_mkopalbpa () {
BACKUP=OPALPBA # Makes ReaR create a minimal PBA system
OUTPUT=RAWDISK # A raw disk image is the only valid output for this workflow

SourceStage "prep"

SourceStage "layout/save"

SourceStage "rescue"

SourceStage "build"

SourceStage "pack"

SourceStage "output"
}
31 changes: 31 additions & 0 deletions usr/share/rear/prep/OPALPBA/Linux-i386/380_configure_workflow.sh
@@ -0,0 +1,31 @@
# Configure the workflow for TCG Opal pre-boot authentication (PBA) image creation

has_binary sedutil-cli || Error "Executable sedutil-cli is missing. Cannot create a TCG Opal PBA without it."

LogPrint "Re-configuring Relax-and-Recover to create a TCG Opal pre-boot authentication (PBA) image"

# Configure kernel
KERNEL_CMDLINE+=" quiet splash systemd.volatile=yes systemd.unit=opalpba.target"

# Enable debugging in PBA on request
is_true "$OPALPBA_DEBUG" && KERNEL_CMDLINE+=" opal_debug"

# Strip kernel files to a reasonable minimum
FIRMWARE_FILES=( 'no' )
MODULES=( 'loaded_modules' )
EXCLUDE_MODULES+=( $(lsmod | tail -n +2 | cut -d ' ' -f 1 | while read m; do modprobe -R $m; done | grep '^nvidia' ) )

# Include plymouth boot animation if available
PROGS+=( plymouth plymouthd clear )
COPY_AS_IS+=( /usr/lib/x86_64-linux-gnu/plymouth /usr/share/plymouth /etc/alternatives )

# Redirect output
[[ -n "$OPALPBA_URL" ]] || Error "The OPALPBA_URL configuration variable must be set."
OUTPUT_URL="$OPALPBA_URL"

# Configure raw disk output
RAWDISK_GRUB_BOOT_MENUENTRY_TITLE="TCG Opal pre-boot authentication"
RAWDISK_PARTITION_NAME="TCG Opal PBA"
RAWDISK_BOOT_FS_NAME="OPAL PBA"
RAWDISK_SYSLINUX_START_INFORMATION="Starting TCG Opal pre-boot authentication..."
RAWDISK_IMAGE_NAME="TCG-Opal-PBA-$HOSTNAME"
132 changes: 132 additions & 0 deletions usr/share/rear/skel/default/etc/scripts/unlock-opal-disks
@@ -0,0 +1,132 @@
#!/bin/bash
#
# Unlock TCG Opal-compliant disks and reboot to continue booting the 'real' operating system
#
# This script executes the final stage of a TCG Opal pre-boot authentication (PBA) boot.
# It is expected that this script executes on a volatile system running entirely on RAM file systems.
# To avoid delays, this script will perform a hard reset or power-off instead of a regular
# system shutdown.

kernel_cmdline="$(cat /proc/cmdline)"

function opal_debug() {
# returns 0 if Opal debug mode is requested
[[ " $kernel_cmdline " == *" opal_debug "* ]]
}

function be_quiet() {
# returns 0 if quiet boot is requested
[[ " $kernel_cmdline " == *" quiet "* ]]
}

function use_plymouth() {
# returns 0 if plymouth is to be used
type -p plymouth &>/dev/null && plymouth --ping
}

function quit_plymouth() {
# quits plymouth if in use
use_plymouth && plymouth quit
}

function ask_for_password() {
# asks for a password with prompt $1, setting the variable $password
if ! password="$(use_plymouth && plymouth ask-for-password --prompt="$1")"; then
echo ""
read -s -p "$1: " password
echo ""
fi
}

function display_message() {
# displays the message $1
(use_plymouth && plymouth display-message --text="$1") || echo -e "\n$1"
}

function instant_reboot() {
quit_plymouth
# Force immediate hardware reboot via Magic SysRq key
echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger
# Fallback if the previous method did not work
sleep 1
reboot --force
}

function instant_poweroff() {
quit_plymouth
# Force immediate hardware poweroff via Magic SysRq key
echo 1 > /proc/sys/kernel/sysrq
echo o > /proc/sysrq-trigger
# Fallback if the previous method did not work
sleep 1
poweroff --force
}


# Minimal system setup
# TODO: split system setup scripts into PBA and rescue categories to protect against script renaming
for system_setup_script in 00-functions.sh 10-console-setup.sh 40-start-udev-or-load-modules.sh; do
source "/etc/scripts/system-setup.d/$system_setup_script"
done


# Find TCG Opal 2-compliant disks
opal_disks=( $(sedutil-cli --scan | awk '$1 ~ /\/dev\// && $2 ~ /2/ { print $1; }') )
opal_disk_count=${#opal_disks[@]}
if [[ $opal_disk_count -eq 0 ]]; then
if opal_debug; then
display_message "Could not detect TCG Opal-compliant disks. Entering shell..."
sleep 3
quit_plymouth
bash --login
else
display_message "Could not detect TCG Opal-compliant disks. Powering off..."
sleep 3
instant_poweroff
fi
fi

# Query TCG Opal-compliant disks to determine the maximum number of authentication attempts
max_authentications=1
for disk in "${opal_disks[@]}"; do
disk_max_authentications="$(sedutil-cli --query "$disk" | sed -r -e '/MaxAuthentications/ { s/.*MaxAuthentications *= *([0-9]+).*/\1/; p }' -e 'd')"
if [[ "$disk_max_authentications" -gt 0 ]] && [[ "$disk_max_authentications" -lt "$max_authentications" ]]; then
# Limit authentication attempts to the lowest number supported by any disk
max_authentications="$disk_max_authentications"
fi
done

# Ask for a password, unlock TCG Opal-compliant disks, reboot if successful
attempt=0
while [[ "$attempt" -lt "$max_authentications" ]]; do
attempt=$((attempt + 1))

ask_for_password "Enter password to unlock disks"

unlocking_successful="no"
for disk in "${opal_disks[@]}"; do
if sedutil-cli --setLockingRange 0 RW "$password" "$disk" >/dev/null 2>&1; then
unlocking_successful=yes
sedutil-cli --setMBRDone on "$password" "$disk" >/dev/null 2>&1
fi
done

if [[ "$unlocking_successful" == "yes" ]]; then
display_message "Unlocking successful, rebooting..."
sleep 1
instant_reboot
elif [[ $opal_disk_count -eq 0 ]]; then
display_message "No disks to unlock, rebooting..."
sleep 1
instant_reboot
else
display_message "Could not unlock any disk."
fi
done

# If unsuccessful, power off.
# This is required as TCG Opal-compliant disks will refuse further authentication attempts before being reset.
display_message "Powering off after $attempt unsuccessful attempts..."
sleep 3
instant_poweroff
11 changes: 11 additions & 0 deletions usr/share/rear/skel/default/usr/lib/systemd/system/opalpba.target
@@ -0,0 +1,11 @@
# This file is part of systemd.
#
# See systemd.special(7) for details

[Unit]
Description=TCG Opal pre-boot authentication (PBA)
Requires=sysinit-opalpba.service
AllowIsolate=yes

[Install]
Alias=opalpba.target
@@ -0,0 +1,16 @@
[Unit]
Description=Show Plymouth Boot Screen
DefaultDependencies=no
Before=systemd-udev-trigger.service systemd-udevd.service
ConditionKernelCommandLine=!plymouth.enable=0
ConditionKernelCommandLine=!nosplash
ConditionKernelCommandLine=splash
ConditionFileIsExecutable=/sbin/plymouthd
ConditionFileIsExecutable=/bin/plymouth

[Service]
ExecStart=/sbin/plymouthd --mode=boot --pid-file=/run/plymouth/pid --attach-to-session
ExecStartPost=-/bin/plymouth show-splash
Type=forking
KillMode=none
SendSIGKILL=no
@@ -0,0 +1,10 @@
[Unit]
Description=TCG Opal pre-boot authentication (PBA) service
Requires=systemd-udev-trigger.service systemd-udevd.service rear-boot-helper.service
Wants=plymouth-start.service
After=systemd-udev-trigger.service systemd-udevd.service plymouth-start.service rear-boot-helper.service

[Service]
Type=oneshot
ExecStart=/etc/scripts/unlock-opal-disks
StandardInput=tty

0 comments on commit a0a3340

Please sign in to comment.