Classic confinement request: communitheme-set-default


I’m requesting to set the newly communitheme-set-default snap as a classic snap.

Some people were wondering how to reset default values in gsettings key and update GDM login screen to use communitheme (from the communitheme snap).

The first one can be done via the gsettings plug, however, the second one (changing GDM login screen) relies on update-alternatives as the root user.

For that use case, we need thus this package (simple shell script, arch: all) to be a classic snap so that it has access to host /etc/alternatives.

The split between communitheme snap and communitheme-set-default is on purpose so that only the latter one needs to be a classic snap.


+1 though I’d tweak the name to something more generic, how about communitheme-tweak-tool?


I don’t think we want to allow tweaking, but only providing the default communitheme experience before having it by default. So, it’s more a tool to “reset & clean” than encouraging particular tweaks (and I think, we should limit it to this)


@niemeyer - can you weigh in on this one? It seems like an ‘administrative’ type of request, but the request is very limited in scope and seems allowable.


@niemeyer - can you give feedback on it. I’m inclined to allow it but want you to at least be aware.


+1 I find it very helpful since I’m following the development on the --edge channel and need to be sure I have the default setting before reporting some issues .

Totally agree with @didrocks .



This will help users fix configuration errors and help filing bug reports.


@niemeyer - what do you think?


@jdstrand @didrocks Is this a snap getting classic confinement to configure the system for a third snap? That requires some consideration indeed.

What are the actual operations that require the classic support? update-alternatives makes it sound like a command is being changed, which isn’t generally required by a theme.

Can we have some more details about the operation?


@niemeyer: This snap configure the arch:all communitheme snap. We need to have communitheme theme as arch: all for multiple reasons:

So, basically, we can’t ship the “dconf” binary for resetting in communitheme snap itself, and we need to a way to access /etc/alternatives symlinks. Indeed, as detailed on planet ubuntu, the gdm theme selection is selected via update-alternatives, more info on Some people wants to set it and don’t know how to use update-alternatives properly. I don’t think we have an interface to access and update the host /etc/alternatives, correct? This is why this request for classic confinement here.

I hope that sheds some lights on it!


@didrocks Thanks for the details.

What permission can we offer the real snap that would enable it to do the job it needs to do? Can we dig a bit deeper on that?

As I understand it, it needs:

  1. update-alternatives
  2. dconf

In both cases, what specific paths does it need access to for performing those tasks? The best alternative here may well be to simply implement the interfaces you need.

@jdstrand Ideally we’d be able to confine not only to “update-alternatives” but “update-alternatives of that executable”.


Thanks for the answer!

So, basically, dconf is only the gsettings plug already, so this isn’t what is really blocking on the classic confinement request.

Stands thus update-alternatives. This one access /etc/alternatives/ directory, in particular the gdm3.css alternative file (so it doesn’t match the binary and can’t really, as it’s not gdm, but we want to configure the gdm theme). Alternatives aren’t necessarilly for executables, but abitrary files as well (like the theme one in that case), so a mapping may be difficult to be systematic for that particular case.

Stracing that utility and omitting linkers and such, it seems that it doesn’t access that much files, once you filter the locales out (that you don’t see in non interactive mode for my specific case), remains:
/usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache and log files /var/log/alternatives.log that we probably want to be written on the system itself, as it impacts the global system state.


@didrocks That sounds relatively straightforward. We probably need read access on /var/lib/dpkg/alternatives/<name>, and write access to /etc/alternatives/<name> and possibly the log file as you suggest. The interface might look similar to:

            - gdm3.css

The update-alternatives command itself will need to be run with the --altdir, --admindir, and --logdir options pointing to the host filesystem, unless the tool can read its directories from the environment. Can it?

@jdstrand What do you think?


@niemeyer - I took a look at this and I think this needs a good bit of design consideration (sorry for the long reply, but it is necessary).

snap calling update-alternatives directly

First off, I looked at the accesses required if a snap is allowed to run update-alternatives directly and noticed that for --install/–remove/–query/–display/–list without --altdir/–admindir, a snap running update-alternatives itself requires:

