Some checks failed
💙 Generating a PUBLIC Live ISO. / 💙 Generating a PUBLIC Live ISO. (push) Has been cancelled
🔐 Generating a Private Live ISO TRIXIE. / 🔐 Generating a Private Live ISO TRIXIE. (push) Has been cancelled
🛡️ Retrieve DNSSEC status of coresecret.dev. / 🛡️ Retrieve DNSSEC status of coresecret.dev. (push) Successful in 59s
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Successful in 1m5s
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
303 lines
10 KiB
Bash
303 lines
10 KiB
Bash
#!/bin/bash
|
|
# SPDX-Version: 3.0
|
|
# SPDX-CreationInfo: 2025-10-11; 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: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1
|
|
# 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
|
|
set -Ceuo pipefail
|
|
|
|
printf "\e[95m++++ ++++ ++++ ++++ ++++ ++++ ++ 🧪 '%s' starting ... \e[0m\n" "${0}"
|
|
|
|
[[ -r /root/ciss_xdg_tmp.sh ]] && . /root/ciss_xdg_tmp.sh
|
|
export DEBIAN_FRONTEND="noninteractive"
|
|
export INITRD="No"
|
|
|
|
apt-get install -y --no-install-recommends kexec-tools
|
|
|
|
install -d -m 0755 /boot/ciss-memwipe
|
|
install -d -m 0755 /usr/local/sbin
|
|
install -d -m 0755 /etc/systemd/system
|
|
install -d -m 0755 /etc/default
|
|
|
|
### Pick a kernel to kexec into: use the latest installed vmlinuz. -------------------------------------------------------------
|
|
# shellcheck disable=SC2012,SC2155
|
|
declare _KERNEL="$(cd /boot && ls -1 vmlinuz-* | sed 's|vmlinuz-||' | sort -V | tail -n1)"
|
|
cp -f "/boot/vmlinuz-${_KERNEL}" /boot/ciss-memwipe/vmlinuz
|
|
|
|
### Build minimal initramfs with a busybox and a tiny '/init'. -----------------------------------------------------------------
|
|
declare _TMP_DIR; _TMP_DIR="$(mktemp -d)"
|
|
trap 'rm -rf "${_TMP_DIR}"' EXIT
|
|
|
|
mkdir -p "${_TMP_DIR}"/{bin,dev,proc,sys,wipe}
|
|
|
|
### Locate the current busybox binary. -----------------------------------------------------------------------------------------
|
|
declare _BUSYBOX_BIN; _BUSYBOX_BIN="$(command -v busybox || true)"
|
|
if [[ -z "${_BUSYBOX_BIN}" ]]; then
|
|
echo "ERROR: busybox not found after installation attempt." >&2
|
|
exit 42
|
|
fi
|
|
|
|
cp -f "${_BUSYBOX_BIN}" "${_TMP_DIR}/bin/busybox"
|
|
|
|
#######################################
|
|
# Copy required shared libs into the initramfs (if the busybox is dynamic).
|
|
# Globals:
|
|
# _TMP_DIR
|
|
# Arguments:
|
|
# 1: _BUSYBOX_BIN
|
|
# Returns:
|
|
# 0: on success
|
|
#######################################
|
|
copy_libs() {
|
|
declare bin="$1"
|
|
|
|
if ldd "${bin}" 2>&1 | grep -q 'not a dynamic executable'; then
|
|
return 0
|
|
fi
|
|
|
|
ldd "${bin}" | awk '
|
|
/=> \// {print $3}
|
|
# some libs are printed as absolute path without "=>"
|
|
/^\// {print $1}
|
|
' | while read -r lib; do
|
|
[[ -n "${lib}" ]] || continue
|
|
dest="${_TMP_DIR}$(dirname "${lib}")"
|
|
install -d -m 0755 "${dest}"
|
|
cp -f "${lib}" "${dest}"
|
|
done
|
|
}
|
|
|
|
copy_libs "${_BUSYBOX_BIN}"
|
|
|
|
### Generate '/init' script ----------------------------------------------------------------------------------------------------
|
|
cat << 'EOF' >| "${_TMP_DIR}/init"
|
|
#!/bin/busybox sh
|
|
# SPDX-Version: 3.0
|
|
# SPDX-CreationInfo: 2025-10-11; 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: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1
|
|
# 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
|
|
|
|
# Minimal init to wipe RAM, then power off.
|
|
# Parses cmdline: ciss_wipe_passes=2 ciss_wipe_mode=zero+random ciss_dd_bs=64M ciss_tmpfs_pct=95
|
|
set -eu
|
|
|
|
#######################################
|
|
# Helper
|
|
# Globals:
|
|
# None
|
|
# Arguments:
|
|
# 1: key
|
|
# Returns:
|
|
# 0: on success
|
|
#######################################
|
|
get_arg() { # $1=key ; echoes value or empty
|
|
for tok in $(cat /proc/cmdline); do
|
|
case "$tok" in
|
|
$1=*) echo "${tok#*=}"; return 0;;
|
|
esac
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
mount -t devtmpfs devtmpfs /dev 2>/dev/null || true
|
|
[ -e /dev/console ] || mknod -m 600 /dev/console c 5 1
|
|
[ -e /dev/null ] || mknod -m 666 /dev/null c 1 3
|
|
[ -e /dev/urandom ] || mknod -m 444 /dev/urandom c 1 9
|
|
|
|
mount -t proc proc /proc
|
|
mount -t sysfs sysfs /sys
|
|
|
|
PASSES="$(get_arg ciss_wipe_passes)"; [ -n "${PASSES}" ] || PASSES=2
|
|
MODE="$(get_arg ciss_wipe_mode)"; [ -n "${MODE}" ] || MODE="zero+random"
|
|
BS="$(get_arg ciss_dd_bs)"; [ -n "${BS}" ] || BS=64M
|
|
PCT="$(get_arg ciss_tmpfs_pct)"; [ -n "${PCT}" ] || PCT=95
|
|
|
|
echo 1 >| /proc/sys/kernel/printk 2>/dev/null || true
|
|
|
|
MEM_KB="$(awk '/MemTotal:/ {print $2}' /proc/meminfo)"
|
|
SIZE_KB=$(( MEM_KB * PCT / 100 ))
|
|
mount -t tmpfs -o "size=${SIZE_KB}k,nodev,nosuid,noexec,mode=0700" tmpfs /wipe
|
|
|
|
#######################################
|
|
# Wipe helper
|
|
# Globals:
|
|
# None
|
|
# Arguments:
|
|
# 1: pattern
|
|
# Returns:
|
|
# 0: on success
|
|
#######################################
|
|
wipe_pass() {
|
|
pattern="$1" # zero or random
|
|
if [ "$pattern" = "zero" ]; then
|
|
src="/dev/zero"
|
|
else
|
|
src="/dev/urandom"
|
|
fi
|
|
|
|
i=0
|
|
while :; do
|
|
# Use busybox dd explicitly to avoid surprises
|
|
busybox dd if="$src" of="/wipe/block_$i" bs="$BS" status=none || break
|
|
i=$((i+1))
|
|
done
|
|
sync
|
|
echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
|
|
rm -f /wipe/block_* 2>/dev/null || true
|
|
sync
|
|
return 0
|
|
}
|
|
|
|
DO_ZERO=0; DO_RANDOM=0
|
|
case "$MODE" in
|
|
zero) DO_ZERO=1 ;;
|
|
random) DO_RANDOM=1 ;;
|
|
zero+random|random+zero) DO_ZERO=1; DO_RANDOM=1 ;;
|
|
*) DO_ZERO=1 ;;
|
|
esac
|
|
|
|
p=1
|
|
while [ $p -le "$PASSES" ]; do
|
|
[ $DO_ZERO -eq 1 ] && wipe_pass zero
|
|
[ $DO_RANDOM -eq 1 ] && wipe_pass random
|
|
p=$((p+1))
|
|
done
|
|
|
|
sync
|
|
busybox poweroff -f || echo o >| /proc/sysrq-trigger
|
|
|
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
|
EOF
|
|
|
|
chmod +x "${_TMP_DIR}/init"
|
|
|
|
### Create the initramfs archive -----------------------------------------------------------------------------------------------
|
|
( cd "${_TMP_DIR}" && find . -print0 | cpio --null -ov --format=newc ) | gzip -9 > /boot/ciss-memwipe/initrd.img
|
|
|
|
### Default configuration.
|
|
cat << 'EOF' >| /etc/default/ciss-memwipe
|
|
# SPDX-Version: 3.0
|
|
# SPDX-CreationInfo: 2025-10-11; 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: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1
|
|
# 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
|
|
|
|
# CISS Memory Wipe defaults:
|
|
|
|
CISS_WIPE_PASSES=2 # number of passes
|
|
CISS_WIPE_MODE="zero+random" # zero | random | zero+random
|
|
CISS_WIPE_DD_BS="64M" # dd block size
|
|
CISS_WIPE_TMPFS_PCT=95 # percentage of MemTotal to allocate
|
|
|
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=conf
|
|
EOF
|
|
|
|
### Helper script --------------------------------------------------------------------------------------------------------------
|
|
cat << 'EOF' >| /usr/local/sbin/ciss-memwipe
|
|
#!/bin/bash
|
|
# SPDX-Version: 3.0
|
|
# SPDX-CreationInfo: 2025-10-11; 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: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1
|
|
# 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
|
|
set -euo pipefail
|
|
|
|
. /etc/default/ciss-memwipe || true
|
|
|
|
KERNEL="/boot/ciss-memwipe/vmlinuz"
|
|
INITRD="/boot/ciss-memwipe/initrd.img"
|
|
|
|
append_common="quiet loglevel=1 ciss_wipe_passes=${CISS_WIPE_PASSES:-2} ciss_wipe_mode=${CISS_WIPE_MODE:-zero+random} ciss_dd_bs=${CISS_WIPE_DD_BS:-64M} ciss_tmpfs_pct=${CISS_WIPE_TMPFS_PCT:-95}"
|
|
|
|
prepare() {
|
|
if [ -w /proc/sys/kernel/kexec_load_disabled ] && [ "$(cat /proc/sys/kernel/kexec_load_disabled)" = "1" ]; then
|
|
echo 0 > /proc/sys/kernel/kexec_load_disabled || true
|
|
fi
|
|
if command -v kexec >/dev/null 2>&1 && [ -s "$KERNEL" ] && [ -s "$INITRD" ]; then
|
|
kexec -l "$KERNEL" --initrd="$INITRD" --append="$append_common" || true
|
|
fi
|
|
}
|
|
|
|
fallback_inplace() {
|
|
mount -t tmpfs -o "size=95%,nodev,nosuid,noexec,mode=0700" tmpfs /run/wipe 2>/dev/null || mkdir -p /run/wipe
|
|
i=0
|
|
while :; do
|
|
dd if=/dev/zero of="/run/wipe/blk_$i" bs="${CISS_WIPE_DD_BS:-64M}" status=none || break
|
|
i=$((i+1))
|
|
done
|
|
sync; echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
|
|
rm -f /run/wipe/blk_* 2>/dev/null || true
|
|
sync
|
|
systemctl poweroff -f || poweroff -f || echo o > /proc/sysrq-trigger
|
|
}
|
|
|
|
execute() {
|
|
sync; echo 3 > /proc/sys/vm/drop_caches 2>/dev/null || true
|
|
if command -v systemctl >/dev/null 2>&1 && systemctl --quiet is-system-running; then
|
|
systemctl kexec || kexec -e || fallback_inplace
|
|
else
|
|
kexec -e || fallback_inplace
|
|
fi
|
|
}
|
|
|
|
case "${1:-}" in
|
|
prepare) prepare ;;
|
|
execute) execute ;;
|
|
*) echo "Usage: $0 {prepare|execute}" >&2; exit 2 ;;
|
|
esac
|
|
|
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
|
EOF
|
|
chmod 0755 /usr/local/sbin/ciss-memwipe
|
|
|
|
### Systemd service: load at boot, execute on shutdown. ------------------------------------------------------------------------
|
|
cat << 'EOF' >| /etc/systemd/system/ciss-memwipe.service
|
|
[Unit]
|
|
Description=CISS: preload and execute kexec-based RAM wipe on shutdown
|
|
DefaultDependencies=no
|
|
Before=shutdown.target
|
|
After=local-fs.target network.target multi-user.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
RemainAfterExit=yes
|
|
ExecStart=/usr/local/sbin/ciss-memwipe prepare
|
|
ExecStop=/usr/local/sbin/ciss-memwipe execute
|
|
TimeoutStartSec=20s
|
|
TimeoutStopSec=infinity
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
install -d -m 0755 /etc/systemd/system/multi-user.target.wants
|
|
ln -sf /etc/systemd/system/ciss-memwipe.service /etc/systemd/system/multi-user.target.wants/ciss-memwipe.service
|
|
|
|
systemctl enable ciss-memwipe.service
|
|
|
|
printf "\e[92m++++ ++++ ++++ ++++ ++++ ++++ ++ ✅ '%s' applied successfully. \e[0m\n" "${0}"
|
|
|
|
exit 0
|
|
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|