So, I learned an “interesting” (read: disturbing) fact about VirtualBox’s resolution “auto-resize” feature while trying to add a privacy feature to vm-config-dist’s wlr_resize_watcher utility. Some backstory for the feature itself:
Previously the utility always resized the compositor’s resolution to match that of the virtual display, but during wiki auditing I noticed that we previously had a feature where Whonix’s display resolution was locked to 1920x1080. This helped anonymity, since malware that infected the workstation wouldn’t be able to see anything unique about the VM’s display resolution, and browsers would be less likely to leak a unique or odd resolution to websites. That feature got lost somewhere along the line (I think it was missing even from the X11 session, but it’s certainly missing from the Wayland session), so after some discussion with Patrick I set out to implement it.
wlr_resize_watcher gets the resolution of the virtual display from /sys/class/drm/card*/modes (where * is a wildcard). There is one such file per display the hypervisor exposes to the guest. When resizing the guest window, the hypervisor will typically do something with the virtual display device to signal the changed display resolution. Linux then changes this modes file to list the new “real” resolution as the monitor’s native resolution, and sends a notification about the change via udev. wlr_resize_watcher currently works by detecting these udev events, reading the native resolution of the changed display, and then telling the compositor to resize the changed display’s resolution to the new native resolution.
The original plan for making this a bit more privacy-oriented was to introduce a config file option that would make wlr_resize_watcher not resize the compositor’s resolution when it detected a display resize. This is good for keeping browsers from leaking info about the user, but it doesn’t help if malware infects the workstation, since that malware can simply read the same sysfs file wlr_resize_watcher is looking at and get the display’s real resolution anyway. To mitigate that, we decided to add a notification that would tell the user that they should disable the automatic resolution resize feature of their hypervisor. The idea is that once the automatic resolution resize feature is disabled, the virtual display’s native resolution should change to the actual resolution of the host (edit: meant window, not host), and thus the user’s anonymity is better preserved.
This sounds great on paper, but when actually implementing it, I discovered VirtualBox makes it ridiculously hard to banish a non-generic (and thus fingerprint-able) resolution from the modes file. (I’m sure this is unintentional, but it’s nonetheless true sadly.) Basically what happens is:
- The VM’s display resolution is saved in the VirtualBox VM’s XML, generally under
~/VirtualBox VMs/Whonix-Workstation-LXQt/Whonix-Workstation-LXQt.vbox, in anExtraDataitem calledGUI/LastGuestSizeHint. If you attempt to reboot to clear a non-standard resolution from the VM, it won’t work because that non-standard resolution is stored in the XML and will be restored to the VM on boot. - Clicking
View -> Adjust Window Sizewill resize the virtual display’s size to the compositor’s resolution, but the non-standard resolution will still be present in themodesfile!. - If you try to resize the guest window just a tiny bit, you’ll discover that you can get the native resolution to change to anything except one of the generic values elsewhere in the list (like 1920x1080). If you land exactly on a generic value, the native resolution will be left on the last non-standard value.
- Even if you do manage to get the display to land exactly on 1024x768 via careful adjustments, the “stuck bad” native resolution is what gets saved back to the
GUI/LastGuestSizeHintvalue, meaning that the same bad resolution will be loaded on next boot.
What this boils down to is that, once the user uses VirtualBox’s “Auto-resize guest display” once, there is no way to get the guest’s apparent native resolution to ever change back to a generic resolution like 1920x1080 without modifying the guest’s extra data directly. That means either editing the XML by hand, or (probably more conveniently) using vboxmanage to change the size hint. This has to be done on the host. Even if the user changes back to a normal resolution, the last non-standard resolution will linger around theoretically forever, providing a persistent fingerprinting mechanism.
KVM / virt-manager is much better-behaved in this respect; one needs to click View -> Resize to VM to get the native resolution to actually match the compositor’s resolution. Once this is done, all the resolutions displayed in the modes file are either various generic resolutions the graphics device supports, and the native resolution of 1920x1080 listed at the top.
I’m not sure what the best solution to this is; we could document this very-easy-to-trigger-and-very-hard-to-fix footgun on the Wiki, we could integrate a fix for this into some sort of installer or maintenance tool intended for the host, or we could try to find a way to get the guest to tell VirtualBox that it really wants its resolution to be one of the generic resolutions (this might be possible by talking to the /tmp/.iprt-localipc-DRMIpcServer socket, which is what VBoxDRMClient usually uses to tell the graphics driver the guest’s current resolution. It’s unknown whether this socket accepts multiple clients though, or if it can cope with a client disconnecting and some other client connecting).