Opening URLs/files in other Qubes

Note: there is an ongoing pull request to add most of the content of this document to the official Qubes OS documentation.

This page is about opening URLs and files from one qube in a different qube. The most straightforward way to do this is simply to copy and paste URLs or copy and move files from the source qube to the target qube, then manually open them in the target qube. However, some users might wish to use RPC policies in order to regiment their workflows and safeguard themselves from making mistakes.

Naming conventions:

  • <SOURCE_QUBE> is the qube in which the URL or file originates.
  • <TARGET_QUBE> is the qube in which we wish to open the URL or file.

Configuring RPC policies

The qvm-open-in-vm and qvm-open-in-dvm scripts are invoked in a qube to open files and URLs in another qube. Those scripts make use of the qubes.OpenInVM and qubes.OpenURL RPC services. Qubes RPC policies control which RPC services are allowed between qubes.

Policy files are in /etc/qubes/policy.d/.

Using the ask action

This action displays a confirmation prompt in dom0 with a drop-down list of allowed target qubes each time the associated RPC service is called. This setup makes it possible to always control whether and in which qube a URL or file opened.

The selected qube will automatically start if it wasn’t running.

Note: When using ask, the target qube given as an argument to qvm-open-in-vm is ignored if no allow rule matches the current RPC service and source/target qubes.

Using the allow action

This action allows a specified RPC service to be invoked between source and target qubes without displaying a confirmation prompt in dom0.

When an allow action is defined for a target other than @dispvm, the target qube is the one given as an argument to qvm-open-in-vm in <SOURCE_QUBE>. The corresponding RPC policies must be configured accordingly.

Warning: Since there is no user confirmation with allow, applications in <SOURCE_QUBE> could leak data through URLs or file names.

Using disposables and the @dispvm keyword in policies

It is possible to further restrict a target disposable qube by specifying the template on which it is based with the @dispvm:<DISPOSABLE_TEMPLATE> syntax (learn more).

Note: The keyword @dispvm designates any disposable based on the calling qube’s default disposable template. It does not designate any disposable whatsoever. For example, if you were to run qvm-open-in-vm @dispvm:<ONLINE_DISPOSABLE_TEMPLATE> https://www.qubes-os.org in <SOURCE_QUBE> while <ONLINE_DISPOSABLE_TEMPLATE> is not <SOURCE_QUBE>'s default disposable template, it wouldn’t work if your policy line merely had @dispvm as the target. You would have to use @dispvm:<ONLINE_DISPOSABLE_TEMPLATE> as the target instead.

Sample RPC user policy

See the main document, RPC policies, for more information.

The following is a partial example of the kinds of qubes.OpenInVM and qubes.OpenURL rules that you could write in /etc/qubes/policy.d/30-user.policy:

# Deny opening files or URLs from or in 'vault'
qubes.OpenInVM   *   @anyvm   vault         deny
qubes.OpenURL    *   @anyvm   vault         deny
qubes.OpenInVM   *   vault    @anyvm        deny
qubes.OpenURL    *   vault    @anyvm        deny

# Allow 'work' to open URLs in disposable qubes without prompting the user
qubes.OpenURL    *   work     @dispvm       allow

# Allow 'work' to open files in 'untrusted' without prompting the user
qubes.OpenInVM   *   work     @dispvm       allow target=untrusted

# Allow any qube to open files and URLs in disposables based on the
# disposable templates 'foo' and 'bar'
qubes.OpenInVM   *   @anyvm   @dispvm:foo   allow
qubes.OpenURL    *   @anyvm   @dispvm:bar   allow

# Prompt the user before opening any file or URL in any other qube, but prefill
# the target with 'personal' for files and 'untrusted' for URLs
qubes.OpenInVM   *   @anyvm   @anyvm        ask default_target=personal
qubes.OpenURL    *   @anyvm   @anyvm        ask default_target=untrusted

Configuring application handlers

It is possible to (re)define a default application handler so that it is automatically called by any application in <SOURCE_QUBE> to open files or URLs provided that the applications adhere to the freedesktop standard (which is almost always the case nowadays).

For application-specific configurations or applications that don’t adhere to the freedesktop standard, please refer to the unofficial, external community documentation.

