How do I run a script in dom0 from within a qube securely?

Hi all,

I want to open a folder from a qube, X, in another (disposable) qube, dispXXXX.

I know I can copy a folder using qvm-copy, then select a DispVM, however:

  1. the dispXXXX spawns, and terminates as soon as the copy process is done (?)
  2. even if it’d work, I’d like to auto open the folder in this new disposable qube instead of manually opening its file manager, going to QubesIncoming, etc etc

My idea would be for Qube X (the one that has all the folders) to somehow tell dom0 the path of the folder and have dom0:

  1. spawn a disposable VM, get its name and store it in a variable dispname
  2. do qvm-run $QUBE_X 'qvm-copy-to-vm $dispname $path_here_somehow'
  3. then do qvm-run $dispname /usr/bin/xdg-open ~/QubesIncoming/$QUBE_X/$path_split so it opens the file manager on the disposable

(where $path_split would be $path_here_somehow but only the last dir)

However:

How would Qube X securely communicate with dom0? It only needs to give it the path of the directory, and dom0 takes it from there.

I am new to Qubes, thank you!

EDIT: and also, is this fine to do to achieve what I want? Unfortunately, QubesOS doesn’t seem to natively support opening directories in DispVMs, as I can see under /usr/lib/qubes/qvm-actions.sh:

    openvm)
        for file in "$@"
        do
            if [ -d "$file" ];
            then
                zenity --notification --text "Directory $file found, cannot open directories in other VMs." --timeout 3 &
                exit 1
            fi
        done7

EDIT: ok it seems I could use qubes.VMShell, but it sounds insecure to me: the prompt doesn’t tell me what command will be executed, so an attacker can just change it to whatever. And yeah it’s also mentioned in here How I can run any vm from another vm? - #2 by unman

It seems I can create a custom RPC operation, so I will try that

Are you looking for the qvm-open-in-dvm command?

That doesn’t work for directories

I would try to initiate this from dom0 instead, especially considering that something like this would be easier to bind to a key combination. For example, you could open a terminal of QUBE_X, and then run this:

window="$(xdotool getwindowfocus)"
QUBE_X="$(xprop _QUBES_VMNAME -id "$window" | cut -d \" -f 2)"
disptmpl="$(qvm-prefs "$QUBE_X" default_dispvm)"

if [ -z "$disptmpl" ]
then disptmpl="dom0"
fi

readarray -d '' -s 1 disp < <(\
  qubesd-query --empty --fail dom0 admin.vm.CreateDisposable "$disptmpl" \
)
qvm-start "$disp"
echo -n "$disp" | xsel --clipboard --input
notify-send -u normal "$disp is ready"

Afterwards, execute qvm-copy ~/mydir and paste the disposable name into the copy confirmation dialog

The only thing left is to figure out how would you like to open the direcory after it have been copied. For example, you could extend the script above to assume that you already have terminal with qvm-copy ~/mydir open, and automate it even further:

xdotool windowactivate --sync "$window"
xdotool key --window "$window" Enter
sleep .5 # wait just a bit for copy confirmation to open
xdotool key ctrl+v
xdotool key Enter
# either this
qvm-run -u user "$disp" /usr/bin/xdg-open /home/user/QubesIncoming
# or this for thunar specifically:
qvm-run -u user "$disp" /usr/bin/thunar /home/user/QubesIncoming
# once you close thunar, qvm-run will finish; to terminate $disp:
qvm-shutdown "$disp"

p.s. I haven’t tested any of this, it might need some tweaking to actually work (especially xdotool automation)

1 Like

Thanks. I will try that.

For now, this is what I was able to achieve.

I created, under /etc/qubes-rpc in dom0, vault.OpenFolderDisp:

#!/usr/bin/bash
set -euo pipefail

