Qubes-VM-hardening/vm-boot-protect.sh

173 lines
5.0 KiB
Bash
Raw Normal View History

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-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"
2018-04-02 10:55:55 -04:00
2017-05-12 05:47:53 -04:00
vmname=`qubesdb-read /name`
rw=/mnt/rwtmp
2018-04-02 10:55:55 -04:00
errlog=/var/run/vm-protect-error
2018-04-03 11:01:31 -04:00
defdir=/etc/default/vms
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
}
2018-04-02 10:55:55 -04:00
# Start rescue shell then exit/fail
abort_startup() {
echo "$1" >>$errlog
cat $errlog
umount /dev/xvdb
mv -f /dev/xvdb /dev/badxvdb
mount -o ro /dev/badxvdb $rw
truncate --size=500M /root/dev-xvdb
loop=`losetup --find --show /root/dev-xvdb`
mv -f $loop /dev/xvdb
cat /etc/bashrc /etc/bash.bashrc >/etc/bashrc-insert
echo "echo '** VM-BOOT-PROTECT SERVICE SHELL'" >/etc/bashrc
echo "echo '** Private volume is located at' $rw" >>/etc/bashrc
echo "cat $errlog" >>/etc/bashrc
echo ". /etc/bashrc-insert" >>/etc/bashrc
ln -f /etc/bashrc /etc/bash.bashrc
echo '/usr/bin/nohup /usr/bin/xterm /bin/bash 0<&- &>/dev/null &' \
>/etc/X11/Xsession.d/98rescue
2017-05-12 05:47:53 -04:00
exit 1
2018-04-02 10:55:55 -04:00
}
# Don't bother with root protections in template or standalone
if ! is_rwonly_persistent; then
### make_immutable
exit 0
2017-04-17 14:23:59 -04:00
fi
2018-04-02 10:55:55 -04:00
echo >$errlog # Clear
2018-03-29 02:57:06 -04:00
if qsvc vm-boot-protect-cli; then
2018-04-02 10:55:55 -04:00
abort_startup "CLI requested."
fi
# Mount private volume in temp location
mkdir -p $rw
if [ -e /dev/xvdb ] && mount -o ro /dev/xvdb $rw ; then
echo "Good read-only mount."
else
abort_startup "Mount failed!"
2017-05-13 15:00:13 -04:00
fi
2017-04-17 14:23:59 -04:00
2018-04-02 10:55:55 -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-04-02 10:55:55 -04:00
# * Remove /rw root startup files (config, usrlocal, bind-dirs).
2017-05-12 05:47:53 -04:00
# * Contents of vms/vms.all and vms/$vmname folders will be copied.
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
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
2018-04-02 10:55:55 -04:00
sha256sum --strict -c $defdir/$vmset.SHA >>$errlog 2>&1
2017-05-09 06:48:12 -04:00
checkcode=$((checkcode+$?))
fi
done
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
2018-04-02 10:55:55 -04:00
abort_startup "Hash check failed!"
fi
# Begin write operations
if [ -e /dev/xvdb ] && mount -o remount,rw /dev/xvdb $rw ; then
echo Good rw remount.
else
abort_startup "Remount failed!"
2017-05-09 06:48:12 -04:00
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
2018-04-02 10:55:55 -04:00
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-04-02 10:55:55 -04:00
echo "Deactivate $dir"
bakdir=`dirname $dir`/vm-boot-protect/BAK-`basename $dir`
origdir=`dirname $dir`/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-04-02 10:55:55 -04:00
srcfile="`echo $wlfile |sed -r \"s|^/rw/(.+)$|$rw/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
2018-04-02 10:55:55 -04:00
echo "Whitelist entry not present in filesystem:"
echo "$srcfile"
2017-05-13 15:00:13 -04:00
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
2018-04-02 10:55:55 -04:00
echo "Whitelist path must begin with /rw/. Skipped."
2017-05-12 05:47:53 -04:00
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-04-02 10:55:55 -04:00
echo "Copy files from $defdir/$vmset/rw"
2018-03-29 09:54:31 -04:00
cp -af $defdir/$vmset/rw/* $rw
2017-05-09 06:48:12 -04:00
done
2018-03-29 07:31:40 -04:00
# Keep configs invisible at runtime...
2018-04-03 11:01:31 -04:00
rm -rf "$defdir"
2018-03-29 07:31:40 -04:00
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