Defining a new handler simply requires creating a .desktop file and registering it. The following example shows how to open http/https URLs (along with common “web” media types) with qvm-open-in-vm:

  • Create $HOME/.local/share/applications/mybrowser.desktop with the following content:

    [Desktop Entry]
    Encoding=UTF-8
    Name=MyBrowser
    Exec=qvm-open-in-vm <TARGET_QUBE> %u
    Terminal=false
    X-MultipleArgs=false
    Type=Application
    Categories=Network;WebBrowser;
    MimeType=x-scheme-handler/unknown;x-scheme-handler/about;text/html;text/xml;application/xhtml+xml;application/xml;application/vnd.mozilla.xul+xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;
    
  • Register the .desktop file with xdg-settings set default-web-browser mybrowser.desktop.

The same can be done with any other media type (see man xdg-mime and xdg-settings).

Notes

  • Some applications may not use the new XDG application handler (e.g., if you had previously configured default applications), in which case you’d have to manually configure the application to use the XDG handler.

  • qvm-open-in-vm target-qube %u can be replaced by a user wrapper with custom logic for selecting different target qubes depending on the URL/file type, level of trust, etc. The RPC policies should be configured accordingly.

  • Advanced users may wish to consider basing app qubes on minimal templates. That way, unless a default handler is set, it is unlikely that any other program will be present that can open the URL or file.

Configuring specific applications

Most applications provide a way to select a given program to use for opening specific URL/file (MIME) types. We can use that feature to select the /usr/bin/qvm-open-in-{vm,dvm} scripts instead of the default programs.

The subsections below show how to configure popular applications in case the “default handler” approach above doesn’t work / isn’t sufficient.

Firefox, Chrome/Chromium

Those browsers have an option to define programs associated to a file (MIME) type. It is pretty straightforward to configure and is outside the scope of this document.

An alternative is to use Raffaele Florio’s qubes-url-redirector add-on, which provides a lot of flexibility when opening links without the hassle of having to write custom shell wrappers to qvm-open-in-vm. For instance links can be opened with a context menu and the add-on’s default behavior can be configured, even with whitelist regexes.

Notes:

  • the qubes-url-redirector add-on will likely be included officialy in Qubes (see this issue).
  • the add-on can actually be used with applications other than firefox/chrome/chromium, the only requirement is that URLs open in a browser in <SOURCE_QUBE>. It works like so:
    • the application in <SOURCE_QUBE> opens an URL in the default browser in <SOURCE_QUBE> (eg. firefox)
    • firefox starts on <SOURCE_QUBE>, the add-on processes the URL and according to its configuration “sends” the URL to <TARGET_QUBE> with qubes.OpenURL
    • the URL opens in the <TARGET_QUBE>'s browser

Thunderbird

Opening attachments: “actions” must be defined, see section “Download Actions” settings" in this document.

Opening URLs: changing the way http and https URLs are opened requires tweaking configuration options; see this and this document for more information. Those changes can be made in Thunderbird’s built-in config editor, or by adding the following lines to $HOME/.thunderbird/user.js:

user_pref("network.protocol-handler.warn-external.http", true);
user_pref("network.protocol-handler.warn-external.https", true);
user_pref("network.protocol-handler.expose-all", true);

Thunderbird will then ask which program to use the next time a link is opened. If <TARGET_QUBE> is a standard (random) dispVM, choose /usr/bin/qvm-open-in-dvm. Otherwise you’ll have to create a wrapper to qvm-open-in-vm since arguments cannot be passed to programs selected in Thunderbird’s dialog gui. For instance, put the following text in $HOME/bin/thunderbird-open-url, make it executable, and select that program when asked which program to use:

#!/bin/sh
qvm-open-in-vm <TARGET_QUBE> "$@"

Vi

Opening URLs: put the following in $HOME/.vimrc:

let g:netrw_browsex_viewer = 'qvm-open-in-vm <TARGET_QUBE>'

Typing gx when the cursor is over an URL will then open it in <TARGET_QUBE> (or will trigger a dialog if ask policy is configured, ignoring the <TARGET_QUBE> argument).

Considerations on dispVMs

Re-using dispVMs

In the section above we’ve seen how using the ‘ask’ RPC policy allowed us to start a (disp)VM once and use it for opening subsequent URLs (or files) to avoid having to wait insane amounts of time for dispVMs to start. However this comes at the price of a loss in compartmentalization. It is thus up to the user to carefully pick destination VMs and to manage the lifecycle of dispVMs, killing it/them when necessary when a clean state is required.

Managing changes

