diff --git a/README.md b/README.md index b3c908d..1dc356a 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,6 @@ Due to potential security implications of arbitrary code execution (firewall.rul - `systemd.volatile=overlay` controls the switch between Protected Mode (when present) and Maintenance Mode (when omitted) - `reliant.e2fsck` runs `e2fsck -p` on every volume before mount to avoid needing an extra reboot in case of accidental data corruption -- `reliant.profile` mounts the upperdir and workdir of OverlayFS in an accessible location under /run/reliant for debugging purposes - `reliant.dvl=VOLUME_ID` limits the amount of volumes displayed in Qubes app menu, manager, and other places, useful for when you want to avoid showing your hidden qubes in public - Displayed volume limit does **NOT** provide plausible deniability or actual device inspection diff --git a/dracut/99reliant/module-setup.sh b/dracut/99reliant/module-setup.sh index 5a7b29b..3b6c636 100755 --- a/dracut/99reliant/module-setup.sh +++ b/dracut/99reliant/module-setup.sh @@ -33,11 +33,17 @@ install() { inst_script /usr/local/sbin/surgeon-suture inst_script /usr/local/sbin/reliant-mount inst_script /usr/local/sbin/reliant-hash + inst_script /usr/local/sbin/reliant-seal inst /etc/reliant.conf # Other binaries - inst_multiple dmesg lsblk blockdev mount dd wc sed sleep md5sum find modprobe cut grep mkdir rm tail + inst_multiple dmesg lsblk blockdev mount dd wc sed sort sleep md5sum find modprobe cut grep mkdir rm tail + # Optional profiling + if [ "$RELIANT_PROFILING" = "true" ]; then + inst /usr/lib/systemd/systemd-volatile-root.reliant-profiling /usr/lib/systemd/systemd-volatile-root + fi + return 0 } diff --git a/install.sh b/install.sh index d82db3d..0d3b438 100755 --- a/install.sh +++ b/install.sh @@ -12,6 +12,7 @@ if [ ! "$HOSTNAME" = "dom0" ]; then fi # Set up the defaults +: "${RELIANT_PROFILING=false}" : "${RELIANT_PARANOID=false}" : "${RELIANT_BIN_DIR:=/usr/local/bin}" : "${RELIANT_SBIN_DIR:=/usr/local/sbin}" @@ -54,6 +55,14 @@ case "$RELIANT_PARANOID" in exit 1 ;; esac +# RELIANT_PROFILING must be a boolean value +case "$RELIANT_PROFILING" in + "true") ;; + "false") ;; + *) echo "[ERROR]: RELIANT_PROFILING: $RELIANT_PROFILING is not a valid boolean value" + exit 1 ;; +esac + # RELIANT_SPARSE_SAMPLES must be an integer if ! [ "$RELIANT_SPARSE_SAMPLES" -eq "$RELIANT_SPARSE_SAMPLES" ] 2>/dev/null; then echo "[ERROR]: RELIANT_SPARSE_SAMPLES: $RELIANT_SPARSE_SAMPLES is not a valid integer" @@ -114,6 +123,7 @@ reliant_install_sbin tools/surgeon-dissect surgeon-dissect 0744 root root reliant_install_sbin tools/reliant-security reliant-security 0744 root root reliant_install_sbin tools/reliant-snapshot-rw reliant-snapshot-rw 0744 root root reliant_install_bin tools/reliant-print-config reliant-print-config 0755 root root +reliant_install_sbin tools/reliant-profiling-patch-systemd reliant-profiling-patch-systemd 0744 root root # reliant-system/dracut reliant_install_dracut dracut/99reliant/module-setup.sh module-setup.sh 0744 root root @@ -162,12 +172,18 @@ systemctl enable shufflecake-close.service # reliant-system/tools surgeon-dissect -t varlibqubes reliant-snapshot-rw +if [ "$RELIANT_PROFILING" = "true" ]; then + reliant-profiling-patch-systemd +fi # reliant-system/qubes-sflc depmod -a "$RELIANT_KERNEL_VERSION" # reliant-system/dracut dracut --force --regenerate-all +if [ "$RELIANT_PROFILING" = "true" ]; then + RELIANT_PROFILING=true dracut --force "/boot/initramfs-$RELIANT_KERNEL_VERSION.reliant-profiling.img" +fi # Report successful installation echo "[INFO]: Installation complete. Reboot to enter Protected Mode." diff --git a/tools/reliant-mount b/tools/reliant-mount index ffd0e43..08b2860 100755 --- a/tools/reliant-mount +++ b/tools/reliant-mount @@ -34,7 +34,7 @@ while true; do done # Check for the displayed volume limit in commandline arguments -# This is only useful when booting in public to hide deniable qubes +# This is useful when booting in public to hide deniable qubes from the menu dvl_required=$RELIANT_FALSE for argument in $(cat /proc/cmdline); do if [[ "$argument" == reliant.dvl=* ]]; then @@ -44,7 +44,7 @@ for argument in $(cat /proc/cmdline); do done # Set the displayed volume limit -if [ -n "$dvl_id" ]; then +if [ $dvl_required -eq $RELIANT_TRUE ]; then dvl_device="/dev/mapper/sflc_0_$dvl_id" # Notify the user so they know the limit has been detected @@ -58,7 +58,7 @@ if [ -n "$dvl_id" ]; then dvl_device="/dev/mapper/sflc_0_$dvl_id" # Validate user input - if [ -b $dvl_device ]; then + if [ -b "$dvl_device" ]; then plymouth display-message --text="Limit adjusted successfully" sleep 1 plymouth hide-message --text="Limit adjusted successfully" @@ -75,10 +75,10 @@ mkdir -m 750 /run/shufflecake reliant_e2fsck=$(grep -q reliant.e2fsck /proc/cmdline) # Mount each volume -find /dev/mapper -maxdepth 1 -name 'sflc_0_*' | while read -r device; do +find /dev/mapper -maxdepth 1 -name 'sflc_0_*' | sort | while read -r device; do # IMPORTANT: Seal it blockdev --setro "$device" || exit 1 - + # Determine the name and mountpoint name="${device##*/}" mountpoint="/run/shufflecake/$name" @@ -93,7 +93,7 @@ find /dev/mapper -maxdepth 1 -name 'sflc_0_*' | while read -r device; do mount -o ro,noatime,nodiratime "$device" "$mountpoint" &> /dev/null || true # Allow it to silently fail in case there's no filesystem or it is corrupted # Apply the displayed volume limit if required - if [ $dvl_required = $RELIANT_TRUE ] && [ "$device" = "$dvl_device" ]; then + if [ $dvl_required -eq $RELIANT_TRUE ] && [ "$device" = "$dvl_device" ]; then break fi done @@ -105,17 +105,3 @@ for path in '/sysroot/var/lib/qubes/appvms/'*; do name="${path##*/}" mkdir -m 750 "/run/volatile/appvms/$name" done - -# Check if we need to set up profiling -if grep -q reliant.profile /proc/cmdline; then - mkdir -m 750 /run/reliant - mkdir -m 750 /run/reliant/profile - - # Upperdir - mkdir -m 750 /run/reliant/profile/upper - mount --bind /run/systemd/overlay-sysroot/upper /run/reliant/profile/upper - - # Workdir - mkdir -m 750 /run/reliant/profile/work - mount --bind /run/systemd/overlay-sysroot/work /run/reliant/profile/work -fi diff --git a/tools/reliant-profiling-patch-systemd b/tools/reliant-profiling-patch-systemd new file mode 100644 index 0000000..3260c29 --- /dev/null +++ b/tools/reliant-profiling-patch-systemd @@ -0,0 +1,24 @@ +#!/usr/bin/sh + +# Create a new file to be patched +binary=/usr/lib/systemd/systemd-volatile-root +target=/usr/lib/systemd/systemd-volatile-root.reliant-profiling +cp $binary $target + +# We must NOP calls to umount and rmdir +hex_offsets=$(objdump -d "$binary" | grep -E 'call.*(umount|rmdir)' | awk '{ print $1 }' | tr -d ':') +for hex_offset in $hex_offsets; do + dec_offset=$(perl -le "print hex(\"$hex_offset\")") + printf '\x90\x90\x90\x90\x90' | dd of="$target" bs=1 seek=$dec_offset conv=notrunc +done + +# Verify the patch has succeeded +for hex_offset in $hex_offsets; do + echo -n "$hex_offset: " + opcode=$(objdump -d "$target" | grep $hex_offset | awk '{ print $3 }') + if [ $opcode -eq 90 ]; then + echo "OK" + else + echo "FAIL" + fi +done diff --git a/tools/reliant-unseal b/tools/reliant-unseal index 3403788..4481ba3 100755 --- a/tools/reliant-unseal +++ b/tools/reliant-unseal @@ -34,13 +34,18 @@ echo "Done." # Check if we were given a qube list allowed_qubes="${*:2}" +if [ -z "$allowed_qubes" ]; then + allowed_only=0 +else + allowed_only=1 +fi echo "Creating links... " for appvm in "/run/shufflecake/$name/appvms/"*; do qube="${appvm##*/}" # Filter if user provided a list of qubes - if [ ! -z "$allowed_qubes" ]; then + if [ $allowed_only -eq 1 ]; then allowed=0 for allowed_qube in $allowed_qubes; do if [ "$qube" = "$allowed_qube" ]; then @@ -64,8 +69,13 @@ for appvm in "/run/shufflecake/$name/appvms/"*; do # App menus su user -c "qvm-start $qube" &>/dev/null || true su user -c "qvm-sync-appmenus $qube" &>/dev/null || true - su user -c "qvm-shutdown $qube" &>/dev/null || true + # If we have a list of allowed qubes, the user probably wants to run them anyway + # Otherwise, shut them down + if [ $allowed_only -eq 0 ]; then + su user -c "qvm-shutdown $qube" &>/dev/null || true + fi + # Firewall rules if [ -f "$appvm/firewall.rules" ]; then echo "Found firewall.rules. Approve?"