more fixes, add argon2 patch

This commit is contained in:
Anderson Rosenberg 2025-09-01 17:42:15 -04:00
parent c28c503296
commit 0830eb4e45
No known key found for this signature in database
GPG key ID: 7ACF448C0590AB9C
11 changed files with 150 additions and 86 deletions

2
build.sh Normal file → Executable file
View file

@ -2,5 +2,7 @@
set -euo pipefail
# Build Shufflecake
echo "[INFO]: Building qubes-sflc..."
cd qubes-sflc
./build.sh
echo "[INFO]: Build complete."

View file

@ -10,10 +10,10 @@ depends() {
install() {
# Interactive script
inst_simple "$moddir/scripts/reliant-initramfs.sh" "/usr/local/share/scripts/reliant-initramfs.sh"
inst_script "$moddir/scripts/reliant-initramfs.sh" "/usr/local/share/scripts/reliant-initramfs.sh"
# Main service
inst_simple "$moddir/reliant.service" "/etc/systemd/system/reliant.service"
inst "$moddir/reliant.service" "/etc/systemd/system/reliant.service"
systemctl --root="$initdir" enable reliant.service
# Shufflecake
@ -28,10 +28,12 @@ install() {
# TODO: Do we need udev rules to --setro newly attached devices?
# Reliant
for file in "/usr/local/share/scripts/reliant-*" "/usr/local/sbin/reliant-*" "/usr/local/bin/surgeon-*"; do
inst_binary "$file"
done
inst_simple "/etc/reliant.conf"
inst_script /usr/local/share/scripts/reliant-common.sh
inst_script /usr/local/sbin/reliant-security
inst_script /usr/local/sbin/surgeon-suture
inst_script /usr/local/sbin/reliant-mount
inst_script /usr/local/sbin/reliant-hash
inst /etc/reliant.conf
# Other binaries
inst_multiple dmesg lsblk blockdev mount dd wc sed sleep md5sum find modprobe cut grep mkdir rm tail

View file

@ -6,7 +6,7 @@ export RELIANT_INITRAMFS=$RELIANT_TRUE
# Upon encountering issues, prompt the user for the next course of action
reliant_prompt_user() {
while true; do
REPLY=$(plymouth ask-question --prompt="System might be compromised. Proceed? [Y(es)/N(o)/S(kip)]: ")
REPLY=$(plymouth ask-question --prompt="System might be compromised. Proceed? [Y(es)/N(o)/S(kip)]")
case $REPLY in
[Yy]*)
# User confirmed the system is safe to boot
@ -29,16 +29,16 @@ reliant_prompt_user() {
exit 0 ;;
*)
plymouth display-message --text="Invalid response. [Y(es)/N(o)/S(kip)]: "
plymouth display-message --text="Invalid response."
sleep 1
plymouth hide-message --text="Invalid response. [Y(es)/N(o)/S(kip)]: "
plymouth hide-message --text="Invalid response."
;;
esac
done
}
# Ensures the canary files have been wiped by previous shutdown
reliant_initramfs_check_canaries() {
reliant_security_initramfs_check_canaries() {
# /rootfs.canary
if [ -f /rootfs.canary ]; then
reliant_error "reliant_initramfs_check_canaries: /rootfs.canary exists!"
@ -73,14 +73,25 @@ reliant_initramfs_check_canaries() {
# Verifies that the initramfs cannot leak information via non-volatile media, logs or network
reliant_security_check_initramfs() {
# Run the common checks
reliant-security /sysroot || return $RELIANT_SECURITY_FAIL
# Run the common checks first
status_common=$RELIANT_OK
reliant-security /sysroot || status_common=$?
# No need to report, already done
# Check canaries
reliant_security_initramfs_check_canaries || return $RELIANT_SECURITY_FAIL
# Pass
return 0
status_canaries=$RELIANT_OK
reliant_security_initramfs_check_canaries || status_canaries=$?
echo "[CANARIES]: $(reliant_err2str $status_canaries)"
# Calculate and return the verdict
echo -n "[VERDICT]: "
if [ $status_common -eq $RELIANT_OK ] && [ $status_canaries -eq $RELIANT_OK ]; then
echo "SAFE TO BOOT"
return $RELIANT_OK
else
echo "POTENTIALLY COMPROMISED"
return $RELIANT_SECURITY_FAIL
fi
}
# Main function

View file

@ -22,6 +22,7 @@ fi
: "${RELIANT_SKIP_CHECKSUM:=}"
: "${RELIANT_SPARSE_SAMPLES:=512}"
: "${RELIANT_BOOTSTRAP_QUBE:=bootstrap}"
: "${RELIANT_KERNEL_VERSION:=$(qvm-run --pass-io "$RELIANT_BOOTSTRAP_QUBE" 'uname -r')}"
# Validate configuration values
if [ -z "$RELIANT_SECURE_DEVICE" ]; then
@ -86,6 +87,10 @@ reliant_install_dracut() {
reliant_install_file "$1" "$RELIANT_DRACUT_DIR/$2" "$3" "$4" "$5"
}
# Run the build script inside of the bootstrap qube
echo "[INFO]: Building $RELIANT_BOOTSTRAP_QUBE:$RELIANT_SYSTEM_ROOT for kernel $RELIANT_KERNEL_VERSION..."
qvm-run --pass-io "$RELIANT_BOOTSTRAP_QUBE" "sh -c 'cd $RELIANT_SYSTEM_ROOT && ./build.sh'"
# Begin the installation process
echo "[INFO]: Installing reliant-system from $RELIANT_BOOTSTRAP_QUBE:$RELIANT_SYSTEM_ROOT..."
@ -118,7 +123,7 @@ reliant_install_dracut dracut/99reliant/scripts/reliant-initramfs.sh scripts/rel
reliant_install_dracut dracut/99reliant/patches/create-snapshot.sh patches/create-snapshot.sh 0755 root root
# reliant-system/qubes-sflc
reliant_install_file qubes-sflc/dm-sflc.ko "/usr/lib/modules/$(uname -r)/extra" 0644 root root
reliant_install_file qubes-sflc/dm-sflc.ko "/usr/lib/modules/$RELIANT_KERNEL_VERSION/extra/dm-sflc.ko" 0644 root root
reliant_install_sbin qubes-sflc/shufflecake shufflecake 0744 root root
echo "[INFO]: Successfully copied files to dom0."
@ -158,11 +163,11 @@ systemctl enable shufflecake-close.service
surgeon-dissect -t varlibqubes
reliant-snapshot-rw
# reliant-system/qubes-sflc
depmod -a "$RELIANT_KERNEL_VERSION"
# reliant-system/dracut
dracut --force --regenerate-all
# reliant-system/qubes-sflc
depmod
# Report successful installation
echo "[INFO]: Installation complete. Reboot to enter protected mode."

View file

@ -2,9 +2,29 @@
set -euo pipefail
# Download the submodules
git submodule init --update --recursive
echo "[INFO]: Updating git submodules..."
git submodule update --init --recursive
# Apply the Argon2 memory parameter patch
echo "[INFO]: Applying Argon2 memory patch to improve KDF resilience..."
# Change the working directory
OLD_PWD=$PWD
cd shufflecake-c
# Apply the patch
CRYPTO_H=shufflecake-userland/include/utils/crypto.h
git restore $CRYPTO_H
patch $CRYPTO_H "$OLD_PWD/crypto.h.patch"
# Return back to qubes-sflc
cd "$OLD_PWD"
# Notify user of a breaking change
echo "[WARN]: Your new Argon2 memory parameter is 2097152 KiB, INCOMPATIBLE with default Shufflecake."
# Ensure Docker is running
echo "[INFO]: Starting the Docker container..."
sudo systemctl start docker
# Build and execute the container
@ -12,5 +32,9 @@ sudo docker build -t qubes-sflc .
sudo docker run --rm -v /usr/lib/modules:/usr/lib/modules:ro -v $PWD/shufflecake-c:/root/shufflecake-c qubes-sflc
# Copy artifacts
cp shufflecake-c/dm-sflc.ko $PWD/dm-sflc.ko
cp shufflecake-c/shufflecake $PWD/shufflecake
echo "[INFO]: Copying build artifacts..."
cp shufflecake-c/dm-sflc.ko "$PWD/dm-sflc.ko"
cp shufflecake-c/shufflecake "$PWD/shufflecake"
# Restore the original crypto.h to avoid interference with future updates
git restore "shufflecake-c/$CRYPTO_H"

13
qubes-sflc/crypto.h.patch Normal file
View file

@ -0,0 +1,13 @@
diff --git a/shufflecake-userland/include/utils/crypto.h b/shufflecake-userland/include/utils/crypto.h
index 8366134..303b2ae 100644
--- a/shufflecake-userland/include/utils/crypto.h
+++ b/shufflecake-userland/include/utils/crypto.h
@@ -67,7 +67,7 @@
// Argon memory parameter
// We assume machines with at least 128 MiB available RAM, so 2^17 kiB
-#define SFLC_ARGON_M (1 << 17) /* kibibytes */
+#define SFLC_ARGON_M 2097152 /* kibibytes */
// Argon iterations count
// We aim for 1-2 seconds on a low-end laptop or mobile (it's a one-time operation)

View file

@ -23,8 +23,9 @@ modprobe dm-sflc
# Prompt the user for their password
while true; do
if plymouth ask-for-password --prompt="Auxillary password" | shufflecake open "$SECURE_DEVICE" &>/dev/null; then
if plymouth ask-for-password --prompt="Auxillary password" | shufflecake open "$RELIANT_SECURE_DEVICE" &>/dev/null; then
plymouth display-message --text="Success"
break
else
plymouth display-message --text="Invalid password"
sleep 2

View file

@ -22,7 +22,7 @@ fi
name=$1
echo -n "Destroying links... "
for appvm in /run/shufflecake/$name/appvms/*; do
for appvm in "/run/shufflecake/$name/appvms/"*; do
qube="${appvm##*/}"
# Shutdown
@ -31,8 +31,8 @@ for appvm in /run/shufflecake/$name/appvms/*; do
# Remove directory
directory="/var/lib/qubes/appvms/$qube"
if [ -d $directory ]; then
rm -rf $directory
if [ -d "$directory" ]; then
rm -rf "$directory"
fi
done
echo "Done."

View file

@ -15,6 +15,11 @@ fi
# No more variable checks needed
set -u
# Require superuser permissions
if [ "$EUID" -ne 0 ]; then
reliant_fail "must be superuser"
fi
# Kernel command line check
reliant_security_check_cmdline() {
# Check if /proc/cmdline exists
@ -94,7 +99,7 @@ reliant_security_check_network() {
# Persistent, real filesystems must be readonly
reliant_security_check_filesystems() {
# Check each mountpoint
mount | while IFS= read -r line; do
mount | while read -r line; do
# Determine the filesystem type
filesystem_type=$(echo "$line" | awk '{ print $5 }' )
@ -115,7 +120,7 @@ reliant_security_check_filesystems() {
esac
done
# Pass from subshell
# Pass status from subshell
return $?
}
@ -139,68 +144,64 @@ reliant_security_check_overlay() {
fi
# Find the mountpoint
mount | while IFS= read -r line; do
# Determine the mountpoint
filesystem_mountpoint=$(echo "$line" | awk '{ print $3 }')
mount | {
found=$RELIANT_FALSE
while read -r line; do
# Filter by mountpoint
filesystem_mountpoint=$(echo "$line" | awk '{ print $3 }')
if [ "$filesystem_mountpoint" != "$1" ]; then continue; fi
# Skip if not matching
if [ "$filesystem_mountpoint" != "$1" ]; then continue; fi
# Determine the filesystem flags
filesystem_flags=$(echo "$line" | awk '{ print $6 }')
# Iterate the flags
upper_found=$RELIANT_FALSE
work_found=$RELIANT_FALSE
IFS=','
for flag in $filesystem_flags; do
case $flag in
'upperdir=/run/systemd/overlay-sysroot/upper') upper_found=0 ;;
'workdir=/run/systemd/overlay-sysroot/work' ) work_found=0 ;;
esac
# Filter by filesystem type
filesystem_type=$(echo "$line" | awk '{ print $5 }' )
if [ "$filesystem_type" != "overlay" ]; then continue; fi
# Determine the filesystem flags
filesystem_flags=$(echo "$line" | awk '{ print $6 }')
# Iterate the flags
upper_found=$RELIANT_FALSE
work_found=$RELIANT_FALSE
IFS=','
for flag in $filesystem_flags; do
case $flag in
'upperdir=/run/systemd/overlay-sysroot/upper') upper_found=$RELIANT_TRUE ;;
'workdir=/run/systemd/overlay-sysroot/work' ) work_found=$RELIANT_TRUE ;;
esac
done
# Check if they have been validated
if [ $work_found -ne $RELIANT_TRUE ]; then
reliant_error "reliant_security_check_overlay: workdir for $1 could not be validated"
exit $RELIANT_SECURITY_FAIL
fi
if [ $upper_found -ne $RELIANT_TRUE ]; then
reliant_error "reliant_security_check_overlay: upperdir for $1 could not be validated"
exit $RELIANT_SECURITY_FAIL
fi
# Indicate that the mountpoint has been found
found=$RELIANT_TRUE
break
done
# Check if they have been validated
if [ $work_found -ne $RELIANT_TRUE ]; then
reliant_error "reliant_security_check_overlay: workdir for $1 could not be validated"
exit $RELIANT_SECURITY_FAIL
fi
if [ $upper_found -ne $RELIANT_TRUE ]; then
reliant_error "reliant_security_check_overlay: upperdir for $1 could not be validated"
# Check if the mountpoint has been found within the loop
if [ $found -ne $RELIANT_TRUE ]; then
reliant_error "reliant_security_check_overlay: mountpoint for overlay root on $1 not found"
exit $RELIANT_SECURITY_FAIL
else
exit $RELIANT_OK
fi
}
# Indicate that the mountpoint has been found
exit 255
done
status=$?
# Check the subshell return code
case "$status" in
0)
# Not found
reliant_error "reliant_security_check_overlay: mountpoint $1 not found"
return $RELIANT_FAIL
;;
255)
# Found
return $RELIANT_OK
;;
*)
# Other issues
reliant_error "reliant_security_check_overlay: mountpoint $1 verification failed"
return $status
;;
esac
# Forward from subshell
return $?
}
# Checksum verification
reliant_security_check_devices() {
IFS=$'\n'
for device in $(lsblk -rno name); do
device_path="/dev/$device"
for device_path in $(lsblk -rnpo name); do
device="${device_path##*/}"
# Check if it is a valid block device
if [ ! -b "$device_path" ]; then return $RELIANT_BUG; fi
@ -214,6 +215,7 @@ reliant_security_check_devices() {
# User-specified devices will be excluded
should_skip=$RELIANT_FALSE
IFS=' '
for skip_device in $RELIANT_SKIP_CHECKSUM; do
if [ "$skip_device" = "$device_path" ]; then
should_skip=$RELIANT_TRUE
@ -232,7 +234,7 @@ reliant_security_check_devices() {
# Inside initramfs, use Plymouth, otherwise, use read
prompt="$device_path matches $hash? [Y/N]"
if [ $RELIANT_INITRAMFS -eq $RELIANT_TRUE ]; then
if [ "$RELIANT_INITRAMFS" -eq $RELIANT_TRUE ]; then
REPLY=$(plymouth ask-question --prompt="$prompt")
else
read -r -p "$prompt: "
@ -244,6 +246,9 @@ reliant_security_check_devices() {
return $RELIANT_SECURITY_FAIL
fi
done
# Forward from subshell
return $?
}
# Main function
@ -272,7 +277,7 @@ main() {
reliant_security_check_network || status_network=$?
reliant_security_check_filesystems || status_filesystems=$?
reliant_security_check_overlay "$1" || status_overlay=$?
reliant_security_check_devices || status_devices=$?
reliant_security_check_devices || status_devices=$?
# Print the report
echo "[REPORT]"

View file

@ -106,7 +106,7 @@ def parse_qubes_xml(target_pools, qubes_xml):
for domain in root.find('domains'):
volume_config = domain.find('volume-config')
if volume_config is None:
continue
volume_config = []
# Detect sys-net and sys-whonix
# TODO: use reliant.conf RELIANT_RW_DOMAINS
@ -118,8 +118,6 @@ def parse_qubes_xml(target_pools, qubes_xml):
# Check VM type
if domain.get('class') == 'AdminVM':
# dom0
# Disable update checking
features = domain.find('features')
for feature in features:
@ -127,6 +125,9 @@ def parse_qubes_xml(target_pools, qubes_xml):
features.remove(feature)
ElementTree.SubElement(features, 'feature', name='config.default.qubes-update-check').text = ''
# dom0 does not have volumes, so add it immediately
domains['varlibqubes'].append(domain)
else:
# Not dom0, qube ID must be randomized
qid = random.randint(1, qubes.config.max_qid)