When opening and modifying a document in a dispVM the content is sent back to <SOURCE_QUBE> when the dispVM’s process (eg. LibreOffice) closes. The dispVM’s private volume is then wiped and any change that was made to the VM are discarded - eg. automatically updated add-ons, blacklists, tweaked browser preferences, … ; The following ideas show how to cope with those “deliberate” changes:

  • inter-VM copy/paste is probably the easiest way to synchronize small amounts of data in text form from the dispVM to <SOURCE_QUBE> (or to another dedicated VM like the oft-used ‘vault’ VM). Eg.:
    • passwords: copy/paste from/to KeepassX (or one of its forks).
    • bookmarks: copy/paste from/to
      • a plain text file
      • or an html bookmark file (most browsers can export/import such file)
      • or a dedicated bookmark manager like buku (command line manager, available in Fedora 28 repo - dnf install buku).
  • other content/changes will have to be copied, usually to the dispVM templateVM. Care must be taken not to replicate compromised files: working with a freshly started dispVM and performing only the required update actions before synchronizing files with the templateVM is a good idea.

Using “named” dispVMs

If for some reason a user needs to have use a dispVM with a given name - which is for instance handy when using allow RPC policies - he/she can do like so (replace fedora-28-dvm with the dvm template you want to use):

qvm-create -C DispVM -t fedora-28-dvm -l red <TARGET_QUBE>

This VM works like a regular VM, with the difference that its private disk is wiped after it’s powered off. However it doesn’t “auto power off” like random dispVMs so it’s up to the user to power off (and optionally restart) the VM when he/she deems necessary.


Credits: @raffaeleflorio, Micah Lee


This document was migrated from the qubes-community project
  • Page archive
  • First commit: 26 Sep 2018. Last commit: 24 Jan 2020.
  • Applicable Qubes OS releases based on commit dates and supported releases: 3.2, 4.0
  • Original author(s) (GitHub usernames): awokd, taradiddles, SvenSemmler
  • Original author(s) (forum usernames): @taradiddles, @sven
  • Document license: CC BY 4.0
7 Likes

Very good stuff!

I shall humbly add an extension that I just trialed:

after setting up mybrowser.desktop as the default browser, which the above guide outlines, one may want to have files open in disposables as well, perhaps from specific applications, which don’t necessarily have this functionality, or open the files that would be opened by those applications in another VM directly, bypassing that application completely.
Note something like this will likely eventually make it into QubesOS with a nice GUI (see here), and there is also another guide with a bit of a different approach here, but maybe someone will find the following useful also (the main difference to the guide in the last link is that this will allow you to create your own mimetype list only for those applications you choose and I’ve found that there are some mimetypes that the list in that guide misses, though they’re not necessarily relevant in most situations):

  1. create new file in .local/share/applications, e.g. dvmviewer.desktop with same content as the desktop file in the above guide.
  2. replace the content of the field Name= in that file with something else, e.g. Name=dvmviewer
  3. open the desktop file of an application whose mimetypes you want opened somewhere else (look for desktop files in /usr/share/applications/)
  4. copy the parts of the Categories field in that file that aren’t already in your desktop file and add them to the existing parts in your file.
  5. copy the entirety of the MimeType= field’s contents and save them to a file, e.g. mimetypes.
  6. repeat steps 3 to 6 for all applications whose mimetypes you want handled in a different VM, simply adding to the file mimetypes, without creating new lines, so have it be one big line
  7. now we need to sort and deduplicate the file mimetypes; for that execute cat mimetypes | tr ';' '\n' | sort -u | tr '\n' ';' > mimetypes_deduped and copy the contents of the mimetypes_deduped file as the content of the MimeType= field in your desktop file
  8. now we set the VM to regard your desktop file, which launches some VM, e.g. a disposable, as the default application for all those mimetypes: execute cat mimetypes_deduped | tr ';' '\n' | while read -r line; do xdg-mime default dvmviewer.desktop $line; done

Opening a file of the processed mimetype, whether from nautilus / thunar or via xdg-open should now automatically open in the specified VM.

1 Like

@taradiddles could you please fix the links to the Qubes OS Docs?
There is a wrong substring forum. is all links which points to the offical Docs.
i. e.

…

Thank you

Since this guide is a wiki, I think you should be able to edit it yourself @whoami :eyes:

1 Like

Thanks for the hint! I will do it…

Suggestion: mention the --view-only option for qvm-open-in-vm to ensure no changes will get back to the source qube.

3 Likes

Suggestion: fix qubes-url-redirector to remove splash screen and make configurable defaults.

1 Like

:pray:t3: yes PLEASE

These are all already set by default in my Thunderbird based on f39-xfce, checked via config editor. Yet, clicking on a link in email opens Thunderbird qube’s Firefox, not asking me how I would want to open link.

My RPC is also by default set to

qubes.OpenURL * @anyvm @dispvm allow

