Automate debian-minimal based template creation

You’re removing one of its depends (e.g. xdg-utils):

$ apt-cache show qubes-core-agent
Package: qubes-core-agent
Version: 4.2.26-1+deb12u1
Architecture: amd64
Maintainer: unman <unman@thirdeyesecurity.org>
Installed-Size: 729
Depends: apt-transport-https, dconf-cli, dmsetup, gawk, graphicsmagick, init-system-helpers, initscripts | sysvinit-utils, librsvg2-bin, locales, ncurses-term, psmisc, procps, util-linux, e2fsprogs, parted, python3-daemon, python3-qubesdb, python3-gi, python3-xdg, python3-dbus, qubes-utils (>= 3.1.3), qubes-core-qrexec, qubesdb-vm, systemd, xdg-user-dirs, xdg-utils, xen-utils-common, xen-utils-guest, xenstore-utils, python3:any, libc6 (>= 2.34), libqubes-rpc-filecopy2 (>= 4.1.7), dconf-gsettings-backend | gsettings-backend
Recommends: cups, gnome-terminal, gnome-themes-standard, haveged, libnotify-bin, locales-all, mate-notification-daemon, ntpdate, system-config-printer, qubes-core-agent-nautilus, qubes-core-agent-networking, qubes-core-agent-network-manager, x11-xserver-utils, xinit, xserver-xorg-core, xsettingsd, xterm
Conflicts: firewalld, pulseaudio-qubes (<< 4.2.0-1), qubes-core-agent-linux, qubes-core-vm-sysvinit, qubes-gui-agent (<< 4.1.6-1)
Homepage: https://www.qubes-os.org
Priority: extra
Section: admin
Filename: pool/main/q/qubes-core-agent/qubes-core-agent_4.2.26-1+deb12u1_amd64.deb
Size: 94476
SHA256: ea13bf510002a0b80f6d0acf226f90959eb20420d2bf3eefa7beb8d358f3205c
SHA1: 431c45ad5a3891260790cf798d158f4ddfab9465
MD5sum: 56b70ef04b1c4ff9e9df4fa75761c815
Description: Qubes core agent
 This package includes various daemons necessary for qubes domU support,
 such as qrexec services.
Description-md5: d5c21beb3c25cf7972d88fc97ad4fac4
2 Likes

I am removing the exact same packages which I installed previously.

The question is - why that attempts to remove more than what they installed?

No, you are not.
xdg-utils is already installed in the template. You did not install it.
It could be that you thought you installed it, but if you had checked
the logs you would have seen that this was not so.

I never presume to speak for the Qubes team. When I comment in the Forum or in the mailing lists I speak for myself.

@unman

What do you mean? If you look at the actual command line, you can see it does not contain xdg-utils. So, I am not uninstalling that explicitly.

IIUC, some of the other packages, which are on my apt-get purge command line, depends on qubes-core-agent, and for some reason it is now considered unnecessary, so apt-get tries to remove it, thus creating this mess.

Why is this happening?

OK. I found the culprit - psmisc. It somehow ended up in my command line. Removing it from there removes all errors and purging works fine. Sorry for bothering.

Go for it and report back how it worked for you.

Here is some more feedback on the decremental approach:

I have not polished it but the it works. In regards to efficiency, it is still not quite to my taste though.

First, it increases the boot time of qubes which need less packages, due to the initial package purging. To remove the packages mentioned in a previous post and clean up, it takes about 57 s (nVME storage). If I move qube’s volatile volume to tmpfs, the time is 37 s - still a significant delay. Additionally, tmpfs volatiles come at the cost of eating RAM from dom0 - the more packages are purged, the more memory is consumed by the CoW system. That might create OOM issues if running many minimized qubes (e.g. sys-*).

The main issue is obviously that GNU/Linux and its file hierarchy are simply not designed with Qubes in mind, so both approaches increase complexity and maintenance for probably marginal benefit. Maybe ZFS could reduce duplication in the incremental approach, but the additional complexity of having multiple templates remains.

If we should go for true minimalism, we need something better. No idea what exactly though. Maybe we should consider the concept of distributed operating systems.

Wait a minute. You installed things in the Template, and in the AppVM you uninstalled them?

You will have to repeat the uninstall every time you run the AppVM, since nothing done in the system area gets saved when an AppVM shuts down. (Things you say later on I didn’t quite understand might indicate you know this.) That seems like an awful lot of writes to disk, when you could do the uninstall just once in a custom template (or better yet not install in the first place).

Wait a minute. You installed things in the Template, and in the AppVM you uninstalled them?

Yes. That’s the essence of the decremental approach.

