Files
CISS.debian.live.builder/config/includes.chroot/usr/lib/live/boot/0024-ciss-crypt-squash
Marc S. Weidner 5362412a9a
All checks were successful
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m28s
V8.13.440.2025.11.19
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
2025-11-22 14:48:56 +00:00

349 lines
9.7 KiB
Bash

#!/bin/sh
# bashsupport disable=BP5007
# shellcheck disable=SC2249
# shellcheck shell=sh
# SPDX-Version: 3.0
# SPDX-CreationInfo: 2025-11-12; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git
# SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency
# SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; <msw@coresecret.dev>
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: EUPL-1.2 OR LicenseRef-CCLA-1.0
# SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework.
# SPDX-PackageName: CISS.debian.live.builder
# SPDX-Security-Contact: security@coresecret.eu
# Purpose: Open /live/ciss_rootfs.crypt (LUKS) for final processing in '9990-overlay.sh'
# Phase : premount (executed by live-boot inside the initramfs)
set -eu
printf "\e[95m[INFO] Starting: [/usr/lib/live/boot/0024-ciss-crypt-squash] ... \n\e[0m"
#######################################
# Ask for a passphrase on /dev/console, mask input with '*'.
# Globals:
# None
# Arguments:
# None
# Returns:
# 0: on success
# 1: on failure / empty
#######################################
ask_pass_console() {
PASSPHRASE=""
SAVED_STTY=""
if command -v stty >/dev/null 2>&1; then
SAVED_STTY="$(stty -g </dev/console 2>/dev/null || printf '')"
stty -echo </dev/console >/dev/console 2>/dev/null || SAVED_STTY=""
fi
printf "\e[93m[INFO] Enter LUKS passphrase: \n\e[0m" >/dev/console 2>/dev/null || return 1
while :; do
C="$(dd if=/dev/console bs=1 count=1 2>/dev/null | tr -d '\r\n')"
[ -z "${C}" ] && break
PASSPHRASE="${PASSPHRASE}${C}"
printf "*" >/dev/console 2>/dev/null || :
done
if [ -n "${SAVED_STTY}" ]; then
stty "${SAVED_STTY}" </dev/console >/dev/console 2>/dev/null || :
else
stty echo </dev/console >/dev/console 2>/dev/null || :
fi
printf "\n" >/dev/console 2>/dev/null || :
[ -n "${PASSPHRASE}" ] || return 1
printf '%s\n' "${PASSPHRASE}"
return 0
}
#######################################
# Premount logging helper.
# Globals:
# None
# Arguments:
# *: String to log.
#######################################
log() {
msg="$*"
if [ -w /dev/kmsg ]; then
printf '<6>%s: %s\n' '0024-ciss-crypt-squash' "${msg}" > /dev/kmsg
else
printf '%s: %s\n' '0024-ciss-crypt-squash' "${msg}"
fi
}
### Declare variables. ---------------------------------------------------------------------------------------------------------
export CDLB_ISO_LABEL="CISS.debian.live"
export CDLB_LUKS_FS="/live/ciss_rootfs.crypt"
export CDLB_MAPPER_NAME="crypt_liveiso"
export CDLB_MAPPER_DEV="/dev/mapper/${CDLB_MAPPER_NAME}"
CDLB_REMOTE_WAIT_SECS="${CDLB_REMOTE_WAIT_SECS:-3600}"
MNT_MEDIUM="/run/live/medium"
MNT_ROOTFS="/run/live/rootfs"
_PARAMETER=""
_dev=""
### Read the kernel cmdline once. ----------------------------------------------------------------------------------------------
CMDLINE="$(cat /proc/cmdline 2>/dev/null || printf '')"
for _PARAMETER in ${CMDLINE}; do
case "${_PARAMETER}" in
ciss_crypt_path=*) export CDLB_LUKS_FS="${_PARAMETER#ciss_crypt_path=}";;
ciss_iso_label=* ) export CDLB_ISO_LABEL="${_PARAMETER#ciss_iso_label=}";;
esac
done
printf "\e[92m[INFO] CDLB_LUKS_FS : [%s] \n\e[0m" "${CDLB_LUKS_FS}"
printf "\e[92m[INFO] CDLB_ISO_LABEL : [%s] \n\e[0m" "${CDLB_ISO_LABEL}"
mkdir -p "${MNT_MEDIUM}" "${MNT_ROOTFS}"
### Mount the live medium (ISO) read-only, unless already mounted. -------------------------------------------------------------
if ! mountpoint -q "${MNT_MEDIUM}"; then
if [ -n "${CDLB_ISO_LABEL}" ] && [ -e "/dev/disk/by-label/${CDLB_ISO_LABEL}" ]; then
mount -r -t iso9660 "/dev/disk/by-label/${CDLB_ISO_LABEL}" "${MNT_MEDIUM}" 2>/dev/null \
|| mount -r -t udf "/dev/disk/by-label/${CDLB_ISO_LABEL}" "${MNT_MEDIUM}" 2>/dev/null \
|| log "could not mount label=${CDLB_ISO_LABEL} (iso9660/udf)"
fi
fi
if ! mountpoint -q "${MNT_MEDIUM}"; then
### Fallback scan (covers SR drives and loop-mounted ISOs that udev exposed).
for _dev in /dev/sr* /dev/cdrom /dev/disk/by-label/*; do
### Skip non-block entries early.
[ -b "${_dev}" ] || continue
### Try ISO9660 first, then UDF; only unmount on failure.
if mount -r -t iso9660 "${_dev}" "${MNT_MEDIUM}" 2>/dev/null || mount -r -t udf "${_dev}" "${MNT_MEDIUM}" 2>/dev/null; then
mountpoint -q "${MNT_MEDIUM}" 2>/dev/null && break
else
umount "${MNT_MEDIUM}" 2>/dev/null || true
fi
done
fi
if ! mountpoint -q "${MNT_MEDIUM}"; then
log "No live medium mounted, defer to default live-boot path."
printf "\e[91m[FATAL] No live medium mounted, defer to default live-boot path. \n\e[0m"
exit 0
fi
printf "\e[92m[INFO] MNT_MEDIUM : [%s] \n\e[0m" "${MNT_MEDIUM}"
### Locate the encrypted root container on the medium. -------------------------------------------------------------------------
if [ ! -f "${MNT_MEDIUM}${CDLB_LUKS_FS}" ]; then
log "Encrypted root not found at: [${MNT_MEDIUM}${CDLB_LUKS_FS}]"
printf "\e[91m[FATAL] Encrypted root not found at: [%s%s] \n\e[0m" "${MNT_MEDIUM}" "${CDLB_LUKS_FS}"
exit 0
fi
printf "\e[92m[INFO] CISS LUKS FS : [%s%s] \n\e[0m" "${MNT_MEDIUM}" "${CDLB_LUKS_FS}"
### Attach a loop device read-only to the encrypted file. ----------------------------------------------------------------------
LOOP="$(losetup -f --show -r "${MNT_MEDIUM}${CDLB_LUKS_FS}")" || { log "losetup failed"; exit 42; }
printf "\e[92m[INFO] Loop device : [%s] \n\e[0m" "${LOOP}"
### Expose the loop device for unlock-wrapper.sh, dropbear forced-command. -----------------------------------------------------
mkdir -p /run 2>/dev/null || true
echo "${LOOP}" > /run/ciss-loopdev 2>/dev/null || true
chmod 0600 /run/ciss-loopdev 2>/dev/null || true
printf "\e[92m[INFO] Exposed LOOP : [/run/ciss-loopdev] -> [%s]\n\e[0m" "${LOOP}"
### Prepare fifo for passphrase. -----------------------------------------------------------------------------------------------
mkdir -p /lib/cryptsetup 2>/dev/null || true
if [ -p /lib/cryptsetup/passfifo ]; then
rm -f /lib/cryptsetup/passfifo 2>/dev/null || true
fi
if ! mkfifo /lib/cryptsetup/passfifo 2>/dev/null; then
printf "\e[92m[WARN] Failed to create /lib/cryptsetup/passfifo \n\e[0m"
exit 42
fi
chmod 0600 /lib/cryptsetup/passfifo 2>/dev/null || true
### Background broker: read FIFO, try cryptsetup per line. ---------------------------------------------------------------------
(
set +e
PASS=""
while :; do
if [ -b "${CDLB_MAPPER_DEV}" ]; then
break
fi
if ! IFS= read -r PASS < /lib/cryptsetup/passfifo; then
sleep 1
continue
fi
[ -n "${PASS}" ] || continue
printf "\e[93m[INFO] Trying to unlock via cryptsetup ...\n\e[0m" >/dev/console 2>/dev/null || true
KEYLEN=${#PASS}
printf '%s' "${PASS}" | cryptsetup open --tries 1 \
--type luks \
--keyfile-size="${KEYLEN}" \
--readonly "${LOOP}" "${CDLB_MAPPER_NAME}" --key-file - 2>/dev/console
if [ -b "${CDLB_MAPPER_DEV}" ]; then
printf "\e[92m[INFO] LUKS mapper [%s] successfully opened.\n\e[0m" "${CDLB_MAPPER_DEV}" >/dev/console 2>/dev/null || true
break
fi
done
) &
PID_BROKER="$!"
### Background process console-prompt feed passphrases into FIFO. --------------------------------------------------------------
(
set +e
PASS=""
while :; do
if [ -b "${CDLB_MAPPER_DEV}" ]; then
break
fi
#printf "\e[93m[INFO] Enter LUKS passphrase on console: \n\e[0m" >/dev/console 2>/dev/null || break
#if ! IFS= read -r PASS </dev/console 2>/dev/null; then
# break
#fi
[ -n "${PASS}" ] || continue
# shellcheck disable=SC2310
PASS="$(ask_pass_console)" || continue
printf '%s\n' "${PASS}" >| /lib/cryptsetup/passfifo 2>/dev/null || :
done
) &
PID_PROMPT="$!"
### Main process: wait bounded time for the mapper to appear. ------------------------------------------------------------------
REMAINING="${CDLB_REMOTE_WAIT_SECS}"
if [ ! -b "${CDLB_MAPPER_DEV}" ]; then
printf "\e[93m[INFO] Waiting up to %s seconds for [%s] to be unlocked ...\n\e[0m" "${REMAINING}" "${CDLB_MAPPER_DEV}"
fi
while [ "${REMAINING}" -gt 0 ]; do
if [ -b "${CDLB_MAPPER_DEV}" ]; then
break
fi
sleep 1
REMAINING=$((REMAINING - 1))
done
if [ ! -b "${CDLB_MAPPER_DEV}" ]; then
printf "\e[91m[WARN] Timeout: mapper [%s] not present after %s seconds. \n\e[0m" "${CDLB_MAPPER_DEV}" "${CDLB_REMOTE_WAIT_SECS}"
kill "${PID_PROMPT}" 2>/dev/null || true
kill "${PID_BROKER}" 2>/dev/null || true
rm -f /lib/cryptsetup/passfifo 2>/dev/null || true
exit 42
fi
kill "${PID_PROMPT}" 2>/dev/null || true
wait "${PID_BROKER}" 2>/dev/null || true
rm -f /lib/cryptsetup/passfifo 2>/dev/null || true
printf "\e[92m[INFO] LUKS mapper : [%s] is now present.\n\e[0m" "${CDLB_MAPPER_DEV}"
### Expose the decrypted root device for live-boot overlay. The live-boot components will pick this up in '9990-overlay.sh'. ---
echo "${CDLB_MAPPER_DEV}" >| /run/ciss-rootdev
chmod 0644 /run/ciss-rootdev 2>/dev/null || true
export CISS_ROOT_DEV="${CDLB_MAPPER_DEV}"
export CISS_ROOT_DIR=""
log "Decrypted root device exposed at [/run/ciss-rootdev] -> [${CDLB_MAPPER_DEV}]"
printf "\e[92m[INFO] Decrypted root device exposed at: [/run/ciss-rootdev] -> [%s] \n\e[0m" "${CDLB_MAPPER_DEV}"
### Final sanity check. --------------------------------------------------------------------------------------------------------
if [ ! -b "${CDLB_MAPPER_DEV}" ]; then
log "Failed to unlock encrypted root [${CDLB_LUKS_FS}] via dropbear and console."
printf "\e[91m[WARN] Failed unlock : [%s] via dropbear and console. \n\e[0m" "${CDLB_LUKS_FS}"
exit 42
fi
printf "\e[92m[INFO] Successfully applied: [/usr/lib/live/boot/0024-ciss-crypt-squash] \n\e[0m"
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh