Edit in disposable (qvm-open-in-vm): file is not updated

Hello there,

I have successfully managed to edit a file in a disposable with gedit as shown in:

Now, instead of gedit, I tried to use a custom script in the disposable, which updates a given text file in the original qube. Unfortunately, this did not work. Minimal example:

.desktop file and custom script (disposable A):

mkdir -p .local/share/applications

cat <<'EOF' > .local/share/applications/open.desktop
[Desktop Entry]
Name=Update text file
Exec=/home/user/open.sh %f
Type=Application
MimeType=text/plain
EOF

cat <<'EOF' > $HOME/open.sh
#!/bin/sh
echo ARGUMENTS: "$@" >> /tmp/test.log 
echo "updated!" > "$1" # guess, file updating with $1 is wrong
EOF

chmod u+x $HOME/open.sh

# Add default handler  for `text/plain`
mkdir -p .config
xdg-mime default open.desktop text/plain
xdg-mime query default text/plain

In qube B:

echo foo > test.txt
qvm-open-in-vm @default test.txt # choose disposable A in ask  dialog

I hoped to have test.txt updated with content "updated!" in qube B, which is not the case - content is still "foo". But the script is invoked, as /tmp/test.log gets updated.

How might I change the code? Appreciate any help, thanks!

You have to take it out of disposable mode, make the change, then flip it back to disposable. I also always disconnect network connections to help ensure the VM doesn’t get tainted when it’s not in disposable mode.

@joe.blough what do you mean by “take it out of disposable mode”?

If I use gedit instead of my custom script (which is contrived for illustration purpose), then I can retain disposables and update files in original qubes. So that should be definitely possible by using disposables, if I understood your point correctly.

The changes you make in that directory should keep but I think you need to make the changes while the VM is not a disposable.

In Qube Settings for that AppVM, select the Advanced tab. There is a checkbox called DisposableVM Template. Click it to change it from disposable to regular.

No need to change the code - it does exactly what you want (except for
the logging). I am unclear as to why you think it does not.
Have you check that the code is present in every disposable based on the
disposable template?
Where is /tmp/test.log updated? In B? (I doubt that.)

Have you confirmed that the script works if you call the disposable
template instead of a disposable?

@joe.blough Doesn’t work unfortunately (see next). I am also strongly convinced, this should work with disposables.

@unman Good to hear, I am not totally on the wrong path.
Yes, open.sh is ensured to exist in disposable A. I also tried to address an existent disposable via qvm-open-in-vm dispXXX test.txt, no change.

Let’s take disposables out of the way and use normal AppVMs:

qvm-create -l red -t fedora-33 test-a
qvm-create -l red -t fedora-33 test-b

/etc/qubes-rpc/policy/qubes.OpenInVM:

test-b test-a allow

test-a: Use script from first post.

test-b:

echo foo > test.txt
qvm-open-in-vm test-a test.txt
echo $? # 0
cat test.txt # still "foo", not "updated!"

Now check, that script has been invoked in test-a:

cat /tmp/test.log 
# ARGUMENTS: /tmp/test-b-FiIZBZ/test.txt

So the script in A is executed and receives input file from B (/tmp/test-b-xxx/test.txt). It also changes its content to "updated!" inside A.
But B does not get the changed file and still has "foo", when the IPC call is finished.

What version of Qubes are you using and what template is used for test-a
and test-b?
Have you confirmed that your script works when called with a text file
in test-a ? That should be your first step.

You don’t need to do this.
In 4.1, there are menu items both for the disposable and for the
disposable template.
In 4.0 you can always access the disposable template, from dom0 - if the
disposable is based on “work” just call it directly with qvm-run work...

Qubes 4.0 with latest updates:

[user@dom0 ~]$ cat /etc/qubes-release 
Qubes release 4.0 (R4.0)

test-a and test-b are fresh AppVMs based on default fedora-33 template.

Yes, I confirmed that. In test-a:

[user@test-a ~]$ echo foo > test.txt
[user@test-a ~]$ gtk-launch open.desktop test.txt 
[user@test-a ~]$ cat test.txt 
updated!

But here is a surprising thing - staying with qvm-open-in-vm, this is what I just have executed:

[user@test-b ~]$ echo foo > test.txt
[user@test-b ~]$ qvm-open-in-vm test-a test.txt
[user@test-b ~]$ cat test.txt
updated!
[user@test-b ~]$ echo foo > test.txt
[user@test-b ~]$ qvm-open-in-vm test-a test.txt
[user@test-b ~]$ cat test.txt
foo

So two invocations may result in different outcomes . The first one doesn’t need to be a successful write either, in fact it’s very rare, it works.

It seems, there is some kind of race condition?

With Debian and Ubuntu qubes, it works every time for me. No apparent
race:not a superpowered machine.
If you put a sleep in your script before the cat, and then after it,
does that make any difference?

1 Like

yes, sleep works, thanks!

open.sh (in test-a):

#!/bin/sh
sleep 1 # this sleep is important
echo "updated!" > "$1"
#sleep 1 # this sleep didn't fix race condition

Now, qvm-open-in-vm from test-b consistently results in file test.txt having content "updated!".

I am glad there is a workaround, though would be very keen to find a “real” fix for this race condition.

No super-powered machine on my side either, no special hardware. I guess, gedit and GUI applications work due to more needed startup-time, but in theory should have same issue.

Are you using Qubes 4.1 and does it work properly there?

// EDIT Btw: also tried Debian 10 qubes, but does not work without sleep.