Prevent Qubes OS clearnet leaks

Introduction

:warning: This setup is only useful for people who want to block non-VPN / non-Tor traffic.

By default, Qubes OS checks for updates of qube’s templates using running qubes themselves generating traffic through their current netvm. To some people, this can be seen as a privacy issue because queries Qubes OS’s packages repository, which immediately flag the user as a Qubes OS user.

Even if you use sys-whonix or a VPN qube for all your qubes, there are 3 qubes that could leak network because they are before the VPN/Tor in the netvm chain:

Related to Qubes Global Config: "Disable checking for updates for all existing qubes" no longer true after new qubes are subsequently created; unclear how to reapply setting · Issue #9338 · QubesOS/qubes-issues · GitHub

Explanations

The idea is to block all traffic generated by sys-usb, sys-firewall and sys-net, but still allow them to route traffic for Qubes so network still work. Although sys-usb should not have network, it is actually configure as a “providing network” qube for when you plug in an USB network adapter.

This is a software solution, this can not guarantee against leaks after an update or a misconfiguration. For a more leak-proof solution, the user should use a hardware gateway between Qubes OS and the real network to be block any unwanted traffic leak.

:information_source: Disabling update check for these qubes may be enough. But an extra security is to block all traffic.

Setup

Disable update check

Run the commands in a terminal from dom0:

qvm-service sys-firewall qubes-update-check off
qvm-service sys-net qubes-update-check off
qvm-service sys-usb qubes-update-check off
qvm-service default-dvm qubes-update-check off # just in case

Disable network done by sys-usb / sys-firewall / sys-net

Add this to the file /rw/config/rc.local in the template named default-dvm:

if [ "$(qubesdb-read /name)" = "sys-firewall" ] || [ "$(qubesdb-read /name)" = "sys-net" ] || [ "$(qubesdb-read /name)" = "sys-usb" ]
then
    sudo nft add chain ip qubes output '{type filter hook output priority 0; policy drop; }'
    sudo nft add chain ip6 qubes output '{type filter hook output priority 0; policy drop; }'
fi

Restart the qubes.

sys-net is not a disposable qube

If your sys-net is not disposable, apply the same instructions as explained for default-dvm but in the qube sys-net.

Warning

  • this has not been tested extensively, this may lack leakage fixes (if any please report)
  • this might break DNS for qubes using sys-firewall/sys-usb/sys-net as the netvm
  • you need to configure the Update proxy in “Qubes Global Config” in “Updates” tab to a qube that is not sys-firewall/sys-usb/sys-net:
    • Dom0 update proxy
    • Default update proxy
4 Likes

I would replace hostname -s with qubesdb-read /name instead, especially for sys-net. Sometimes the hostname is not sys-net but an IPv6 address based on the user setup.

3 Likes

Great, thanks

1 Like

Needs another (ip6) rule to cover IPv6 too, I think?

Also this could still leak during startup of sys-net etc., because rc.local(.d/) is run by the qubes-misc-post.service systemd unit which doesn’t have an ordering before network-pre.target.

In R4.3 there’s a new rc.local-early(.d/) run by qubes-early-vm-config.service which does have the ordering. Not backported to R4.2 yet, but it’s just a small self-contained change to /usr/lib/qubes/init/qubes-early-vm-config.sh in the TemplateVM:

1 Like

Thanks for this info! I saw the announcement for R4.3 in one of @alimirjamali 's weekly updates and will definitely test now on R4.2.

Indeed I forgot to mention this does not prevent IPv6.

For the fix in the shell script, I don’t like this, it could easily be overwritten by Qubes OS if the package holding the file is updated? An override mechanism through systemd would be better, like a postexec

1 Like

I updated the instructions, it’s now blocking IPv6

I often chattr +i a file after this kind of change to ensure any package update that would clobber the file fails and I can sort it out again. Although for qubes-early-vm-config.sh I’m guessing that if it’s ever updated, the update would include the backport anyway.

BTW if the nft commands are indeed moved to rc.local-early(.d/) they’d be running concurrently with qubes-iptables, so the qubes tables might not exist yet.

Making a file immutable could be bad too because if the file has a security vulnerability that has to be fixed through an update, it won’t be updated.

Yeah but in this case the whole package/system update fails noisily. It doesn’t just silently skip the file.

with both apt and dnf?

Both, yes. Although chattr +i is probably still too hacky to recommend, because both dnf and apt will fail qubes-core-agent package updates even if the immutable file’s content hasn’t changed at all.

@marmarek Could you cherry-pick the two rc.local-early(.d) commits for R4.2?

Another approach could be to inject the new line in the script at shutdown time using a systemd oneshot service. I’ve been doing it in another project and it’s reliable.

Disable network done by sys-usb

sys-usb has no net qube. How does it “do network” (and leak)?

1 Like

sys-usb has the “provides network” check enabled, because you can use it as a network VM if you plug USB network adapter.

I wrote it in my initial draft, and it got lost… I’ll update

2 Likes

Come to think of it, this functionality (cleanly blocking IPv4/IPv6 output traffic) seems like a good thing to include in the actual qubes-core-agent package as part of the qubes-iptables script that creates the qubes tables. It could be enabled per VM through a qvm-service or something

2 Likes

Hear, hear!
QubesOs development is just coasting on, propelled by inertia, propagating wrong decisions which may have looked right 15 years ago but are still wrong and correctable today.

1 Like

sys-usb has the “provides network” check enabled, because you can use it as a network VM if you plug USB network adapter.

I see.

Wouldn’t it be wiser (and “the qubes way”) to have a firewall qube between the client and sys-usb then, instead of relying on an in-qube (in-sys-usb through the DVM template) firewall rule? What I mean is - if we are concerned that sys-usb can leak, then why should we trust it to guard us from those same leaks through a firewall rule (based on its hostname) which is in its control only? Or am I missing something?

This guide will make you run into `qubes-vm-update` should automatically use `--force-update` when `qubes-update-check` is disabled · Issue #9749 · QubesOS/qubes-issues · GitHub / you’ll have to use qubes-vm-update --force-update.

1 Like

Yes, but in most cases people would use either sys-net or sys-usb, not both. Sys-firewall could be reallocated.

Having a sys-firewall-usb by default might be confusing maybe?