#!/bin/bash # SPDX-Version: 3.0 # SPDX-CreationInfo: 2025-06-17; WEIDNER, Marc S.; # SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.installer.git # SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency # SPDX-FileCopyrightText: 2024-2025; WEIDNER, Marc S.; # 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.installer # SPDX-Security-Contact: security@coresecret.eu guard_sourcing ####################################### # Configure the target system for chroot. # Globals: # TARGET # VAR_CHROOT_ACTIVATED # VAR_CHROOT_SYS_MASK_HELPER # VAR_NEED_RUN_IN_TARGET # Arguments: # None # Returns: # 0: on success # ERR_CHRT_MOUNTS: on failure ####################################### prepare_mounts() { ### Notes # This function mounts all necessary pseudo filesystems into the target root environment to enable chroot operations. # --rbind: recursive binding. # --make-rslave: In this case, the mount point is marked as 'slave'. # This means changes to the source mount (e.g., /proc) are propagated to the target mount (e.g., "${TARGET}/proc"). # Conversely, changes to the target mount are not propagated back to the source mount. # This mode is necessary to avoid problems with double or erroneous propagation effects in chroot or container environments. # # Some subdirectories (such as /dev/pts, /dev/shm, /sys/fs/cgroup) are remounted with more restrictive options # like 'noexec', 'nosuid', and 'nodev' to enhance security. This ensures they override the inherited bind-mounts and # enforce proper runtime behavior in the chroot. ### Declare Arrays, HashMaps, and Variables. declare -A HMP_SPECIAL_MOUNTS=( ["/dev"]="devtmpfs devtmpfs mode=0755,nosuid" # Base device node FS ["/dev/pts"]="devpts devpts noexec,nosuid" # Pseudoterminals ["/dev/shm"]="tmpfs tmpfs rw,nosuid,nodev" # Shared memory ["/dev/mqueue"]="mqueue mqueue rw,nosuid,nodev,noexec" # POSIX message queues ["/dev/hugepages"]="hugetlbfs hugetlbfs rw,nosuid,nodev" # Huge pages ["/proc"]="proc proc nosuid,noexec,nodev" # procfs ["/sys"]="sysfs sysfs nosuid,noexec,nodev" # sysfs ["/sys/fs/cgroup"]="cgroup2 cgroup2 rw,nosuid,nodev,noexec,relatime" # Unified cgroup2 ) declare var_path="" var_fs="" var_src="" var_opts="" # shellcheck disable=SC2034 declare -g VAR_CHROOT_SYS_MASK_HELPER="" # shellcheck disable=SC2034 VAR_CHROOT_SYS_MASK_HELPER=$(cat <<'EOF' #------------------------------------------------------------------------------- # Helpers: mount detection and conditional umount (idempotent). # Detect if PATH is an exact mountpoint (not just covered by a parent mount). cdi_is_mountpoint() { declare path="${1:?target path required}" if command -v mountpoint >/dev/null 2>&1; then mountpoint -q -- "${path}" return $? fi if command -v findmnt >/dev/null 2>&1; then # Exact mountpoint check (not -T which matches enclosing mounts). findmnt -rn --mountpoint "${path}" >/dev/null 2>&1 && return 0 || return 1 fi # Fallback: parse /proc/self/mountinfo (field 5 = mountpoint, no spaces here). awk -v p="${path}" '$5==p {found=1; exit} END{exit (found?0:1)}' /proc/self/mountinfo 2>/dev/null } cdi_umount_if_mountpoint() { declare path="${1:?target path required}" if cdi_is_mountpoint "${path}"; then umount -l -- "${path}" || { printf 'ERROR: cannot umount %s\n' "${path}" >&2; return 128; } fi return 0 } cdi_sys_mask_enter() { declare state="/run/.ciss_sysmask" mkdir -p /run # Record only true mountpoints. declare had_sys="0" declare had_cg="0" cdi_is_mountpoint /sys && had_sys="1" cdi_is_mountpoint /sys/fs/cgroup && had_cg="1" printf 'HAD_SYS=%s\nHAD_CG=%s\n' "${had_sys}" "${had_cg}" >| "${state}" # Unmount only if exact mountpoints exist. cdi_umount_if_mountpoint /sys/fs/cgroup || return 129 cdi_umount_if_mountpoint /sys || return 130 mkdir -p /sys mount -t tmpfs -o ro,nosuid,nodev,noexec,mode=0555,size=1M tmpfs /sys \ || { printf 'ERROR: cannot mount tmpfs on /sys\n' >&2; return 131; } return 0 } cdi_sys_mask_leave() { declare state="/run/.ciss_sysmask" declare had_sys="0" declare had_cg="0" if [[ -f "${state}" ]]; then # shellcheck disable=SC2155 declare had_sys="$(grep -Eo '^HAD_SYS=[01]' "${state}" 2>/dev/null | cut -d= -f2 || printf '0')" # shellcheck disable=SC2155 declare had_cg="$(grep -Eo '^HAD_CG=[01]' "${state}" 2>/dev/null | cut -d= -f2 || printf '0')" fi # Drop the mask if present (it is an exact mountpoint). cdi_umount_if_mountpoint /sys || return 132 if [[ "${had_sys}" == "1" ]]; then mount -t sysfs -o nosuid,nodev,noexec sysfs /sys \ || { printf 'ERROR: cannot mount sysfs on /sys\n' >&2; return 133; } fi if [[ "${had_cg}" == "1" ]]; then mkdir -p /sys/fs/cgroup mount -t cgroup2 -o rw,nosuid,nodev,noexec,relatime cgroup2 /sys/fs/cgroup \ || { printf 'ERROR: cannot mount cgroup2 on /sys/fs/cgroup\n' >&2; return 134; } fi rm -f -- "${state}" return 0 } #------------------------------------------------------------------------------- EOF ) for var_path in "${!HMP_SPECIAL_MOUNTS[@]}"; do mkdir -p "${TARGET}${var_path}" done for var_path in "${!HMP_SPECIAL_MOUNTS[@]}"; do IFS=" " read -r var_fs var_src var_opts <<< "${HMP_SPECIAL_MOUNTS[${var_path}]}" if mountpoint -q "${TARGET}${var_path}"; then do_log "info" "file_only" "4010() Skipped: '${TARGET}${var_path}' is already a mountpoint." continue fi if ! mount -t "${var_fs}" "${var_src}" "${TARGET}${var_path}" -o "${var_opts}"; then do_log "emergency" "file_only" "4010() Command: [mount -t ${var_fs} ${var_src} ${TARGET}${var_path} -o ${var_opts}] failed." return "${ERR_CHRT_MOUNTS}" fi do_log "info" "file_only" "4010() Command: [mount -t ${var_fs} ${var_src} ${TARGET}${var_path} -o ${var_opts}] successful." done if [[ "${VAR_NEED_RUN_IN_TARGET:-false}" == "true" ]]; then mkdir -p "${TARGET}/run" if ! mount --make-rslave --rbind /run "${TARGET}/run"; then do_log "emergency" "file_only" "4010() Command: [mount --make-rslave --rbind /run ${TARGET}/run] failed." return "${ERR_CHRT_MOUNTS}" fi do_log "info" "file_only" "4010() Command: [mount --make-rslave --rbind /run ${TARGET}/run] successful." fi if ! chroot_exec "${TARGET}" mkdir -p /etc/systemd/system/multi-user.target.wants; then do_log "emergency" "file_only" "4010() Command: [chroot_exec ${TARGET} mkdir -p /etc/systemd/system/multi-user.target.wants] failed." return "${ERR_CHRT_MOUNTS}" fi do_log "info" "file_only" "4010() Command: [chroot_exec ${TARGET} mkdir -p /etc/systemd/system/multi-user.target.wants] successful." mkdir -p "${TARGET}/media/cdrom0" # shellcheck disable=SC2034 declare -gx VAR_CHROOT_ACTIVATED="system" do_log "info" "file_only" "4010() Command: [declare -gx VAR_CHROOT_ACTIVATED=system]" guard_dir && return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f prepare_mounts # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh