V9.14.024.2026.06.11
🛡️ Retrieve DNSSEC status of coresecret.dev. / 🛡️ Retrieve DNSSEC status of coresecret.dev. (push) Has been cancelled
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Has been cancelled
💙 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) Has been cancelled
🛡️ Shell Script Linting / 🛡️ Shell Script Linting (push) Has been cancelled
💙 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
Signed-off-by: Marc S. Weidner <msw@coresecret.dev>
This commit is contained in:
@@ -0,0 +1,318 @@
|
||||
#!/bin/bash
|
||||
# SPDX-Version: 3.0
|
||||
# SPDX-CreationInfo: 2026-06-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-2026; 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
|
||||
# shellcheck disable=SC2154
|
||||
|
||||
# Module overview:
|
||||
# This module centralizes build-directory safety checks for path validation, builder-ownership markers, and destructive cleanup
|
||||
# helpers. It keeps cleanup operations limited to canonical, explicitly validated build-directory paths.
|
||||
#
|
||||
# Function behavior:
|
||||
# build_dir_safety_error(): writes a scoped build-directory safety error message to stderr.
|
||||
# reject_broad_build_dir_path(): rejects the filesystem root and common top-level system directories as build targets.
|
||||
# validate_build_dir_argument(): validates a non-empty absolute build-directory argument before the path is created.
|
||||
# validate_existing_build_dir(): validates the argument and confirms that it resolves to an existing directory.
|
||||
# require_builder_owned_build_dir(): requires a validated directory with a safe root-owned builder marker.
|
||||
# ensure_builder_owned_build_dir(): creates the marker for a safe empty build directory or verifies an existing marker.
|
||||
# require_builder_owned_subpath(): confirms that a target exists strictly below a verified builder-owned directory.
|
||||
# safe_clean_build_dir_contents(): removes direct build-directory contents while preserving the builder marker.
|
||||
# safe_remove_builder_subpath(): removes one verified subpath below a builder-owned build directory.
|
||||
|
||||
guard_sourcing || return "${ERR_GUARD_SRCE}"
|
||||
|
||||
#######################################
|
||||
# Print a cleanup/path safety error.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Error detail.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
#######################################
|
||||
build_dir_safety_error() {
|
||||
declare detail="${1}"
|
||||
|
||||
printf "\e[91m❌ build directory safety: %s \e[0m\n" "${detail}" >&2
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f build_dir_safety_error
|
||||
|
||||
#######################################
|
||||
# Reject broad parent directories as build-directory targets.
|
||||
# Globals:
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Canonical path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
reject_broad_build_dir_path() {
|
||||
declare canonical_path="${1}"
|
||||
|
||||
case "${canonical_path}" in
|
||||
"" | "/" | "/bin" | "/boot" | "/dev" | "/etc" | "/home" | "/lib" | "/lib64" | "/opt" | "/proc" | "/root" | "/run" | "/sbin" | "/sys" | "/tmp" | "/usr" | "/var")
|
||||
build_dir_safety_error "refusing broad path."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f reject_broad_build_dir_path
|
||||
|
||||
#######################################
|
||||
# Validate a build-directory argument before it is created.
|
||||
# Globals:
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
validate_build_dir_argument() {
|
||||
declare build_dir="${1}" canonical_path=""
|
||||
|
||||
if [[ -z "${build_dir}" ]]; then
|
||||
build_dir_safety_error "path MUST NOT be empty."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
if [[ "${build_dir}" != /* ]]; then
|
||||
build_dir_safety_error "path MUST be absolute."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
if [[ -L "${build_dir}" ]]; then
|
||||
build_dir_safety_error "path MUST NOT be a symlink."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
canonical_path="$(realpath -m -- "${build_dir}")"
|
||||
reject_broad_build_dir_path "${canonical_path}" || return "${?}"
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f validate_build_dir_argument
|
||||
|
||||
#######################################
|
||||
# Canonicalize and validate an existing build directory.
|
||||
# Globals:
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
validate_existing_build_dir() {
|
||||
declare build_dir="${1}" canonical_path=""
|
||||
|
||||
validate_build_dir_argument "${build_dir}" || return "${?}"
|
||||
|
||||
if [[ ! -d "${build_dir}" ]]; then
|
||||
build_dir_safety_error "path MUST be an existing directory."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
canonical_path="$(realpath -e -- "${build_dir}")"
|
||||
reject_broad_build_dir_path "${canonical_path}" || return "$?"
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f validate_existing_build_dir
|
||||
|
||||
#######################################
|
||||
# Validate the builder-owned marker in a build directory.
|
||||
# Globals:
|
||||
# CISS_BUILD_DIR_MARKER
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
require_builder_owned_build_dir() {
|
||||
declare build_dir="${1}" canonical_path="" marker_path="" marker_owner="" marker_mode="" marker_mode_octal=""
|
||||
|
||||
validate_existing_build_dir "${build_dir}" || return "$?"
|
||||
|
||||
canonical_path="$(realpath -e -- "${build_dir}")"
|
||||
marker_path="${canonical_path}/${CISS_BUILD_DIR_MARKER}"
|
||||
|
||||
if [[ -L "${marker_path}" || ! -f "${marker_path}" ]]; then
|
||||
build_dir_safety_error "builder-owned marker is missing or unsafe."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
marker_owner="$(stat -c '%u:%g' -- "${marker_path}")"
|
||||
if [[ "${marker_owner}" != "0:0" ]]; then
|
||||
build_dir_safety_error "builder-owned marker MUST be owned by root:root."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
marker_mode="$(stat -c '%a' -- "${marker_path}")"
|
||||
marker_mode_octal=$((8#${marker_mode}))
|
||||
if (( (marker_mode_octal & 022) != 0 )); then
|
||||
build_dir_safety_error "builder-owned marker MUST NOT be group- or world-writable."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f require_builder_owned_build_dir
|
||||
|
||||
#######################################
|
||||
# Create or preserve the builder-owned marker.
|
||||
# Globals:
|
||||
# CISS_BUILD_DIR_MARKER
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
ensure_builder_owned_build_dir() {
|
||||
declare build_dir="${1}" canonical_path="" marker_path=""
|
||||
|
||||
validate_existing_build_dir "${build_dir}" || return "${?}"
|
||||
|
||||
canonical_path="$(realpath -e -- "${build_dir}")"
|
||||
marker_path="${canonical_path}/${CISS_BUILD_DIR_MARKER}"
|
||||
|
||||
if [[ -e "${marker_path}" || -L "${marker_path}" ]]; then
|
||||
require_builder_owned_build_dir "${canonical_path}" || return "${?}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -d "${canonical_path}/.build" ]]; then
|
||||
build_dir_safety_error "existing live-build state lacks the builder-owned marker."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
install -m 0600 -o root -g root /dev/null "${marker_path}"
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f ensure_builder_owned_build_dir
|
||||
|
||||
#######################################
|
||||
# Validate that a target path is strictly below a builder-owned build directory.
|
||||
# Globals:
|
||||
# ERR_INVLD_CHAR
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# 2: Target-path below the build directory.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# ERR_INVLD_CHAR: on failure
|
||||
#######################################
|
||||
require_builder_owned_subpath() {
|
||||
declare build_dir="${1}" target_path="${2}" build_real="" target_real=""
|
||||
|
||||
require_builder_owned_build_dir "${build_dir}" || return "$?"
|
||||
|
||||
if [[ -z "${target_path}" || -L "${target_path}" || ! -e "${target_path}" ]]; then
|
||||
build_dir_safety_error "target subpath is empty, missing, or a symlink."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
build_real="$(realpath -e -- "${build_dir}")"
|
||||
target_real="$(realpath -e -- "${target_path}")"
|
||||
|
||||
if [[ "${target_real}" == "${build_real}" ]]; then
|
||||
build_dir_safety_error "target subpath MUST NOT be the build directory itself."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
fi
|
||||
|
||||
case "${target_real}" in
|
||||
"${build_real}"/*)
|
||||
;;
|
||||
*)
|
||||
build_dir_safety_error "target subpath MUST stay below the build directory."
|
||||
return "${ERR_INVLD_CHAR}"
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f require_builder_owned_subpath
|
||||
|
||||
#######################################
|
||||
# Remove all contents of the exact builder-owned build directory.
|
||||
# Globals:
|
||||
# CISS_BUILD_DIR_MARKER
|
||||
# Arguments:
|
||||
# 1: Build directory path.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# Non-zero: on failure
|
||||
#######################################
|
||||
safe_clean_build_dir_contents() {
|
||||
declare build_dir="${1}" build_real=""
|
||||
|
||||
require_builder_owned_build_dir "${build_dir}" || return "${?}"
|
||||
|
||||
build_real="$(realpath -e -- "${build_dir}")"
|
||||
|
||||
find "${build_real}" -mindepth 1 -maxdepth 1 -xdev ! -name "${CISS_BUILD_DIR_MARKER}" -exec rm -rf --one-file-system -- {} +
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f safe_clean_build_dir_contents
|
||||
|
||||
#######################################
|
||||
# Remove one exact builder-owned subpath.
|
||||
# Globals:
|
||||
# None
|
||||
# Arguments:
|
||||
# 1: Build-directory-path.
|
||||
# 2: Target-path below build-directory.
|
||||
# Returns:
|
||||
# 0: on success
|
||||
# Non-zero: on failure
|
||||
#######################################
|
||||
safe_remove_builder_subpath() {
|
||||
declare build_dir="${1}" target_path="${2}" target_real=""
|
||||
|
||||
require_builder_owned_subpath "${build_dir}" "${target_path}" || return "${?}"
|
||||
|
||||
target_real="$(realpath -e -- "${target_path}")"
|
||||
rm -rf --one-file-system -- "${target_real}"
|
||||
|
||||
return 0
|
||||
}
|
||||
### Prevents accidental 'unset -f'.
|
||||
# shellcheck disable=SC2034
|
||||
readonly -f safe_remove_builder_subpath
|
||||
# vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh
|
||||
Reference in New Issue
Block a user