GSettings/dconf reports incorrect values on setting change

Bug #1661626 reported by Michael Sheldon on 2017-02-03
10
This bug affects 1 person
Affects Status Importance Assigned to Milestone
Snapcraft
Medium
Marcus Tomlinson

Bug Description

When reading a gsetting value from a change signal, this value is not updated correctly. This can be demonstrated with the following snap: https://code.launchpad.net/~michael-sheldon/+junk/snap-gsettings-test which uses the "gsettings" interface.

The script in the snap uses "gsettings monitor" to report changes to the gsettings values

When the script is run outside of a snap it outputs the following values:
'fr'
active-language: 'en'
'en'
active-language: 'de'
'de'
active-language: 'fr'
'fr'

However when run in a snap it outputs:
'fr'
active-language: 'fr'
'en'
active-language: 'fr'
'de'
active-language: 'fr'
'fr'

Explicit requests to read a key from gsettings results in the correct value being returned, but the changes reported by gsettings are never updated.

The same behaviour can be replicated using "dconf watch" instead of "gsettings monitor", suggesting the underlying problem is with dconf usage within snaps. I've noticed that dconf appears to use both the user's real dconf settings in ~/.config/dconf/user and the snap specific settings in ~/snap/gsettings-test/<version>/.config/dconf/user so I suspect the two copies end up out of sync and one is being used when reporting changes whereas the other is used when requesting a value directly.

Also, there are no apparmor or seccomp denials reported in the system log when running this snap.

description: updated
desrt (desrt) wrote :

I have a feeling this has to do with the shm file in the xdg runtime directory. This is how the service signals to clients that the database has changed and needs to be re-opened (otherwise they will continue to use the old copy). If this is not being shared correctly between the snap and the outside work (different XDG_RUNTIME_DIR setting?) then dconf isn't going to report changes properly.

Zygmunt Krynicki (zyga) wrote :

I'm marking this bug as triaged/medium and will ask the desktop team to investigate.

Changed in snappy:
status: New → Triaged
importance: Undecided → Medium
affects: snappy → snapd
tags: added: destkop
tags: added: desktop
removed: destkop
Changed in snapd:
assignee: nobody → Marcus Tomlinson (marcustomlinson)

I think Michael was onto something with his theory of two dconf/user files falling out of sync.

~/snap/gsettings-test/current/.config/dconf/user is not the problem as that is simply a symlink to ~/.config/dconf/user, however, upon running the snap, another empty dconf/user file is created under XDG_RUNTIME_DIR (/run/user/UID/snap.gsettings-test/). It looks like this file may be the cause of the headache.

On a hunch, I tried copying ~/.config/dconf/user to /run/user/UID/snap.gsettings-test/dconf/, and the gsettings monitor output began to work!

Now, I'm not sure if doing that ^ is the correct fix really. I wonder if something with more dconf knowledge could demystify this further.

Jamie Strandboge (jdstrand) wrote :

desrt said this:

"I have a feeling this has to do with the shm file in the xdg runtime directory. This is how the service signals to clients that the database has changed and needs to be re-opened (otherwise they will continue to use the old copy). If this is not being shared correctly between the snap and the outside work (different XDG_RUNTIME_DIR setting?) then dconf isn't going to report changes properly."

On irc it was discussed that while we do a symlink from ~/snap/gsettings-test/current/.config/dconf/user to ~/.config/dconf/user, we aren't doing anything to account for XDG_RUNTIME_DIR being set to /run/user/<uid>/snap.<name> in the snap and /run/user/<uid> outside the snap. Marcus said on IRC he tried to symlink from /run/user/<uid>/snap.<name>/dconf to /run/user/<uid>/dconf, but said that didn't work, which is odd, so maybe dconf is ignoring the symlink, uses a hard-coded value, it was a timing thing when the symlink was setup, etc.

I suspect when we move to bind mounting /run/user/<uid>/snap.<name> onto /run/user/<uid> and leaving XDG_RUNTIME_DIR alone (ie, as /run/user/<uid>) this will be fixed (so long as we account for dconf when doing this), but that change, AIUI, is not going to be immediate, so this probably needs more investigation.

Changed in snapd:
assignee: Marcus Tomlinson (marcustomlinson) → James Henstridge (jamesh)
James Henstridge (jamesh) wrote :

This is probably something for snapcraft-desktop-helpers and the gnome extension for Snapcraft. It is the desktop-launch script that currently symlinks ~/.config/dconf to the location the snap will look for it, so it wouldn't be much of a stretch to do the same for $XDG_RUNTIME_DIR/dconf too. The "gsettings" interface looks like it already grants the required AppArmor permissions, so I don't think there is anything strictly necessary to do on the snapd side.

Longer term, we probably want to deprecate the gsettings interface and stop snaps from talking to dconf all together. If you're using a new enough version of GLib in the sandbox and portal support is enabled (i.e. GTK_USE_PORTAL=1 set in environment), then the GSettings API will use store settings in a flat file "$XDG_CONFIG_HOME/glib-2.0/settings/keyfile". Change notification is handled via an inotify watch on that file, comparing new values with those stored in memory.

This means that (a) the confined app can't see settings belonging to other applications, and (b) that data will be managed together with other snap user data. For the few desktop wide GSettings used by GTK's Wayland backend (e.g. theme, fonts, etc), there is an xdg-desktop-portal interface giving read-only access. Access to the portal API is already granted by snapd's desktop interface.

Sure symlinking ~/.config/dconf/user to $XDG_RUNTIME_DIR/dconf/user doesn't seem like much of a stretch, but unfortunately it just doesn't work. In fact, the output is even worse with the symlink in place (neither get nor set seem to work anymore):

'en'
active-language: 'en'
'en'
active-language: 'en'
'en'
active-language: 'en'
'en'

I don't see any apparmor denials in the journal either.

As mentioned in comment #3, I have to copy the user file from ~/.config/dconf to $XDG_RUNTIME_DIR/dconf for things to work. I really don't know why, hence my request for someone with more dconf knowledge to help demystify it :/

One guessplanation for why this may work is:

If SET calls try to write to both ~/.config/dconf/user and $XDG_RUNTIME_DIR/dconf/user consecutively, when the latter is a symlink to the former, the latter could be failing as it tries to open an already open file.

Secondly, it would seem that "gsettings monitor" and "dconf watch" particularly poke at the user file in $XDG_RUNTIME_DIR/dconf, while GET calls poke at the one in ~/.config/dconf (via the symlink in ~/snap/<snap_name>/... I assume).

The above could explain why, if you copy the user file from ~/.config/dconf to $XDG_RUNTIME_DIR/dconf on each launch of the snap, not only do the monitored SETs and GETs work as they should during execution, but all changes made to the settings correctly persist between those launches.

This is what I propose: https://github.com/ubuntu/snapcraft-desktop-helpers/pull/201/files

I've tested this ^ against Michael's gsettings-test snap (slightly modified [1]), and all looks to be working as expected now.

I would appreciate any assistance in testing / reviewing this.

[1] https://code.launchpad.net/~marcustomlinson/+git/gsettings-test/+ref/master

Changed in snapd:
assignee: James Henstridge (jamesh) → Marcus Tomlinson (marcustomlinson)
status: Triaged → In Progress
affects: snapd → snapcraft
summary: - GSettings/dconf reports incorrect values on setting change under
- confinement
+ GSettings/dconf reports incorrect values on setting change
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers