From 56b0685aaa5a3dc6af99851f33e9028d7e57338d Mon Sep 17 00:00:00 2001 From: Jason Mehring Date: Wed, 22 Apr 2015 02:04:10 -0400 Subject: [PATCH] whonix: Added protected-files file used to prevent scripts from modifying files that need to be protected A file is created in /var/lib/qubes/protected-files. Scripts can grep this file before modifying known files to be protected and skip any modifications if the file path is within protected-files. Usage Example: if ! grep -q "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then Also cleaned up maintainer scripts removing unneeded systemd status functions and streamlined the enable/disable systemd unit files functions --- debian/qubes-core-agent.postinst | 126 +++++++++++++------------------ network/setup-ip | 13 +++- rpm_spec/core-vm.spec | 27 ++++--- vm-init.d/qubes-core | 50 ++++++------ vm-systemd/qubes-sysinit.sh | 42 ++++++----- 5 files changed, 132 insertions(+), 126 deletions(-) diff --git a/debian/qubes-core-agent.postinst b/debian/qubes-core-agent.postinst index 01da682..e4a9872 100755 --- a/debian/qubes-core-agent.postinst +++ b/debian/qubes-core-agent.postinst @@ -105,80 +105,47 @@ showIn() { fi } -setArrayAsGlobal() { - local array="$1" - local export_as="$2" - local code=$(declare -p "$array") - local replaced="${code/$array/$export_as}" - eval ${replaced/declare -/declare -g} -} - -systemdInfo() { +changeSystemdStatus() { unit=${1} - return_global_var=${2} + disable=${2-0} + + # Check if unit file is currently active (running) + systemctl is-active ${unit} > /dev/null 2>&1 && active=true || unset active - declare -A INFO=() - while read line; do - INFO[${line%%=*}]="${line##*=}" - done < <(systemctl show ${unit} 2> /dev/null) + case ${disable} in + 0) + systemctl --quiet enable ${unit} > /dev/null 2>&1 || true + ;; + 1) + if [ $active ]; then + systemctl --quiet stop ${unit} > /dev/null 2>&1 || true + fi - setArrayAsGlobal INFO $return_global_var - return ${#INFO[@]} -} - -displayFailedStatus() { - action=${1} - unit=${2} - - # Only display if there are results. In chroot environmnet there will be - # no results to 'systemctl show' command - systemdInfo ${unit} info || { - echo - echo "===================================================" - echo "FAILED: systemd ${action} ${unit}" - echo "===================================================" - echo " LoadState = ${info[LoadState]}" - echo " LoadError = ${info[LoadError]}" - echo " ActiveState = ${info[ActiveState]}" - echo " SubState = ${info[SubState]}" - echo "UnitFileState = ${info[UnitFileState]}" - echo - } -} - -# Disable systemd units -disableSystemdUnits() { - for unit in $*; do - echo "Disabling ${unit}..." - systemctl is-active ${unit} > /dev/null 2>&1 && { - systemctl stop ${unit} > /dev/null 2>&1 || displayFailedStatus stop ${unit} - } - if [ -f /lib/systemd/system/${unit} ]; then - if fgrep -q '[Install]' /lib/systemd/system/${unit}; then - systemctl disable ${unit} > /dev/null 2>&1 || displayFailedStatus disable ${unit} + if [ -f /lib/systemd/system/${unit} ]; then + if fgrep -q '[Install]' /lib/systemd/system/${unit}; then + systemctl --quiet disable ${unit} > /dev/null 2>&1 || true + else + # Forcibly disable + ln -sf /dev/null /etc/systemd/system/${unit} + fi else - echo "Masking service: ${unit}" - systemctl mask ${unit} + systemctl --quiet disable ${unit} > /dev/null 2>&1 || true fi - else - systemctl disable ${unit} > /dev/null 2>&1 || displayFailedStatus disable ${unit} - fi - done + ;; + esac } # Enable systemd units enableSystemdUnits() { for unit in $*; do - systemctl is-enabled ${unit} > /dev/null 2>&1 && { - echo "It appears ${unit} is already enabled!" - #displayFailedStatus is-enabled ${unit} - } || { - echo "Enabling: ${unit}..." - systemctl enable ${unit} > /dev/null 2>&1 || { - echo "Could not enable: ${unit}" - displayFailedStatus enable ${unit} - } - } + changeSystemdStatus ${unit} 0 || true + done +} + +# Disable systemd units +disableSystemdUnits() { + for unit in $*; do + changeSystemdStatus ${unit} 1 || true done } @@ -204,6 +171,9 @@ case "${1}" in dpkg-divert --divert /etc/init/${init}.conf.qubes-disabled --package qubes-core-agent --rename --add /etc/init/${init}.conf done + # Disable sysv init network-manager + disableSystemdUnits network-manager + # Create NetworkManager configuration if we do not have it if ! [ -e /etc/NetworkManager/NetworkManager.conf ]; then echo '[main]' > /etc/NetworkManager/NetworkManager.conf @@ -217,19 +187,27 @@ case "${1}" in rm -f /lib/firmware/updates fi + # Location of files which contains list of protected files + PROTECTED_FILE_LIST='/var/lib/qubes/protected-files' + # ensure that hostname resolves to 127.0.1.1 resp. ::1 and that /etc/hosts is # in the form expected by qubes-sysinit.sh - for ip in '127\.0\.1\.1' '::1'; do - if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then - sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts - sed -i "s/^${ip}\(\s\|$\).*$/\0 `hostname`/" /etc/hosts - else - echo "${ip//\\/} `hostname`" >> /etc/hosts - fi - done + if ! grep -q "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + for ip in '127\.0\.1\.1' '::1'; do + if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then + sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts || true + sed -i "s/^${ip}\(\s\|$\).*$/\0 `hostname`/" /etc/hosts || true + else + echo "${ip//\\/} `hostname`" >> /etc/hosts || true + fi + done + fi + # remove hostname from 127.0.0.1 line (in debian the hostname is by default # resolved to 127.0.1.1) - sed -i "/^127\.0\.0\.1\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts + if ! grep -q "^/etc/hosts$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + sed -i "/^127\.0\.0\.1\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts || true + fi chown user:user /home_volatile/user @@ -286,7 +264,7 @@ case "${1}" in rngd smartd.service \ upower.service \ irqbalance.service \ - colord.service + colord.service rm -f /etc/systemd/system/getty.target.wants/getty@tty*.service diff --git a/network/setup-ip b/network/setup-ip index 06cd651..13adef7 100755 --- a/network/setup-ip +++ b/network/setup-ip @@ -6,6 +6,9 @@ disablegw=`qubesdb-read /qubes-service/disable-default-route 2> /dev/null` disabledns=`qubesdb-read /qubes-service/disable-dns-server 2> /dev/null` +# Location of files which contains list of protected files +PROTECTED_FILE_LIST='/var/lib/qubes/protected-files' + ip=`/usr/bin/qubesdb-read /qubes-ip 2> /dev/null` if [ x$ip != x ]; then netmask=`/usr/bin/qubesdb-read /qubes-netmask` @@ -19,10 +22,12 @@ if [ x$ip != x ]; then fi /sbin/ethtool -K $INTERFACE sg off /sbin/ethtool -K $INTERFACE tx off - echo > /etc/resolv.conf - if [ "x$disabledns" != "x1" ]; then - echo "nameserver $gateway" > /etc/resolv.conf - echo "nameserver $secondary_dns" >> /etc/resolv.conf + if ! grep -q "^/etc/resolv[.]conf$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + echo > /etc/resolv.conf + if [ "x$disabledns" != "x1" ]; then + echo "nameserver $gateway" > /etc/resolv.conf + echo "nameserver $secondary_dns" >> /etc/resolv.conf + fi fi if [ -f /var/run/qubes-service/network-manager ]; then nm_config=/etc/NetworkManager/system-connections/qubes-uplink-$INTERFACE diff --git a/rpm_spec/core-vm.spec b/rpm_spec/core-vm.spec index 3fcb635..8bce180 100644 --- a/rpm_spec/core-vm.spec +++ b/rpm_spec/core-vm.spec @@ -239,24 +239,31 @@ fi # Revert 'Prevent unnecessary updates in VMs': sed -i -e '/^exclude = kernel/d' /etc/yum.conf +# Location of files which contains list of protected files +PROTECTED_FILE_LIST='/var/lib/qubes/protected-files' + # qubes-core-vm has been broken for some time - it overrides /etc/hosts; restore original content -if ! grep -q localhost /etc/hosts; then - cat < /etc/hosts +if ! grep -q "^/etc/hosts$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + if ! grep -q localhost /etc/hosts; then + cat < /etc/hosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 `hostname` ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 EOF + fi fi # ensure that hostname resolves to 127.0.0.1 resp. ::1 and that /etc/hosts is # in the form expected by qubes-sysinit.sh -for ip in '127\.0\.0\.1' '::1'; do - if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then - sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts - sed -i "s/^${ip}\(\s\|$\).*$/\0 `hostname`/" /etc/hosts - else - echo "${ip} `hostname`" >> /etc/hosts - fi -done +if ! grep -q "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + for ip in '127\.0\.0\.1' '::1'; do + if grep -q "^${ip}\(\s\|$\)" /etc/hosts; then + sed -i "/^${ip}\s/,+0s/\(\s`hostname`\)\+\(\s\|$\)/\2/g" /etc/hosts + sed -i "s/^${ip}\(\s\|$\).*$/\0 `hostname`/" /etc/hosts + else + echo "${ip} `hostname`" >> /etc/hosts + fi + done +fi # Copy ip(|6)tables into place if they do not already exist in filesystem. # This prevents conflict with iptables-service diff --git a/vm-init.d/qubes-core b/vm-init.d/qubes-core index e3b2aa3..cd0a6dc 100755 --- a/vm-init.d/qubes-core +++ b/vm-init.d/qubes-core @@ -16,25 +16,37 @@ start() chmod 666 /proc/u2mfn mkdir -p /var/run/xen-hotplug + mkdir -p /var/run/qubes + chgrp qubes /var/run/qubes + chmod 0775 /var/run/qubes - name=$(/usr/bin/qubesdb-read /name) - if ! [ -f /etc/this-is-dvm ] ; then - # we don't want to set hostname for DispVM - # because it makes some of the pre-created dotfiles invalid (e.g. .kde/cache-) - # (let's be frank: nobody's gonna use xterm on DispVM) - hostname $name - sed -i "s/^\(127\.0\.0\.1[\t ].*\) \($name \)\?\(.*\)/\1\2 $name/" /etc/hosts + # Location of files which contains list of protected files + PROTECTED_FILE_LIST='/var/lib/qubes/protected-files' + + # Set the hostname + if ! grep -q "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + name=$(/usr/bin/qubesdb-read /name) + if ! [ -f /etc/this-is-dvm ] ; then + # we don't want to set hostname for DispVM + # because it makes some of the pre-created dotfiles invalid (e.g. .kde/cache-) + # (let's be frank: nobody's gonna use xterm on DispVM) + hostname $name + sed -i "s/^\(127\.0\.0\.1[\t ].*\) \($name \)\?\(.*\)/\1\2 $name/" /etc/hosts + fi fi - timezone=`/usr/bin/qubesdb-read /qubes-timezone 2> /dev/null` - if [ -n "$timezone" ]; then - ln -f /usr/share/zoneinfo/$timezone /etc/localtime - echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock - echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock + # Set the timezone + if ! grep -q "^/etc/timezone$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + timezone=`/usr/bin/qubesdb-read /qubes-timezone 2> /dev/null` + if [ -n "$timezone" ]; then + ln -f /usr/share/zoneinfo/$timezone /etc/localtime + echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock + echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock + fi fi yum_proxy_setup=$(/usr/bin/qubesdb-read /qubes-service/yum-proxy-setup 2> /dev/null || /usr/bin/qubesdb-read /qubes-service/updates-proxy-setup 2> /dev/null) - type=$(/usr/bin/qubesdb-read /qubes-vm-type) + type=$(/usr/bin/qubesdb-read /qubes-vm-type) if [ "$yum_proxy_setup" != "0" ] || [ -z "$yum_proxy_setup" -a "$type" == "TemplateVM" ]; then echo proxy=http://10.137.255.254:8082/ > /etc/yum.conf.d/qubes-proxy.conf else @@ -47,10 +59,6 @@ start() # qubesdb-read fails INTERFACE=eth0 /usr/lib/qubes/setup-ip - mkdir -p /var/run/qubes - chgrp qubes /var/run/qubes - chmod 0775 /var/run/qubes - if [ -e /dev/xvdb ] ; then # check if private.img (xvdb) is empty - all zeros private_size_512=`blockdev --getsz /dev/xvdb` @@ -64,11 +72,11 @@ start() resize2fs /dev/xvdb 2> /dev/null || echo "'resize2fs /dev/xvdb' failed" if ! [ -d /rw/home ] ; then - echo - echo "--> Virgin boot of the VM: Linking /home to /rw/home" + echo + echo "--> Virgin boot of the VM: Linking /home to /rw/home" - mkdir -p /rw/config - cat > /rw/config/rc.local < /rw/config/rc.local < /dev/null } @@ -67,26 +70,31 @@ for srv in `$QDB_LS /qubes-service/ 2>/dev/null |grep ' = 0'|cut -f 1 -d ' '`; d done # Set the hostname -name=`$QDB_READ /name` -if [ -n "$name" ]; then - hostname $name - if [ -e /etc/debian_version ]; then - ipv4_localhost_re="127\.0\.1\.1" - else - ipv4_localhost_re="127\.0\.0\.1" +if ! grep -q "^/etc/hostname$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + name=`$QDB_READ /name` + if [ -n "$name" ]; then + hostname $name + if [ -e /etc/debian_version ]; then + ipv4_localhost_re="127\.0\.1\.1" + else + ipv4_localhost_re="127\.0\.0\.1" + fi + sed -i "s/^\($ipv4_localhost_re\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts + sed -i "s/^\(::1\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts fi - sed -i "s/^\($ipv4_localhost_re\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts - sed -i "s/^\(::1\(\s.*\)*\s\).*$/\1${name}/" /etc/hosts fi -timezone=`$QDB_READ /qubes-timezone 2> /dev/null` -if [ -n "$timezone" ]; then - cp -p /usr/share/zoneinfo/$timezone /etc/localtime - if [ -e /etc/debian_version ]; then - echo "$timezone" > /etc/timezone - else - echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock - echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock +# Set the timezone +if ! grep -q "^/etc/timezone$" "${PROTECTED_FILE_LIST}" 2>/dev/null; then + timezone=`$QDB_READ /qubes-timezone 2> /dev/null` + if [ -n "$timezone" ]; then + cp -p /usr/share/zoneinfo/$timezone /etc/localtime + if [ -e /etc/debian_version ]; then + echo "$timezone" > /etc/timezone + else + echo "# Clock configuration autogenerated based on Qubes dom0 settings" > /etc/sysconfig/clock + echo "ZONE=\"$timezone\"" >> /etc/sysconfig/clock + fi fi fi