What am I missing?

It would be nice if open-www-browser in anon-whonix could let me select where to open.

I was trying to scope qvm-open-in-vm requests from a system to be user selectable between dvm localnet only, dvm with no network, and dvm with full networking.

I tried things like the following in /etc/qubes/policy.d/90-default.policy:

qubes.OpenInVM * @work-mutt @dispvm:debian-11-dvm-localnet-only allow
qubes.OpenInVM * @work-mutt @dispvm:debian-11-dvm-no-networking allow

and

qubes.OpenURL * @work-mutt @dispvm:debian-11-dvm-localnet-only allow
qubes.OpenURL * @work-mutt @dispvm:debian-11-dvm-no-networking allow

then in work-mutt I tried:

qvm-open-in-vm @dispvm:debian-11-dvm-localnet-only /etc/hosts

and

qvm-open-in-vm @dispvm:debian-11-dvm-localnet-only http://google.com

It didn’t work, but it didnt give a error. I tried rebooting, but all it seemed to do is break cut and paste and some other stuff. (Note: I fixed cut and paste by reverting /etc/qubes/policy.d/90-default.policy and rebooting)

Anyone have some thoughts as to what’s going on? (or anyone know how to find error messages for it? /var/log/qubes of dom0 seems to not have anything)

Change @work-mutt to work-mutt in policies.

That was it! Thanks

For anyone interested, instead of presenting the following in the “90-default” policy file successfully locks down the qvm-open-in-vm options of a qube to disposables with 4 different network options (in this example the qube is “work-mutt”).

# Open a file in a VM
qubes.OpenInVM           *           work-mutt          @dispvm:debian-11-dvm-localnet-only      ask
qubes.OpenInVM           *           work-mutt          @dispvm:debian-11-dvm-no-networking      allow
qubes.OpenInVM           *           work-mutt          @dispvm:whonix-workstation-dvm2          ask
qubes.OpenInVM           *           work-mutt          @dispvm:debian-12-dvm-full-internet      ask
qubes.OpenInVM           *           work-mutt          @anyvm      deny

qubes.OpenInVM          *           @anyvm          @dispvm     allow
qubes.OpenInVM          *           @anyvm          @anyvm      ask

# Open URL in a VM
qubes.OpenURL           *           work-mutt          @dispvm:debian-11-dvm-localnet-only      ask
qubes.OpenURL           *           work-mutt          @dispvm:debian-11-dvm-no-networking      allow
qubes.OpenURL           *           work-mutt          @dispvm:whonix-workstation-dvm2          ask
qubes.OpenURL           *           work-mutt          @dispvm:debian-12-dvm-full-internet      ask
qubes.OpenURL           *           work-mutt          @anyvm      deny

qubes.OpenURL           *           @anyvm          @dispvm     allow
qubes.OpenURL           *           @anyvm          @anyvm      ask

Then in work-mutt doing the following should pop up and ask you which of the 4 network options you want for your dvm.

user@work-mutt:~$ qvm-open-in-vm @dispvm:debian-11-dvm-localnet-only http://google.com
user@work-mutt:~$ qvm-open-in-vm @dispvm:debian-11-dvm-localnet-only /etc/hosts

Obviously this requires having already set up disposable templates called the following:

  • debian-11-dvm-localnet-only
  • debian-11-dvm-no-networking
  • whonix-workstation-dvm2
  • debian-12-dvm-full-internet

one way to set up debian-11-dvm-localnet-only is:

  1. clone sys-firewall to sys-firewall-localnet-only
  2. edit settings for sys-firewall-localnet-only , go to firewall rules and select “Limit outgoing connections to …” then add your local network (examples: 192.168.0.0/16, 10.0.0.0/8, etc)
  3. clone your disposable template to debian-11-dvm-localnet-only, and set its network to be sys-firewall-localnet-only

(note: I could have changed the name from “debian-11-dvm-localnet-only” to something else, but to avoid ending up wtih inconsistent instructions, i left it.)

1 Like

There is no need to create a separate sys-firewall for it, you can just configure the firewall rules for the disposable template and they will be applied for the disposable qubes based on it as well.

I feel like if rules are specified per-VM, that it could make firewall configuration mistakes non-obvious, since it’ll probably be one of just a few common choices (localnet, tor, no network, or full internet).

Maybe that’s just me though.

If you plan to use the same rules for many qubes then it’s a good option.
I’ve also submitted an enchantment request for this case:

I know what you mean, but Wow. I never realized how much cooler enchantment request sounds then enhancement request! :slight_smile:

similar