From c9f2f70964ed00bbf7953f031e01980bdddf6324 Mon Sep 17 00:00:00 2001 From: tasket Date: Mon, 17 Apr 2017 14:21:07 -0400 Subject: [PATCH 01/17] Create vm-sudo-protect.service --- lib/systemd/system/vm-sudo-protect.service | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 lib/systemd/system/vm-sudo-protect.service diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service new file mode 100644 index 0000000..5fdaf93 --- /dev/null +++ b/lib/systemd/system/vm-sudo-protect.service @@ -0,0 +1,12 @@ +[Unit] +Description=Script protections to enhance vm-sudo +After=qubes-db.service +Before=qubes-mount-dirs.service + +[Service] +Type=oneshot +RemainAfterExit=no +ExecStart=/usr/lib/qubes/init/vm-sudo-protect.sh + +[Install] +WantedBy=multi-user.target From 8cb3f24acba6ff7e26fa003e5d85264f7b6355ff Mon Sep 17 00:00:00 2001 From: tasket Date: Mon, 17 Apr 2017 14:23:59 -0400 Subject: [PATCH 02/17] Create vm-sudo-protect.sh --- usr/lib/qubes/init/vm-sudo-protect.sh | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 usr/lib/qubes/init/vm-sudo-protect.sh diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh new file mode 100644 index 0000000..93f64a4 --- /dev/null +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +# Define sh, bash, X and desktop init scripts +# to be protected +chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ +.xprofile .xinitrc .xserverrc .xsession" +chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ +.config/autostart-scripts" + +mkdir -p /rw +if [ -e /dev/xvdb ] && mount /rw ; then + echo Good rw mount. +else + exit 0 +fi + +# Experimental: Remove /rw root startup files and copy defaults. +# Activated by presence of /etc/defaults/vms/vms.all dir. +# Contents of vms/vms.all and vms/hostname will be copied. +defdir="/etc/default/vms" +rootdirs="/rw/config /rw/usrlocal /rw/bind-dirs" +if [ -d $defdir/vms.all ] && [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then + rm -rf $rootdirs + # make user scripts temporarily mutable, in case 'rw/home/user' + # files exist in defdir... + cd /rw/home/user + chattr -R -f -i $chfiles $chdirs || true + # copy.. + cp -af $defdir/vms.all/* / || true + if [ -d $defdir/$(hostname) ]; then + cp -af $defdir/$(hostname)/* / || true + fi +fi + +# Make user scripts immutable +cd /rw/home/user +mkdir -p $chdirs ||true +touch $chfiles || true +chattr -R -f +i $chfiles $chdirs || true +touch /rw/home/user/FIXED || true + +cd / +umount /rw From 8dfdc2150eed84c3016fd77c6f4fa1a54bfbc4fb Mon Sep 17 00:00:00 2001 From: tasket Date: Thu, 20 Apr 2017 19:20:25 -0400 Subject: [PATCH 03/17] Update vm-sudo-protect.service Should allow service to run without interference. Now supported as Qubes service `vm-sudo-protect`. --- lib/systemd/system/vm-sudo-protect.service | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 5fdaf93..b254c6b 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -1,7 +1,7 @@ [Unit] Description=Script protections to enhance vm-sudo -After=qubes-db.service -Before=qubes-mount-dirs.service +After=qubes-sysinit.service +ConditionPathExists=/var/run/qubes-service/vm-sudo-protect [Service] Type=oneshot @@ -9,4 +9,4 @@ RemainAfterExit=no ExecStart=/usr/lib/qubes/init/vm-sudo-protect.sh [Install] -WantedBy=multi-user.target +WantedBy=sysinit.target From b3f46e33070bbe83d46fe02e02b87e71dd2667b5 Mon Sep 17 00:00:00 2001 From: tasket Date: Thu, 20 Apr 2017 19:33:44 -0400 Subject: [PATCH 04/17] Update vm-sudo-protect.sh Avoids using fstab mountpoint and enables using `vm-sudo-protect-root` as Qubes service. --- usr/lib/qubes/init/vm-sudo-protect.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index 93f64a4..a9ad609 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -1,5 +1,8 @@ #!/bin/sh +## Protect startup of Qubes VMs from /rw scripts ## +## https://github.com/tasket/Qubes-VM-hardening ## + # Define sh, bash, X and desktop init scripts # to be protected chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ @@ -7,8 +10,9 @@ chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ .config/autostart-scripts" -mkdir -p /rw -if [ -e /dev/xvdb ] && mount /rw ; then +rw=/mnt/rwtmp +mkdir -p $rw +if [ -e /dev/xvdb ] && mount /dev/xvdb $rw ; then echo Good rw mount. else exit 0 @@ -18,12 +22,12 @@ fi # Activated by presence of /etc/defaults/vms/vms.all dir. # Contents of vms/vms.all and vms/hostname will be copied. defdir="/etc/default/vms" -rootdirs="/rw/config /rw/usrlocal /rw/bind-dirs" -if [ -d $defdir/vms.all ] && [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then +rootdirs="$rw/config $rw/usrlocal $rw/bind-dirs" +if [ -e /var/run/qubes-service/vm-sudo-protect-root ] && [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then rm -rf $rootdirs # make user scripts temporarily mutable, in case 'rw/home/user' # files exist in defdir... - cd /rw/home/user + cd $rw/home/user chattr -R -f -i $chfiles $chdirs || true # copy.. cp -af $defdir/vms.all/* / || true @@ -33,11 +37,11 @@ if [ -d $defdir/vms.all ] && [ `qubesdb-read /qubes-vm-persistence` = "rw-only" fi # Make user scripts immutable -cd /rw/home/user +cd $rw/home/user mkdir -p $chdirs ||true touch $chfiles || true chattr -R -f +i $chfiles $chdirs || true -touch /rw/home/user/FIXED || true +touch $rw/home/user/FIXED || true cd / -umount /rw +umount $rw && rmdir $rw From 11d441e41868a124dc51c479c96dfe4fb592f218 Mon Sep 17 00:00:00 2001 From: tasket Date: Thu, 20 Apr 2017 19:35:53 -0400 Subject: [PATCH 05/17] Update vm-sudo-protect.service --- lib/systemd/system/vm-sudo-protect.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index b254c6b..4d52421 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -1,7 +1,8 @@ [Unit] Description=Script protections to enhance vm-sudo After=qubes-sysinit.service -ConditionPathExists=/var/run/qubes-service/vm-sudo-protect +ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect +ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-root [Service] Type=oneshot From 066ec6e67dc4b628d493b63d8ddadf7f6acc452c Mon Sep 17 00:00:00 2001 From: tasket Date: Thu, 20 Apr 2017 19:42:06 -0400 Subject: [PATCH 06/17] Update vm-sudo-protect.sh Test for vms.all before copy --- usr/lib/qubes/init/vm-sudo-protect.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index a9ad609..a88d628 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -30,7 +30,9 @@ if [ -e /var/run/qubes-service/vm-sudo-protect-root ] && [ `qubesdb-read /qubes- cd $rw/home/user chattr -R -f -i $chfiles $chdirs || true # copy.. - cp -af $defdir/vms.all/* / || true + if [ -d $defdir/vms.all ]; then + cp -af $defdir/vms.all/* / || true + fi if [ -d $defdir/$(hostname) ]; then cp -af $defdir/$(hostname)/* / || true fi From b92423e0962ade4f7ad8e5b176fd76638e4270a3 Mon Sep 17 00:00:00 2001 From: tasket Date: Fri, 21 Apr 2017 00:17:55 -0400 Subject: [PATCH 07/17] fix comment --- usr/lib/qubes/init/vm-sudo-protect.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index a88d628..54f09ec 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -19,11 +19,13 @@ else fi # Experimental: Remove /rw root startup files and copy defaults. -# Activated by presence of /etc/defaults/vms/vms.all dir. +# Activated by presence of vm-sudo-protect-root Qubes service. # Contents of vms/vms.all and vms/hostname will be copied. defdir="/etc/default/vms" rootdirs="$rw/config $rw/usrlocal $rw/bind-dirs" -if [ -e /var/run/qubes-service/vm-sudo-protect-root ] && [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then + +if [ -e /var/run/qubes-service/vm-sudo-protect-root ] \ +&& [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then rm -rf $rootdirs # make user scripts temporarily mutable, in case 'rw/home/user' # files exist in defdir... From 99af1038a67e4f855cd45e348b3e61deaa931f92 Mon Sep 17 00:00:00 2001 From: tasket Date: Fri, 21 Apr 2017 11:26:55 -0400 Subject: [PATCH 08/17] Add parameters for Whonix Tested briefly on Whonix. Don't use 'vm-sudo-protect-root' service. --- lib/systemd/system/vm-sudo-protect.service | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 4d52421..95973d8 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -1,8 +1,10 @@ [Unit] Description=Script protections to enhance vm-sudo After=qubes-sysinit.service +Before=qubes-mount-dirs.service ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-root +DefaultDependencies=false [Service] Type=oneshot From 9c720c15cf55e7c9748aea4a876b7d557f2c7e8d Mon Sep 17 00:00:00 2001 From: tasket Date: Fri, 21 Apr 2017 12:03:15 -0400 Subject: [PATCH 09/17] brief systemd instructions --- README.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7839e76..b1acb9a 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,26 @@ # Qubes-VM-hardening Enhancing Qubes VM security and privacy -## rc.local: Protect sh, bash and GUI init files - ### Pre-requisites: Enabling authentication for sudo (see link below for Qubes doc). + +--- + + +## vm-sudo-protect.service + * Protect /home script files + * Remove /rw scripts at VM start + +## Testing systemd version... +Install the two files `vm-sudo-protect.sh` and `vm-sudo-protect.service` into template then use `systemctl` to enable the service. + +Activate by specifying as a Qubes service for each VM; There are two levels... + 1. `vm-sudo-protect` - similar to the rc.local script. Protects scripts within /home and may be used with wide array of VMs including standalone, netVMs and Whonix. + 2. `vm-sudo-protect-root` - new feature which **erases** /rw/config, /rw/usrlocal and /rw/bind-dirs. Use with caution! This feature can also replace files on a global or per-VM basis... see script for details. Not recommended for standalone or VMs that rely on /rw root dirs such as netVMs or Whonix. + +--- + +## rc.local (old version) ### Description: Placed in /etc/rc.local (or equivalent) of a template VM, this makes the shell init files immutable so PATH and alias cannot be used to hijack commands like su and sudo, nor can impostor apps autostart whenever a VM starts. I combed the dash and bash docs -- as well as Gnome, KDE, Xfce and X11 docs -- to address all the user-writable startup files that apply. Feel free to comment or create an issue if you see an omission or other problem. From 4e68dfab79fb56792af436e3a06b92fb1d4b0188 Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Tue, 9 May 2017 06:48:12 -0400 Subject: [PATCH 10/17] In progress, broken. --- lib/systemd/system/vm-sudo-protect.service | 2 + usr/lib/qubes/init/vm-sudo-protect.sh | 108 +++++++++++++++------ 2 files changed, 83 insertions(+), 27 deletions(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 95973d8..401abd1 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -5,6 +5,8 @@ Before=qubes-mount-dirs.service ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-root DefaultDependencies=false +#OnFailure=shutdown.target +#OnFailureJobMode=replace-irreversibly [Service] Type=oneshot diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index 54f09ec..ad48ae1 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -1,7 +1,11 @@ #!/bin/sh -## Protect startup of Qubes VMs from /rw scripts ## -## https://github.com/tasket/Qubes-VM-hardening ## +## Protect startup of Qubes VMs from /rw scripts ## +## https://github.com/tasket/Qubes-VM-hardening ## + + +# Source Qubes library. +. /usr/lib/qubes/init/functions # Define sh, bash, X and desktop init scripts # to be protected @@ -10,42 +14,92 @@ chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ .config/autostart-scripts" +# Make user scripts immutable: +make_immutable() { + cd $rw/home/user + mkdir -p $chdirs + touch $chfiles + chattr -R -f +i $chfiles $chdirs + touch $rw/home/user/FIXED +} + +# Mount private volume in temp location rw=/mnt/rwtmp mkdir -p $rw if [ -e /dev/xvdb ] && mount /dev/xvdb $rw ; then - echo Good rw mount. + echo Good rw mount. else - exit 0 + exit 0 fi -# Experimental: Remove /rw root startup files and copy defaults. +# Protection measures for /rw dirs: # Activated by presence of vm-sudo-protect-root Qubes service. -# Contents of vms/vms.all and vms/hostname will be copied. +# * Hashes in vms/vms.all.SHA and vms/$HOSTNAME.SHA files will be checked. +# * Remove /rw root startup files. +# * Contents of vms/vms.all and vms/$HOSTNAME folders will be copied. defdir="/etc/default/vms" rootdirs="$rw/config $rw/usrlocal $rw/bind-dirs" +HOSTNAME=`hostname` + +if qsvc vm-sudo-protect-root && is_rwonly_persistent; then + + # Check hashes + checkcode=0 + echo "File hash checks:" >/tmp/vm-protect-sum-error + for vmset in vms.all $HOSTNAME; do + if [ -f $defdir/$vmset.SHA ]; then + sha256sum --strict -c $defdir/$vmset.SHA &>>/tmp/vm-protect-sum-error + checkcode=$((checkcode+$?)) + fi + done + # Stop system startup if checksum mismatched + if [ $checkcode != 0 ]; then + cat /tmp/vm-protect-sum-error # For logging + xterm -hold -display :0 -title "VM PROTECTION: CHECKSUM MISMATCH!" \ +-e "cat /tmp/vm-protect-sum-error; echo Private volume is mounted at $rw; bash -i" + exit 1 + fi + + + + + # Make user scripts temporarily mutable, in case 'rw/home/user' + # files exist in defdir -- Copy default files + cd $rw/home/user + chattr -R -f -i $chfiles $chdirs + + # Deactivate config dirs + for dir in $rootdirs; do + if [ -d $dir ]; then + chattr -R -f -i $dir + cp -a --link $dir $dir-BAK +# rm -rf $dir-BAK +# mv $dir $dir-BAK + find $dir -type f | cat - $defdir/$HOSTNAME.whitelist $defdir/vms.all.whitelist \ +| sed -r "s|^\ */rw(.+)\ *$|$rw\1|" | sort | uniq -u | xargs -I fpath rm -f "fpath" + fi + + for vmset in vms.all $HOSTNAME; do + # Process whitelists -- FIX FIX FIX + while false; do +# while read srcfile; do + if [[ $srcfile =~ ^$dir\/ ]]; then + cp -a --link --parents `sed -r "s|^/rw/|$rw/BAK-|" <<<$srcfile` / + else + echo "Cannot use relative or non-rw whitelist path." + fi + done <$defdir/$vmset.whitelist + + # Copy default files + if [ -d $defdir/$vmset ]; then + cp -af $defdir/$vmset/* / + fi + done + done -if [ -e /var/run/qubes-service/vm-sudo-protect-root ] \ -&& [ `qubesdb-read /qubes-vm-persistence` = "rw-only" ]; then - rm -rf $rootdirs - # make user scripts temporarily mutable, in case 'rw/home/user' - # files exist in defdir... - cd $rw/home/user - chattr -R -f -i $chfiles $chdirs || true - # copy.. - if [ -d $defdir/vms.all ]; then - cp -af $defdir/vms.all/* / || true - fi - if [ -d $defdir/$(hostname) ]; then - cp -af $defdir/$(hostname)/* / || true - fi fi -# Make user scripts immutable -cd $rw/home/user -mkdir -p $chdirs ||true -touch $chfiles || true -chattr -R -f +i $chfiles $chdirs || true -touch $rw/home/user/FIXED || true - +make_immutable cd / umount $rw && rmdir $rw +exit 0 From e54a10ea51856dae352f5b4b5f377d965c47f7ef Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Tue, 9 May 2017 19:02:54 -0400 Subject: [PATCH 11/17] Fixes for testing. --- lib/systemd/system/vm-sudo-protect.service | 4 +- usr/lib/qubes/init/vm-sudo-protect.sh | 48 ++++++++-------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 401abd1..099454e 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -5,8 +5,8 @@ Before=qubes-mount-dirs.service ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-root DefaultDependencies=false -#OnFailure=shutdown.target -#OnFailureJobMode=replace-irreversibly +OnFailure=shutdown.target +OnFailureJobMode=replace-irreversibly [Service] Type=oneshot diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index ad48ae1..c5220be 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -20,7 +20,7 @@ make_immutable() { mkdir -p $chdirs touch $chfiles chattr -R -f +i $chfiles $chdirs - touch $rw/home/user/FIXED + touch $rw/home/user/FIXED #debug } # Mount private volume in temp location @@ -48,53 +48,39 @@ if qsvc vm-sudo-protect-root && is_rwonly_persistent; then echo "File hash checks:" >/tmp/vm-protect-sum-error for vmset in vms.all $HOSTNAME; do if [ -f $defdir/$vmset.SHA ]; then - sha256sum --strict -c $defdir/$vmset.SHA &>>/tmp/vm-protect-sum-error + sha256sum --strict -c $defdir/$vmset.SHA >>/tmp/vm-protect-sum-error 2>&1 checkcode=$((checkcode+$?)) fi done + cat /tmp/vm-protect-sum-error # For logging # Stop system startup if checksum mismatched if [ $checkcode != 0 ]; then - cat /tmp/vm-protect-sum-error # For logging xterm -hold -display :0 -title "VM PROTECTION: CHECKSUM MISMATCH!" \ -e "cat /tmp/vm-protect-sum-error; echo Private volume is mounted at $rw; bash -i" exit 1 fi - - - # Make user scripts temporarily mutable, in case 'rw/home/user' - # files exist in defdir -- Copy default files + # Files mutable for del/copy operations cd $rw/home/user - chattr -R -f -i $chfiles $chdirs + chattr -R -f -i $chfiles $chdirs $rootdirs # Deactivate config dirs for dir in $rootdirs; do if [ -d $dir ]; then - chattr -R -f -i $dir - cp -a --link $dir $dir-BAK -# rm -rf $dir-BAK -# mv $dir $dir-BAK - find $dir -type f | cat - $defdir/$HOSTNAME.whitelist $defdir/vms.all.whitelist \ -| sed -r "s|^\ */rw(.+)\ *$|$rw\1|" | sort | uniq -u | xargs -I fpath rm -f "fpath" - fi - - for vmset in vms.all $HOSTNAME; do - # Process whitelists -- FIX FIX FIX - while false; do -# while read srcfile; do - if [[ $srcfile =~ ^$dir\/ ]]; then - cp -a --link --parents `sed -r "s|^/rw/|$rw/BAK-|" <<<$srcfile` / - else - echo "Cannot use relative or non-rw whitelist path." - fi - done <$defdir/$vmset.whitelist - - # Copy default files - if [ -d $defdir/$vmset ]; then - cp -af $defdir/$vmset/* / + if [ ! -d $dir-BAK ]; then + cp -a --link $dir $dir-BAK fi - done + find $dir/* -depth | cat - $defdir/$HOSTNAME.whitelist $defdir/vms.all.whitelist \ +| sed -r "s|^\ */rw(.+)\ *$|$rw\1|" | sort | uniq -u | xargs -I fpath rm -fd 'fpath' + fi + done + + # Copy default files + for vmset in vms.all $HOSTNAME; do + if [ -d $defdir/$vmset ]; then + cp -af $defdir/$vmset/* / + fi done fi From 85891002cdf508f92d073eea59be25c2b3e67499 Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Tue, 9 May 2017 20:02:54 -0400 Subject: [PATCH 12/17] comment --- usr/lib/qubes/init/vm-sudo-protect.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index c5220be..7eb733f 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -66,6 +66,7 @@ if qsvc vm-sudo-protect-root && is_rwonly_persistent; then chattr -R -f -i $chfiles $chdirs $rootdirs # Deactivate config dirs + # Whitelists do *not* support pattern matching! for dir in $rootdirs; do if [ -d $dir ]; then if [ ! -d $dir-BAK ]; then From e2884850242a359d530d81aae880a352cacb08c2 Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Fri, 12 May 2017 05:47:53 -0400 Subject: [PATCH 13/17] Improved whitelist processing --- lib/systemd/system/vm-sudo-protect.service | 1 + usr/lib/qubes/init/vm-sudo-protect.sh | 67 ++++++++++++++-------- 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 099454e..6e5292e 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -11,6 +11,7 @@ OnFailureJobMode=replace-irreversibly [Service] Type=oneshot RemainAfterExit=no +#Environment="privdirs=/rw/config /rw/usrlocal /rw/bind-dirs" ExecStart=/usr/lib/qubes/init/vm-sudo-protect.sh [Install] diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index 7eb733f..e098c17 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -7,12 +7,14 @@ # Source Qubes library. . /usr/lib/qubes/init/functions -# Define sh, bash, X and desktop init scripts +# Define sh, bash, X and desktop init scripts in /home/user # to be protected chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ .xprofile .xinitrc .xserverrc .xsession" chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ .config/autostart-scripts" +vmname=`qubesdb-read /name` +rw=/mnt/rwtmp # Make user scripts immutable: make_immutable() { @@ -24,36 +26,38 @@ make_immutable() { } # Mount private volume in temp location -rw=/mnt/rwtmp mkdir -p $rw if [ -e /dev/xvdb ] && mount /dev/xvdb $rw ; then echo Good rw mount. else - exit 0 + echo Mount failed! + xterm -hold -display :0 -title "VM PROTECTION: MOUNT FAILED!" \ +-e "bash -i" + exit 1 fi # Protection measures for /rw dirs: # Activated by presence of vm-sudo-protect-root Qubes service. -# * Hashes in vms/vms.all.SHA and vms/$HOSTNAME.SHA files will be checked. -# * Remove /rw root startup files. -# * Contents of vms/vms.all and vms/$HOSTNAME folders will be copied. +# * Hashes in vms/vms.all.SHA and vms/$vmname.SHA files will be checked. +# * Remove /rw root startup files (config, usrlocal, bind-dirs). +# * Contents of vms/vms.all and vms/$vmname folders will be copied. defdir="/etc/default/vms" -rootdirs="$rw/config $rw/usrlocal $rw/bind-dirs" -HOSTNAME=`hostname` +privdirs=${privdirs:-"$rw/config $rw/usrlocal $rw/bind-dirs"} if qsvc vm-sudo-protect-root && is_rwonly_persistent; then # Check hashes checkcode=0 echo "File hash checks:" >/tmp/vm-protect-sum-error - for vmset in vms.all $HOSTNAME; do + for vmset in vms.all $vmname; do if [ -f $defdir/$vmset.SHA ]; then sha256sum --strict -c $defdir/$vmset.SHA >>/tmp/vm-protect-sum-error 2>&1 checkcode=$((checkcode+$?)) fi done cat /tmp/vm-protect-sum-error # For logging - # Stop system startup if checksum mismatched + + # Stop system startup on checksum mismatch: if [ $checkcode != 0 ]; then xterm -hold -display :0 -title "VM PROTECTION: CHECKSUM MISMATCH!" \ -e "cat /tmp/vm-protect-sum-error; echo Private volume is mounted at $rw; bash -i" @@ -63,24 +67,37 @@ if qsvc vm-sudo-protect-root && is_rwonly_persistent; then # Files mutable for del/copy operations cd $rw/home/user - chattr -R -f -i $chfiles $chdirs $rootdirs + chattr -R -f -i $chfiles $chdirs $privdirs - # Deactivate config dirs - # Whitelists do *not* support pattern matching! - for dir in $rootdirs; do - if [ -d $dir ]; then - if [ ! -d $dir-BAK ]; then - cp -a --link $dir $dir-BAK - fi - find $dir/* -depth | cat - $defdir/$HOSTNAME.whitelist $defdir/vms.all.whitelist \ -| sed -r "s|^\ */rw(.+)\ *$|$rw\1|" | sort | uniq -u | xargs -I fpath rm -fd 'fpath' - fi + # Deactivate private.img config dirs + for dir in $privdirs; do + rm -rf BAK-$dir + mv $dir BAK-$dir done + mkdir -p $privdirs - # Copy default files - for vmset in vms.all $HOSTNAME; do - if [ -d $defdir/$vmset ]; then - cp -af $defdir/$vmset/* / + for vmset in vms.all $vmname; do + + # Process whitelists... + while read wlfile; do + # Must begin with '/rw/' + if echo $wlfile |grep -q "^\/rw\/"; then #Was [ $wlfile =~ ^\/rw\/ ]; + srcfile="`sed -r \"s|^/rw/(.+)$|$rw/BAK-\1|\" <<<\"$wlfile\"`" + # For large dirs: instant mv whole dir when entry ends with '/' + if echo $wlfile |grep -q "\/$"; then #Was [ $wlfile =~ .+\/$ ]; + mkdir -p "`dirname \"$wlfile\"`" + mv "$srcfile" "`dirname \"$wlfile\"`" + else + cp -al --parents "$srcfile" / + fi + else + echo "Whitelist path must begin with /rw/." + fi + done <$defdir/$vmset.whitelist + + # Copy default files... + if [ -d $defdir/$vmset/rw ]; then + cp -af $defdir/$vmset/rw/* $rw fi done From caa901593d981c3888ec610dab88c874e6d4b22f Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Sat, 13 May 2017 15:00:13 -0400 Subject: [PATCH 14/17] Fixes, add CLI service. --- lib/systemd/system/vm-sudo-protect.service | 3 +- usr/lib/qubes/init/vm-sudo-protect.sh | 52 ++++++++++++++-------- 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/lib/systemd/system/vm-sudo-protect.service b/lib/systemd/system/vm-sudo-protect.service index 6e5292e..f632011 100644 --- a/lib/systemd/system/vm-sudo-protect.service +++ b/lib/systemd/system/vm-sudo-protect.service @@ -1,9 +1,10 @@ [Unit] -Description=Script protections to enhance vm-sudo +Description=Script protections to enhance VM security After=qubes-sysinit.service Before=qubes-mount-dirs.service ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-root +ConditionPathExists=|/var/run/qubes-service/vm-sudo-protect-cli DefaultDependencies=false OnFailure=shutdown.target OnFailureJobMode=replace-irreversibly diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index e098c17..1d5af2f 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -11,17 +11,19 @@ # to be protected chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ .xprofile .xinitrc .xserverrc .xsession" -chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ -.config/autostart-scripts" +chdirs=".config/autostart .config/plasma-workspace/env \ +.config/plasma-workspace/shutdown .config/autostart-scripts" vmname=`qubesdb-read /name` rw=/mnt/rwtmp -# Make user scripts immutable: +# Function: Make user scripts immutable. make_immutable() { + #initialize_home $rw/home ifneeded cd $rw/home/user mkdir -p $chdirs touch $chfiles chattr -R -f +i $chfiles $chdirs + cd /root touch $rw/home/user/FIXED #debug } @@ -35,6 +37,11 @@ else -e "bash -i" exit 1 fi +if qsvc vm-sudo-protect-cli; then + xterm -hold -display :0 -title "VM PROTECTION: SERVICE PROMPT" \ +-e "echo Private volume is mounted at $rw; bash -i" +fi + # Protection measures for /rw dirs: # Activated by presence of vm-sudo-protect-root Qubes service. @@ -64,46 +71,55 @@ if qsvc vm-sudo-protect-root && is_rwonly_persistent; then exit 1 fi - # Files mutable for del/copy operations cd $rw/home/user chattr -R -f -i $chfiles $chdirs $privdirs + cd /root # Deactivate private.img config dirs for dir in $privdirs; do - rm -rf BAK-$dir - mv $dir BAK-$dir + bakdir=`dirname $dir`/BAK-`basename $dir` + rm -rf $bakdir + mv $dir $bakdir done mkdir -p $privdirs for vmset in vms.all $vmname; do # Process whitelists... - while read wlfile; do + cat $defdir/$vmset.whitelist \ + | while read wlfile; do # Must begin with '/rw/' if echo $wlfile |grep -q "^\/rw\/"; then #Was [ $wlfile =~ ^\/rw\/ ]; - srcfile="`sed -r \"s|^/rw/(.+)$|$rw/BAK-\1|\" <<<\"$wlfile\"`" - # For large dirs: instant mv whole dir when entry ends with '/' - if echo $wlfile |grep -q "\/$"; then #Was [ $wlfile =~ .+\/$ ]; - mkdir -p "`dirname \"$wlfile\"`" - mv "$srcfile" "`dirname \"$wlfile\"`" + srcfile="`echo $wlfile |sed -r \"s|^/rw/(.+)$|$rw/BAK-\1|\"`" + dstfile="`echo $wlfile |sed -r \"s|^/rw/(.+)$|$rw/\1|\"`" + dstdir="`dirname \"$dstfile\"`" + if [ ! -e "$srcfile" ]; then + echo "Whitelist entry not present in filesystem." + continue + # For very large dirs: mv whole dir when entry ends with '/' + elif echo $wlfile |grep -q "\/$"; then + echo "Whitelist mv $srcfile" + mkdir -p "$dstdir" + mv "$srcfile" "$dstdir" else - cp -al --parents "$srcfile" / + echo "Whitelist cp $srcfile" + cp -a --link "$srcfile" "$dstdir" fi - else + elif [ -n "$wlfile" ]; then echo "Whitelist path must begin with /rw/." fi - done <$defdir/$vmset.whitelist + done # Copy default files... if [ -d $defdir/$vmset/rw ]; then - cp -af $defdir/$vmset/rw/* $rw + cp -af "$defdir/$vmset/rw/*" $rw fi + done fi make_immutable -cd / -umount $rw && rmdir $rw +umount $rw exit 0 From a72176c9017c097500671691018998179f7c3d74 Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Thu, 25 Jan 2018 07:46:33 -0500 Subject: [PATCH 15/17] Backup when deactivating --- usr/lib/qubes/init/vm-sudo-protect.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index 1d5af2f..91d2020 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -79,6 +79,10 @@ if qsvc vm-sudo-protect-root && is_rwonly_persistent; then # Deactivate private.img config dirs for dir in $privdirs; do bakdir=`dirname $dir`/BAK-`basename $dir` + bak2dir=`dirname $dir`/BAK2-`basename $dir` + if [ -d $bakdir ] && [ ! -d $bak2dir ]; then + mv $bakdir $bak2dir + fi rm -rf $bakdir mv $dir $bakdir done From 155023b962d67ca32bda38f7774294af5f0debdc Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Thu, 25 Jan 2018 07:49:53 -0500 Subject: [PATCH 16/17] Add bin to immutables --- usr/lib/qubes/init/vm-sudo-protect.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr/lib/qubes/init/vm-sudo-protect.sh b/usr/lib/qubes/init/vm-sudo-protect.sh index 91d2020..d895786 100644 --- a/usr/lib/qubes/init/vm-sudo-protect.sh +++ b/usr/lib/qubes/init/vm-sudo-protect.sh @@ -11,7 +11,7 @@ # to be protected chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ .xprofile .xinitrc .xserverrc .xsession" -chdirs=".config/autostart .config/plasma-workspace/env \ +chdirs="bin .config/autostart .config/plasma-workspace/env \ .config/plasma-workspace/shutdown .config/autostart-scripts" vmname=`qubesdb-read /name` rw=/mnt/rwtmp From ce04dcd77775fb8adb2f8ed64f4760f09de76f28 Mon Sep 17 00:00:00 2001 From: Christopher Laprise Date: Thu, 25 Jan 2018 08:22:59 -0500 Subject: [PATCH 17/17] Remove rc.local --- rc.local | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 rc.local diff --git a/rc.local b/rc.local deleted file mode 100644 index fc1217a..0000000 --- a/rc.local +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -e -# Debian: /etc/rc.local - - ######################################################### -## Protect sh, bash, X and desktop init scripts ## -## to prevent privilege escalation attacks ## -## and malware persistence - for Qubes Linux templates ## -chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \ -.xprofile .xinitrc .xserverrc .xsession" -chdirs=".config/autostart .config/plasma-workspace/env .config/plasma-workspace/shutdown \ -.config/autostart-scripts" - -cd /home/user -mkdir -p $chdirs ||true -touch $chfiles || true -chattr -R -f +i $chfiles $chdirs || true -#touch /home/user/FIXED || true - -# end of script -exit 0