SRC_VM="vault"
TMPFILE="$(mktemp)"
TPATH="$1"
TPATH=${TPATH//_//}

[[ -z "$TPATH" ]] && { echo "Please provide TPATH"; exit 1; };

PATH_STRIPPED="${TPATH%/}"
PATH_SPLIT="${PATH_STRIPPED##*/}"
#PATH_SPLIT="$(basename "$PATH")"

echo "path is $TPATH"
echo "split is $PATH_SPLIT"

qvm-run --dispvm=dvm-player --pass-io \
	"/usr/bin/bash -c 'echo \$HOSTNAME'; \
	mkdir -p ~/QubesIncoming/$SRC_VM/$PATH_SPLIT & \
	/usr/bin/xdg-open ~/QubesIncoming/$SRC_VM/$PATH_SPLIT" \
	>"$TMPFILE" &

echo "$TMPFILE"

DISP_VM=$(sed '/disp/q' <(tail -n 0 -f $TMPFILE))

echo "dispvm is $DISP_VM"

qvm-run "$SRC_VM" \
	"qvm-copy-to-vm $DISP_VM '$TPATH'"

It’s hacky, but it works… but only if I run this from dom0.

If I run, in dom0, /etc/qubes-rpc/vault.OpenFolderDisp, Thunar opens in the disposable and the VM stays active until I close it, and the folder is copied etc etc…

However, when I run qrexec-client-vm dom0 vault.OpenFolderDisp+/path/to/dir in vault, for some weird reason, the disposable spawns but then shuts down right after; Thunar is never opened (but the tmpfile is written to.)

I’m trying to figure out why this is…

1 Like

Something is going on with the environment, you don’t have anything set for opening a directory when running from QUBE_X

It works if I use /usr/bin/thunar instead of xdg-open. Unfortunately I don’t have a clue of why xdg-open behaves like that.

Perhaps you should try qubes-open instead

Interesting. /usr/bin/thunar didn’t work for me, nor qubes-open (which seems to be an alias to xdg-open anyway). I wonder if the template of vault is affecting this? But why would the environment of vault affect anything?

Just to make sure, you’re running the same command as above from within QUBE_X, right? The qrexec-client-vm one

Path and service name are different in my case, and my version of service is a bit different as well:

#!/usr/bin/bash
set -o errexit
set -o nounset
set -o pipefail

SRC_VM="test"
TPATH="$1"
TPATH=${TPATH//_//}

[[ -z "$TPATH" ]] && { echo "Please provide TPATH"; exit 1; };

PATH_STRIPPED="${TPATH%/}"
PATH_SPLIT="${PATH_STRIPPED##*/}"

echo "path is $TPATH"
echo "stripped is $PATH_STRIPPED"
echo "split is $PATH_SPLIT"

readarray -d '' -s 1 DISP < <(
  qubesd-query --empty --fail dom0 admin.vm.CreateDisposable \
      "$(qubes-prefs default_dispvm)"
)
qvm-start "$DISP"
qvm-run -u user "$DISP" \
    "/usr/bin/mkdir -p /home/user/QubesIncoming/$SRC_VM/$PATH_SPLIT"
qvm-run -u user "$DISP" \
    "/usr/bin/thunar /home/user/QubesIncoming/$SRC_VM/$PATH_SPLIT"
qvm-shutdown "$DISP"

I hope these changes don’t make any substantial difference. In the end it’s the same qvm-run $vm $program $path. What is important is that if I set $program to xdg-open, it behaves differently when ran with qrexec-client-vm (although in my case it opens firefox instead of thunar, but I assume it’s just the difference in configuration of our vms)

That’s weird! Mine just exits at

qvm-run -u user "$DISP" \
    "/usr/bin/thunar /home/user/QubesIncoming/$SRC_VM/$PATH_SPLIT"

if I run your script under qrexec-client-vm. But if I run this same command straight from dom0, it works.

I also tried using qubes-prefs default_dispvm which in my machine might be similar to yours (the default default-dvm template), still doesn’t work.

Oh well

My default_dispvm isn’t default at all!

Just tested with a completely default fedora 42 disposable template, still works.

p.s. default debian 12 works as well