2017-04-17 14:23:59 -04:00
|
|
|
#!/bin/sh
|
|
|
|
|
2017-05-09 06:48:12 -04:00
|
|
|
## Protect startup of Qubes VMs from /rw scripts ##
|
|
|
|
## https://github.com/tasket/Qubes-VM-hardening ##
|
|
|
|
|
|
|
|
|
|
|
|
# Source Qubes library.
|
|
|
|
. /usr/lib/qubes/init/functions
|
2017-04-20 19:33:44 -04:00
|
|
|
|
2017-05-12 05:47:53 -04:00
|
|
|
# Define sh, bash, X and desktop init scripts in /home/user
|
2017-04-17 14:23:59 -04:00
|
|
|
# to be protected
|
|
|
|
chfiles=".bashrc .bash_profile .bash_login .bash_logout .profile \
|
|
|
|
.xprofile .xinitrc .xserverrc .xsession"
|
2018-02-20 17:40:29 -05:00
|
|
|
chdirs="bin .local/bin .config/autostart .config/plasma-workspace/env \
|
2017-05-13 15:00:13 -04:00
|
|
|
.config/plasma-workspace/shutdown .config/autostart-scripts"
|
2017-05-12 05:47:53 -04:00
|
|
|
vmname=`qubesdb-read /name`
|
|
|
|
rw=/mnt/rwtmp
|
2017-04-17 14:23:59 -04:00
|
|
|
|
2017-05-13 15:00:13 -04:00
|
|
|
# Function: Make user scripts immutable.
|
2017-05-09 06:48:12 -04:00
|
|
|
make_immutable() {
|
2017-05-13 15:00:13 -04:00
|
|
|
#initialize_home $rw/home ifneeded
|
2017-05-09 06:48:12 -04:00
|
|
|
cd $rw/home/user
|
|
|
|
mkdir -p $chdirs
|
|
|
|
touch $chfiles
|
|
|
|
chattr -R -f +i $chfiles $chdirs
|
2017-05-13 15:00:13 -04:00
|
|
|
cd /root
|
2018-02-20 17:40:29 -05:00
|
|
|
#touch $rw/home/user/FIXED #debug
|
2017-05-09 06:48:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
# Mount private volume in temp location
|
2017-04-20 19:33:44 -04:00
|
|
|
mkdir -p $rw
|
|
|
|
if [ -e /dev/xvdb ] && mount /dev/xvdb $rw ; then
|
2017-05-09 06:48:12 -04:00
|
|
|
echo Good rw mount.
|
2017-04-17 14:23:59 -04:00
|
|
|
else
|
2017-05-12 05:47:53 -04:00
|
|
|
echo Mount failed!
|
|
|
|
xterm -hold -display :0 -title "VM PROTECTION: MOUNT FAILED!" \
|
|
|
|
-e "bash -i"
|
|
|
|
exit 1
|
2017-04-17 14:23:59 -04:00
|
|
|
fi
|
2018-03-29 02:57:06 -04:00
|
|
|
if qsvc vm-boot-protect-cli; then
|
2017-05-13 15:00:13 -04:00
|
|
|
xterm -hold -display :0 -title "VM PROTECTION: SERVICE PROMPT" \
|
|
|
|
-e "echo Private volume is mounted at $rw; bash -i"
|
|
|
|
fi
|
|
|
|
|
2017-04-17 14:23:59 -04:00
|
|
|
|
2017-05-09 06:48:12 -04:00
|
|
|
# Protection measures for /rw dirs:
|
2018-03-29 02:57:06 -04:00
|
|
|
# Activated by presence of vm-boot-protect-root Qubes service.
|
2017-05-12 05:47:53 -04:00
|
|
|
# * Hashes in vms/vms.all.SHA and vms/$vmname.SHA files will be checked.
|
2018-03-29 09:54:31 -04:00
|
|
|
# * Remove /rw root startup files - except whitelist.
|
2017-05-12 05:47:53 -04:00
|
|
|
# * Contents of vms/vms.all and vms/$vmname folders will be copied.
|
2017-04-17 14:23:59 -04:00
|
|
|
defdir="/etc/default/vms"
|
2017-05-12 05:47:53 -04:00
|
|
|
privdirs=${privdirs:-"$rw/config $rw/usrlocal $rw/bind-dirs"}
|
2017-05-09 06:48:12 -04:00
|
|
|
|
2018-03-29 02:57:06 -04:00
|
|
|
if qsvc vm-boot-protect-root && is_rwonly_persistent; then
|
2017-05-09 06:48:12 -04:00
|
|
|
|
|
|
|
# Check hashes
|
|
|
|
checkcode=0
|
2018-03-29 07:31:40 -04:00
|
|
|
echo >/tmp/vm-protect-sum-error
|
2017-05-09 06:48:12 -04:00
|
|
|
echo "File hash checks:" >/tmp/vm-protect-sum-error
|
2017-05-12 05:47:53 -04:00
|
|
|
for vmset in vms.all $vmname; do
|
2017-05-09 06:48:12 -04:00
|
|
|
if [ -f $defdir/$vmset.SHA ]; then
|
2017-05-09 19:02:54 -04:00
|
|
|
sha256sum --strict -c $defdir/$vmset.SHA >>/tmp/vm-protect-sum-error 2>&1
|
2017-05-09 06:48:12 -04:00
|
|
|
checkcode=$((checkcode+$?))
|
|
|
|
fi
|
|
|
|
done
|
2017-05-09 19:02:54 -04:00
|
|
|
cat /tmp/vm-protect-sum-error # For logging
|
2017-05-12 05:47:53 -04:00
|
|
|
|
|
|
|
# Stop system startup on checksum mismatch:
|
2017-05-09 06:48:12 -04:00
|
|
|
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"
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2017-05-09 19:02:54 -04:00
|
|
|
# Files mutable for del/copy operations
|
2017-05-09 06:48:12 -04:00
|
|
|
cd $rw/home/user
|
2017-05-12 05:47:53 -04:00
|
|
|
chattr -R -f -i $chfiles $chdirs $privdirs
|
2017-05-13 15:00:13 -04:00
|
|
|
cd /root
|
2017-05-12 05:47:53 -04:00
|
|
|
|
|
|
|
# Deactivate private.img config dirs
|
2018-03-29 09:54:31 -04:00
|
|
|
mkdir -p $rw/vm-boot-protect
|
2017-05-12 05:47:53 -04:00
|
|
|
for dir in $privdirs; do
|
2018-03-29 09:54:31 -04:00
|
|
|
bakdir=$rw/vm-boot-protect/BAK-`basename $dir`
|
|
|
|
origdir=$rw/vm-boot-protect/ORIG-`basename $dir`
|
2018-03-29 07:22:22 -04:00
|
|
|
if [ -d $bakdir ] && [ ! -d $origdir ]; then
|
|
|
|
mv $bakdir $origdir
|
2018-01-25 07:46:33 -05:00
|
|
|
fi
|
2017-05-13 15:00:13 -04:00
|
|
|
rm -rf $bakdir
|
|
|
|
mv $dir $bakdir
|
2017-05-09 19:02:54 -04:00
|
|
|
done
|
2017-05-12 05:47:53 -04:00
|
|
|
mkdir -p $privdirs
|
|
|
|
|
|
|
|
for vmset in vms.all $vmname; do
|
|
|
|
|
|
|
|
# Process whitelists...
|
2017-05-13 15:00:13 -04:00
|
|
|
cat $defdir/$vmset.whitelist \
|
|
|
|
| while read wlfile; do
|
2017-05-12 05:47:53 -04:00
|
|
|
# Must begin with '/rw/'
|
|
|
|
if echo $wlfile |grep -q "^\/rw\/"; then #Was [ $wlfile =~ ^\/rw\/ ];
|
2018-03-29 09:54:31 -04:00
|
|
|
srcfile="`echo $wlfile |sed -r \"s|^/rw/(.+)$|$rw/vm-boot-protect/BAK-\1|\"`"
|
2017-05-13 15:00:13 -04:00
|
|
|
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"
|
2017-05-12 05:47:53 -04:00
|
|
|
else
|
2017-05-13 15:00:13 -04:00
|
|
|
echo "Whitelist cp $srcfile"
|
|
|
|
cp -a --link "$srcfile" "$dstdir"
|
2017-05-12 05:47:53 -04:00
|
|
|
fi
|
2017-05-13 15:00:13 -04:00
|
|
|
elif [ -n "$wlfile" ]; then
|
2017-05-12 05:47:53 -04:00
|
|
|
echo "Whitelist path must begin with /rw/."
|
|
|
|
fi
|
2017-05-13 15:00:13 -04:00
|
|
|
done
|
2017-05-09 06:48:12 -04:00
|
|
|
|
2017-05-12 05:47:53 -04:00
|
|
|
# Copy default files...
|
|
|
|
if [ -d $defdir/$vmset/rw ]; then
|
2018-03-29 09:54:31 -04:00
|
|
|
cp -af $defdir/$vmset/rw/* $rw
|
2017-05-09 19:02:54 -04:00
|
|
|
fi
|
2018-03-29 07:22:22 -04:00
|
|
|
|
2017-05-09 06:48:12 -04:00
|
|
|
done
|
|
|
|
|
2018-03-29 07:31:40 -04:00
|
|
|
# Keep configs invisible at runtime...
|
|
|
|
rm -rf $defdir/*
|
|
|
|
|
2017-05-09 06:48:12 -04:00
|
|
|
fi
|
|
|
|
|
|
|
|
make_immutable
|
2017-05-13 15:00:13 -04:00
|
|
|
umount $rw
|
2017-05-09 06:48:12 -04:00
|
|
|
exit 0
|