with appropriate policy set to ask causes what essentially is a duplicate confirmation - first you imply confirmation by running the command, then in the dialog box. So far I’ve only come up with shit solutions. What hax do you use to get around this?
I’ve been looking into qrexec-client-vm and it seems like one must manually handle sockets to do this cleanly by calling qfile-agent and qfile-unpacker from dom0.
Also let’s rename qrexec agents to qrexec imps because they are lesser than the qrexec daemon
The arguably best solution for this would be to setup a policy that allows qvm-copy without prompt from vm A to B - that used to work way back in I think it was Qubes 4.0 or so, I am not sure how exactly that works now, as in I am not sure if you can automate the “destination vm” prompt away.
Yeah I’ve considered that too, but I don’t want allow policy, I want running command from dom0 to be a sufficient confirmation. One janky idea is to change policy every time, but that is too bad even for me.
Then I thought I should rather create a service that needs no confirmation if source is dom0, but it kind of requires the service to set up data communication separately. I think.
In that light piping through dom0 is an interesting prospect; How different is it from xen’s vchans?
I’ve never tried those directly but always relied on qvm-run –pass-io, even though its pretty fugly.
If you find a way to automate this with using qvm-copy I’m all ears - or a better way of VM to VM copy that ideally supports source and destination paths, as well as piping, using a qrexec policy (that is safe) - and can be triggered from dom0 x)
I’m actually using the qvm-run –pass-io method with tar to create backups, like this:
This saves a ton of time and disk space on both source and backup VM (sys-usb) because the normal workflow would be:
create tar.zst in to-be-backed-up vm and save it somewhere (downside: needs space)
qvm-copy it to sys-usb (needs space in sys-usb that is not on the USB backup device, or you mount that directly to /home/user/QubesIncoming, which I find ugly)
mv that file from sys-usb:QubesIncoming to sys-usb:/mnt
This eats more disk space than required in both backup source and destination vm, and costs time left and right.
The solution with –pass-io is utterly fugly, as it pipes the stream through dom0, but it doesnt have any of the downsides as the “regular way”.
I suppose its time to replace that with a fancy qrexec policy of sorts, but I haven’t gotten to that yet.
Ok thought this was interesting, so I had ChatGPT find out - this is untested.
Here is the minimal qrexec PoC version. It does not stream file bytes through dom0; dom0 only starts the command in the source qube.
In the destination qube, create:
/etc/qubes-rpc/kuhbs.PathCopy
with:
#!/bin/sh
# The source qube sends the destination path as the first line.
read dst
# After read consumes the first line, stdin is still the same qrexec stream;
# the remaining bytes are the file content sent by the source qube.
cat > "$dst"
dom0 starts one command in src-qube
src-qube sends destination path as the first line
src-qube sends file bytes after that
dest-qube reads first line into $dst
dest-qube writes the remaining bytes to that path
So this copies:
src-qube:/home/user/fo.jpg
to:
dest-qube:/home/user/bla/fo.jpg
without using QubesIncoming and without piping the file through dom0.
Note that a malicious src-qube is free to override the destination path that dom0 here tells it to forward to dest-qube (and of course, it can choose the file content too). So src-qube could instead tell dest-qube to write some code to one of its Bash startup files, for example. (src-qube can also initiate the qrexec call itself at any time, instead of waiting for dom0 to tell it to do so.)
You should only allow src-qube to run kuhbs.PathCopy on dest-qube if you would feel okay letting src-qube execute arbitrary code on dest-qube (like giving it qubes.VMShell or qubes.VMExec access).
Yes true, as said, was just proof of concept. You can modify the whole thing to for example be push and pull based form one VM, with a script in dst to only allow for a specific path.
Is python subprocess’ pipe meaningfully different to dom0 shell’s pipe? On that note, does qrexec-daemon connect two vchans together or arranges one vchan between vms when running qubes.Filecopy?
Regardless, thanks for posting good stuff as you so often do.
Not really, the data still has to pass through dom0 memory either way. (Which is worse from an anti-forensic perspective than the normal filecopy initiated from within a VM.)
I’m not so sure about the vchan details, but qubes.Filecopy is bidirectional - the sender side also reads status information from the receiver side - which was the practical reason for using --localcmd. It’s more convenient than e.g.
It probably doesn’t make a realistic difference for almost anyone. Theoretically, I can come up with something like: An attacker might get the disk encryption keys, but the VMs used during filecopy could be on secondary storage that’s no longer around.
Maybe dom0 swap sadly using persistent (instead of ephemeral) encryption keys on Qubes OS could also factor into some weird scenario. I haven’t really thought about it.
As long as dom0 doesn’t do anything with the untrusted data except copying it from one place to another, it’s alright. E.g. if you use the global clipboard, those are also arbitrary bytes that pass through dom0. (They’re even stored in a dom0 RAM-based filesystem for the time between Ctrl+Shift+C and Ctrl+Shift+V.)
I should add that although the stderr diagnostics from qfile-agent and qfile-unpacker end up being displayed in the dom0 terminal - which certainly counts as “dom0 doing something” with VM data! - qvm-run detects that it is outputting to a terminal, and automatically filters this data very strictly. Only printable ASCII plus a few more essential characters are allowed, every other byte is replaced with _ before it hits stderr.