/{,usr/}bin/update-alternatives ixr,
# --install /usr/share/gnome-shell/theme/gdm3.css gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css 15
# --remove gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css
/etc/alternatives/gdm3.css{,.dpkg-tmp} rw,
/usr/share/gnome-shell/theme/gdm3.css{,.dpkg-tmp} rw,
/var/lib/dpkg/alternatives/gdm3.css{,.dpkg-tmp} rw,
/var/lib/dpkg/alternatives/ r,
/var/lib/dpkg/alternatives/* r,
/var/log/alternatives.log w,

Using --altdir /var/lib/snapd/alternatives/alt --admindir /var/lib/snapd/alternatives/admin, then the snap would instead need:

/{,usr/}bin/update-alternatives ixr,
# --altdir /var/lib/snapd/alternatives/alt --admindir /var/lib/snapd/alternatives/admin --install /usr/share/gnome-shell/theme/gdm3.css gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css 15
# --altdir /var/lib/snapd/alternatives/alt --admindir /var/lib/snapd/alternatives/admin --remove gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css
/var/lib/snapd/alternatives/admin/ r,
/var/lib/snapd/alternatives/alt/gdm3.css{,.dpkg-tmp} rw,
/usr/share/gnome-shell/theme/gdm3.css{,.dpkg-tmp} rw,
/var/lib/snapd/alternatives/admin/gdm3.css{,.dpkg-tmp} rw,
/var/log/alternatives.log w,

I then thought, “what if we put --altdir, --admindir and --log in in $SNAP_COMMON”? This reduces the apparmor profile changes to:

/{,usr/}bin/update-alternatives ixr,
/usr/share/gnome-shell/theme/gdm3.css{,.dpkg-tmp} rw,

Note, I looked at dpkg in bionic and found that ADMINDIR_ENVVAR can be used for --admindir, but there is nothing for --altdir or --log.

In considering the above, I noticed several considerations with the general approach of letting a snap execute update-alternatives directly:

  1. when using non-default values for --admindir, --altdir and --log, non-snap invocations of ‘update-alternatives’ is unaware of these alternate locations. While the symlink is setup correctly, this could confuse administrators and users. In the case of gdm3.css where there is already an alternative defined in bionic, update-alternatives with default options would be ignorant of the snapd --altdir/–admindir and vice versa
  2. if the snap is running update-alternatives, there is no guarantee that the snap will DTRT on snap removal which could result in a dangling symlink potentially breaking the software (eg, will gdm3 continue to function correctly if /usr/share/gnome-shell/theme/gdm3.css is a dangling symlink?)
  3. if the snap is running update-alternatives, there is no guarantee it will setup the alternative correctly. This could result in a dangling symlink or a malformated/ill-configured file in --admindir
  4. the snap running update-alternatives itself requires 'w’riting out to an arbitrary location for managing the target symlink (eg, /usr/share/gnome-shell/theme/gdm3.css{,.dpkg-tmp}) and this file is not guaranteed to be in the snap’s mount namespace
  5. update-alternatives and its --altdir/–admindir directories don’t exist in the snap’s mount namespace
  6. cannot mediate the update-alternatives ‘priority’ with security policy
  7. update-alternatives is a command only available on dpkg-based systems and doesn’t exist in the core snap or non-dpkg classic systems
  8. the alternatives mechanism could allow for sandbox escape. Eg, in this case, the snap is allowed to put anything into the css which is processed by an unconfined, privileged process. Consider other cases like someone creating an alternative for ‘/etc/bash.bashrc’ which is sourced in the user’s unconfined shell

To address 2-4, we could simply say that the interface needs manual connection and follow the normal process for issuing snap declarations. If we are going this route, 1 is simply addressed by always using the global database. ‘5’ could be handled a number of ways (eg, adjust snap-confine to mount these files/directories from the host or core ships update-alternatives that uses /var/lib/snapd/hostfs/… for its --altdir/–admindir). 6 cannot be addressed since the priority is defined in the file that is placed in the --admindir, which is writable by the snap (ie, have to trust the snap to DTRT). 7 could potentially be addressed by core shipping an update-alternatives that is a no-op on non-dpkg systems.

In all, I think it is possible to allow the snap to do this using:

      original: /usr/share/gnome-shell/theme/gdm3.css
      target: /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css
    other.file:           # 'name' from 'man update-alternatives'
      original: /usr/...  # 'link' from 'man update-alternatives'
      target: $SNAP/...   # 'path' from 'man update-alternatives'

snapd then looks at the above and adjusts the apparmor profile and mount namespace accordingly. The snap then is allowed to do these commands itself to manage the alternative:

# install
(root)$ update-alternatives --altdir /var/lib/snapd/alternatives/alt --admindir /var/lib/snapd/alternatives/admin --install /usr/share/gnome-shell/theme/gdm3.css gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css 15

# remove
(root)$ update-alternatives --altdir /var/lib/snapd/alternatives/alt --admindir /var/lib/snapd/alternatives/admin --remove gdm3.css /snap/communitheme/current/share/gnome-shell/theme/communitheme/gnome-shell.css

Doing it this way is possible, but again, priority is unmanaged by snapd, the system is somewhat brittle, it all requires a decent amount of trust in the snap to DTRT and requires the developer to have a pretty deep understanding of the update-alternatives dpkg mechanism.

snapd calling update-alternatives on the snap’s behalf

A much more robust implementation would have snapd call out to update-alternatives itself which addresses all of the above shortcomings except ‘8’ (confinement escape) since the snap has no additional access to the system alternates files, arbitrary files, etc and because snapd can ensure that the alternate files have sane values and no dangling symlinks. I can think of a few ways to handle this:

  1. snap declares some snap.yaml and calls a snapd-supplied update-alternatives which talks to snapd over DBus/unix socket/something
  2. snap only declares some snap.yaml and snapd takes care of the rest
  3. snapd only understands certain alternatives (eg, only ‘gdm3.css’) instead of being a general purpose alternatives mechanism (potentially address confinement escape depending on how strict we are with adding new alternatives)

IMHO, ‘2’ and ‘3’ are more inline with the design principles of snapd. We could sketch out what this could look like in yaml, but ultimately I think we need to define some requirements and design the whole thing properly. For whoever would pick this up, here are some questions I think need answers before designing the feature:

  • should the system support only specific alternatives or be totally generalized (ie, option ‘3’ vs anything else)
  • should the system support more than just dpkg-based systems?
  • how much of update-alternatives do we want to expose to the user? ‘man update-alternatives’ has a lot of options for example (ie, option ‘1’ vs anything else)
  • can a snap setup an alternative to something that isn’t part of its snap? In the case of communitheme-set-default, it is setting the alternative to point to something in the ‘communitheme’ snap and not ‘communitheme-set-default’
  • should there by a ‘snap alternative …’ command that the user can use to do things, like add/remove/config an alternative that the snap setup?


One thing I failed to mention is that this hostfs path is going to be highly classic-distro dependent. Eg, there is no guarantee that Ubuntu’s gdm3 is the same as Debian’s is the same as Mint’s is the same as…


Note that alternatives are not supported by all distros out there (RH invented it and debian adopted it, so all derivatives of these two will likely have it, but others will/might not). So this feature should be dynamic based on the distro you install on if it is actually inside snapd …