You will have to repeat the uninstall every time you run the AppVM

Sure.

That seems like an awful lot of writes to disk

There are zero writes to disk if the volatile volume is on tmpfs and the root volume has rw=false.

The only 2 problems which remain are:

(A) The additional RAM for the CoW
(B) The extra time for uninstalling packages at each AppVM boot

(A) might not be a big problem with enough physical RAM. AFAIK, the RAM for dom0 can be increased through a GRUB parameter.

(B) seems significant only if lots of packages are removed. It is possible to have 2 templates (e.g. one for more minimalist stuff, another one for office-like bloatware) but that goes against the idea of having a single template (although 2 is still better than 20).

Another method I have tried:

In the template:

apt-get install package1 package2... --download-only

In AppVM X:

apt-get install packageX && apt-get clean

That is still incremental (nothing is actually installed in the template), and it does not solve (A) and (B). It only reverts (B) - more boot-up time for AppVMs using larger software packages. Additionally, it is not quite clear to me what would happen if a package is downloaded in cache (but not installed) and a system update is run. So, additional complication.

As a possible solution to (A) and (B), here is an ugly but effective method (note the time):

root@appvm-AAA:~ # mapfile -t files < <(dpkg -L libreoffice-calc)
root@appvm-AAA:~ # time (for i in "${files[@]}"; do if [ -f "${i}" ]; then ln -sfT /dev/null "${i}"; fi ; done)

real    0m0.177s
user    0m0.096s
sys     0m0.086s

The full test, symlinking all dependencies of libreoffice-calc as well, shows:

real    0m2.691s
user    0m1.302s
sys     0m1.280s

This also solves (A) because (IIUC) symlinking does not modify actual data blocks (resulting in CoW). My test shows that the usage of the 1 GiB RAM based pool, storing the volatile volume, is 0.07% at VM boot (before symlinking) and increases to 0.34% (after symlinking). That is less than 3.5 MiB.

There is only the additional complexity of having to symlink dependencies without damaging any common ones. For example, if package1 and package2 both depend on package3, and AppVM2 needs package2 but removes package1, the automation system should not attempt to symlink package3’s files. I need to learn how to do this (tips are welcome).

Although this is somewhat hacky (and I don’t know if there may be any side effects), it should work for the purpose of reducing the attack surface (the whole point of the current multi-template exercise). No files = nothing to attack, so as long as rc.local runs early enough, we should be OK. With this approach we can have just an unitary template, where we can install whatever we plan to use, and multiple custom-minified AppVMs.

What do you think?

(I am still working on the automation system, so it is not quite polished yet. Maybe something new will come out along the way)

1 Like

As far as I know, your uninstalled package won’t be updated. So basically the next time you run the VM and install the package, it’s out of date unless you also run updates on starting the VM (which would be a miserable experience). But that’s moot since I don’t even know how to do that, because as far as I know QubesUpdates works on Templates, not AppVMs. (Someone can certainly correct me if I am wrong.)

In what you quoted, I was talking about the case in which a packages is not installed in the template (and hence not uninstalled in the AppVM). It is only downloaded and stored in apt-get’s cache (in the template), then AppVMs install selectively at boot whatever they need. So, in regards to that scenario, I was wondering what would happen to the cache if the template receives an update and what control mechanisms over that exist, i.e. whether:

  • the cache is simply discarded
  • the cache gets updated too (that would align with the goal)
  • the cache becomes outdated compared to the actual current package version (that would require some additional work to make sure an updated packages is re-downloaded and stored in cache again)

I am not a Debian expert, so I don’t know how that works.

1 Like

As far as I know an uninstalled package (and it won’t be installed on your template) doesn’t get updated. You’ll just have to download it again…and that brings up the question of how you will know that you need to do that.

I don’t know whether it is appropriate to call it uninstalled (in the sense: installed and then removed), if it will never be installed in the template and will never be removed in the AppVM. As for the rest, it should be possible to check and compare the version on the repo and the version in local cache, then act accordingly. However, considering this whole approach does not solve (A) or (B), for the moment I am working on the symlinking one.

Has anyone found solution for KeePassXC? It’s qt5 app and I’m not fond of installing adwaita and qt5ct for such a sensitive app…

Yes, here:

More precisely hereafter:

1 Like

I just did some further improvements to fix / adjust the QT font size issue.

You need to install qt5ct and set QT_QPA_PLATFORMTHEME=qt5ct in your environment file.

Unfortunately…

What do you think: would

export QT_FONT_DPI=144
solve the problem? I just need font size…

I tried this first, it did not work.

1 Like