From d55cba0a450501621a27ba5baa251eb8e1cbed3c Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Mon, 30 Nov 2015 17:20:22 +0000 Subject: [PATCH 01/10] work on bind-dirs https://phabricator.whonix.org/T414 --- misc/bind-dirs | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100755 misc/bind-dirs diff --git a/misc/bind-dirs b/misc/bind-dirs new file mode 100755 index 0000000..6f44d05 --- /dev/null +++ b/misc/bind-dirs @@ -0,0 +1,98 @@ +#!/bin/bash -e +# vim: set ts=4 sw=4 sts=4 et : +# +# bind-dirs +# Binds directories which allows changes in TemplateBasedVM to persist. +# +# To umount all bind-dirs, just pass any arg in $1, like umount +# +# Copyright (C) 2014 - 2015 Jason Mehring +# Copyright (C) 2014 - 2015 Patrick Schleizer +# License: GPL-2+ +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set -x + +prerequisite() { + qubes_vm_persistence="$(qubesdb-read /qubes-vm-persistence)" + if [ ! "$qubes_vm_persistence" = "rw-only" ]; then + true "No TemplateBasedVM detected. Exiting." + exit 0 + fi +} + +init() { + [ -n "$rw_dest_dir" ] || rw_dest_dir="/rw/bind-dirs" + mkdir --parents "$rw_dest_dir" +} + +legacy() { + if [ -d /rw/srv/qubes-whonix ]; then + mv /rw/srv/qubes-whonix /rw/bind-dirs || true + fi + if [ -d /rw/srv/whonix ]; then + mv /rw/srv/whonix /rw/bind-dirs || true + fi +} + +bind_dirs() { + ## fso: file system object + ## ro: read-only + ## rw: read-write + for fso_ro in ${binds[@]}; do + fso_rw="${rw_dest_dir}${fso_ro}" + + # Make sure ro directory is not mounted + umount "$fso_ro" 2> /dev/null || true + + if [ -n "$1" ]; then + echo "Umounting $1 only..." + continue + fi + + # Initially copy over data directories to /rw if rw directory does not exist + if [ -d "$fso_ro" ]; then + if [ ! -d "$fso_rw" ]; then + cp --archive --parents --recursive "$fso_ro" "$rw_dest_dir" + fi + elif [ -f "$fso_ro" ]; then + if [ ! -f "$fso_rw" ]; then + cp --archive --recursive "$fso_ro" "$fso_rw" + fi + fi + + # Bind the directory + mount --bind "$fso_rw" "$fso_ro" + done +} + +main() { + prerequisite ${1+"$@"} + init ${1+"$@"} + legacy ${1+"$@"} + bind_dirs ${1+"$@"} +} + +for folder in /usr/lib/qubes-bind-dirs.d /etc/qubes-bind-dirs.d /rw/config/qubes-bind-dirs.d ; do + if [ ! -d "$folder" ]; then + continue + fi + for file_name in "$folder/"*".conf" ; do + bash -n "$file_name" + source "$file_name" + done +done + +main ${1+"$@"} From 8a5fc5f7d1b8200da982038792d051359225ba02 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 18 Dec 2015 00:11:27 +0100 Subject: [PATCH 02/10] work on bind-dirs https://phabricator.whonix.org/T414 --- misc/bind-dirs | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/misc/bind-dirs b/misc/bind-dirs index 6f44d05..f13e6f7 100755 --- a/misc/bind-dirs +++ b/misc/bind-dirs @@ -48,32 +48,52 @@ legacy() { } bind_dirs() { + ## legend ## fso: file system object ## ro: read-only ## rw: read-write + for fso_ro in ${binds[@]}; do fso_rw="${rw_dest_dir}${fso_ro}" - # Make sure ro directory is not mounted + # Make sure fso_ro is not mounted. umount "$fso_ro" 2> /dev/null || true if [ -n "$1" ]; then - echo "Umounting $1 only..." + true "Umounting $1 only..." continue fi - # Initially copy over data directories to /rw if rw directory does not exist + ## If $fso_ro is a symlink, see where it links to, then replace that + ## symlink with the file it linked to. This is because mount does not + ## following symlinks. + ## For more discussion and symlink and other special files, see: + ## https://phabricator.whonix.org/T414 + if [ -h "$fso_ro" ]; then + fso_real_location="$(realpath "$fso_ro")" + unlink "$fso_ro" + if [ -f "$fso_real_location" ]; then + cp --archive --recursive "$fso_real_location" "$fso_ro" + else + true "$fso_real_location is not a file, skipping." + fi + fi + + # Initially copy over data directories to /rw if rw directory does not exist. if [ -d "$fso_ro" ]; then if [ ! -d "$fso_rw" ]; then - cp --archive --parents --recursive "$fso_ro" "$rw_dest_dir" + cp --archive --recursive --parents "$fso_ro" "$rw_dest_dir" fi elif [ -f "$fso_ro" ]; then if [ ! -f "$fso_rw" ]; then cp --archive --recursive "$fso_ro" "$fso_rw" fi + else + true "$fso_ro does not exist, skipping." + continue fi - # Bind the directory + # Bind the fso. mount --bind "$fso_rw" "$fso_ro" done } @@ -85,11 +105,12 @@ main() { bind_dirs ${1+"$@"} } -for folder in /usr/lib/qubes-bind-dirs.d /etc/qubes-bind-dirs.d /rw/config/qubes-bind-dirs.d ; do - if [ ! -d "$folder" ]; then +for source_folder in /usr/lib/qubes-bind-dirs.d /etc/qubes-bind-dirs.d /rw/config/qubes-bind-dirs.d ; do + true "source_folder: $source_folder" + if [ ! -d "$source_folder" ]; then continue fi - for file_name in "$folder/"*".conf" ; do + for file_name in "$source_folder/"*".conf" ; do bash -n "$file_name" source "$file_name" done From bd647a8047f7d35419e80b74c09f28fbe486a0f7 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 18 Dec 2015 01:15:51 +0100 Subject: [PATCH 03/10] work on bind-dirs https://phabricator.whonix.org/T414 --- misc/bind-dirs | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/misc/bind-dirs b/misc/bind-dirs index f13e6f7..e279497 100755 --- a/misc/bind-dirs +++ b/misc/bind-dirs @@ -35,6 +35,7 @@ prerequisite() { init() { [ -n "$rw_dest_dir" ] || rw_dest_dir="/rw/bind-dirs" + [ -n "$symlink_level_max" ] || symlink_level_max="10" mkdir --parents "$rw_dest_dir" } @@ -54,6 +55,27 @@ bind_dirs() { ## rw: read-write for fso_ro in ${binds[@]}; do + local symlink_level_counter + symlink_level_counter="0" + + ## For more discussion and symlink and other special files, see: + ## https://phabricator.whonix.org/T414 + while true; do + if [ -h "$fso_ro" ]; then + symlink_level_counter="$(( symlink_level_counter + 1 ))" + true "$fso_ro is a symlink" + fso_real_location="$(realpath "$fso_ro")" + fso_ro="$fso_real_location" + else + true "$fso_ro is not a symlink" + break + fi + if [ "$symlink_level_counter" -ge "10" ]; then + break + fi + done + + true "fso_ro: $fso_ro" fso_rw="${rw_dest_dir}${fso_ro}" # Make sure fso_ro is not mounted. @@ -64,21 +86,6 @@ bind_dirs() { continue fi - ## If $fso_ro is a symlink, see where it links to, then replace that - ## symlink with the file it linked to. This is because mount does not - ## following symlinks. - ## For more discussion and symlink and other special files, see: - ## https://phabricator.whonix.org/T414 - if [ -h "$fso_ro" ]; then - fso_real_location="$(realpath "$fso_ro")" - unlink "$fso_ro" - if [ -f "$fso_real_location" ]; then - cp --archive --recursive "$fso_real_location" "$fso_ro" - else - true "$fso_real_location is not a file, skipping." - fi - fi - # Initially copy over data directories to /rw if rw directory does not exist. if [ -d "$fso_ro" ]; then if [ ! -d "$fso_rw" ]; then @@ -89,7 +96,7 @@ bind_dirs() { cp --archive --recursive "$fso_ro" "$fso_rw" fi else - true "$fso_ro does not exist, skipping." + true "$fso_ro is neither a directory nor a file or does not exist, skipping." continue fi @@ -99,10 +106,10 @@ bind_dirs() { } main() { - prerequisite ${1+"$@"} - init ${1+"$@"} - legacy ${1+"$@"} - bind_dirs ${1+"$@"} + prerequisite "$@" + init "$@" + legacy "$@" + bind_dirs "$@" } for source_folder in /usr/lib/qubes-bind-dirs.d /etc/qubes-bind-dirs.d /rw/config/qubes-bind-dirs.d ; do @@ -116,4 +123,4 @@ for source_folder in /usr/lib/qubes-bind-dirs.d /etc/qubes-bind-dirs.d /rw/confi done done -main ${1+"$@"} +main "$@" From 8f2a80982b2edb15edc146b5553e345405950b68 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 25 Dec 2015 12:18:18 +0000 Subject: [PATCH 04/10] renamed: misc/bind-dirs -> vm-systemd/bind-dirs --- {misc => vm-systemd}/bind-dirs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {misc => vm-systemd}/bind-dirs (100%) diff --git a/misc/bind-dirs b/vm-systemd/bind-dirs similarity index 100% rename from misc/bind-dirs rename to vm-systemd/bind-dirs From 5a87313ea61c3c9a2f6d909a164de006e222141d Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 25 Dec 2015 12:19:18 +0000 Subject: [PATCH 05/10] renamed: bind-dirs -> bind-dirs.sh --- vm-systemd/{bind-dirs => bind-dirs.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vm-systemd/{bind-dirs => bind-dirs.sh} (100%) diff --git a/vm-systemd/bind-dirs b/vm-systemd/bind-dirs.sh similarity index 100% rename from vm-systemd/bind-dirs rename to vm-systemd/bind-dirs.sh From eb00e40bab8bd40598fe53742a6eacfe66d88ee3 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 25 Dec 2015 12:30:05 +0000 Subject: [PATCH 06/10] run /usr/lib/qubes/bind-dirs.sh from mount-dirs.sh --- vm-systemd/mount-dirs.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vm-systemd/mount-dirs.sh b/vm-systemd/mount-dirs.sh index 0647d88..7045be0 100644 --- a/vm-systemd/mount-dirs.sh +++ b/vm-systemd/mount-dirs.sh @@ -89,3 +89,5 @@ if [ -e /var/run/qubes-service/qubes-dvm ]; then else mount /home fi + +/usr/lib/qubes/bind-dirs.sh From 7e8649f8c7129ca620c9d6363d579dbeee005209 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Wed, 6 Jan 2016 20:46:38 +0000 Subject: [PATCH 07/10] use symlink_level_max rather than hardcoding 10; comment --- vm-systemd/bind-dirs.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm-systemd/bind-dirs.sh b/vm-systemd/bind-dirs.sh index e279497..6647334 100755 --- a/vm-systemd/bind-dirs.sh +++ b/vm-systemd/bind-dirs.sh @@ -58,10 +58,10 @@ bind_dirs() { local symlink_level_counter symlink_level_counter="0" - ## For more discussion and symlink and other special files, see: - ## https://phabricator.whonix.org/T414 while true; do if [ -h "$fso_ro" ]; then + ## Resolving where there symlink points to, and using the result + ## for bind mount instead. symlink_level_counter="$(( symlink_level_counter + 1 ))" true "$fso_ro is a symlink" fso_real_location="$(realpath "$fso_ro")" @@ -70,7 +70,7 @@ bind_dirs() { true "$fso_ro is not a symlink" break fi - if [ "$symlink_level_counter" -ge "10" ]; then + if [ "$symlink_level_counter" -ge "$symlink_level_max" ]; then break fi done From 184f49dbbdb960da13c737030d8af3d56aeff64e Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Wed, 6 Jan 2016 23:08:33 +0000 Subject: [PATCH 08/10] also exit from bind-directories if file /var/run/qubes-service/qubes-dvm exists Thanks to @marmarek for the suggestion! https://github.com/QubesOS/qubes-issues/issues/1328#issuecomment-169483029 --- vm-systemd/bind-dirs.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/vm-systemd/bind-dirs.sh b/vm-systemd/bind-dirs.sh index 6647334..b91b566 100755 --- a/vm-systemd/bind-dirs.sh +++ b/vm-systemd/bind-dirs.sh @@ -31,6 +31,13 @@ prerequisite() { true "No TemplateBasedVM detected. Exiting." exit 0 fi + if [ -f "/var/run/qubes-service/qubes-dvm" ]; then + # https://github.com/QubesOS/qubes-issues/issues/1328#issuecomment-169483029 + # Do none of the following in a DispVM. + # During DispVM savefile generation, 'qubesdb-read /qubes-vm-persistence' + # outputs 'rw'. + exit 0 + fi } init() { From e9fca8fb9fef917f4402eecb1b9b802d82a46550 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Thu, 7 Jan 2016 21:19:52 +0000 Subject: [PATCH 09/10] fixed broken file copy for files in multi level directories Thanks to @marmarek for the report and help fixing! --- vm-systemd/bind-dirs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm-systemd/bind-dirs.sh b/vm-systemd/bind-dirs.sh index b91b566..adbfc95 100755 --- a/vm-systemd/bind-dirs.sh +++ b/vm-systemd/bind-dirs.sh @@ -100,7 +100,7 @@ bind_dirs() { fi elif [ -f "$fso_ro" ]; then if [ ! -f "$fso_rw" ]; then - cp --archive --recursive "$fso_ro" "$fso_rw" + cp --archive --recursive --parents "$fso_ro" "$rw_dest_dir" fi else true "$fso_ro is neither a directory nor a file or does not exist, skipping." From f4d367a6a7eb70f3658e28f5ae5841b2fff3b1c9 Mon Sep 17 00:00:00 2001 From: Patrick Schleizer Date: Fri, 8 Jan 2016 00:36:26 +0000 Subject: [PATCH 10/10] refactoring / code simplification Thanks to @marmarek for the suggestion! --- vm-systemd/bind-dirs.sh | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/vm-systemd/bind-dirs.sh b/vm-systemd/bind-dirs.sh index adbfc95..3c9a7b5 100755 --- a/vm-systemd/bind-dirs.sh +++ b/vm-systemd/bind-dirs.sh @@ -94,14 +94,8 @@ bind_dirs() { fi # Initially copy over data directories to /rw if rw directory does not exist. - if [ -d "$fso_ro" ]; then - if [ ! -d "$fso_rw" ]; then - cp --archive --recursive --parents "$fso_ro" "$rw_dest_dir" - fi - elif [ -f "$fso_ro" ]; then - if [ ! -f "$fso_rw" ]; then - cp --archive --recursive --parents "$fso_ro" "$rw_dest_dir" - fi + if [ -d "$fso_ro" ] || [ -f "$fso_ro" ]; then + cp --verbose --no-clobber --archive --recursive --parents "$fso_ro" "$rw_dest_dir" else true "$fso_ro is neither a directory nor a file or does not exist, skipping." continue