An interface to set the activation environment?

While experimenting with a confined desktop snap I found that I wanted to update the activation environment. In essence:

dbus-update-activation-environment --systemd --verbose WAYLAND_DISPLAY MOZ_ENABLE_WAYLAND XDG_SESSION_TYPE XDG_CURRENT_DESKTOP

This works in devmode, but (unsurprisingly) fails confined with:

dbus-daemon[280907]: [session uid=1000 pid=280907] Activating service name='org.freedesktop.systemd1' requested by ':1.1' (uid=1000 pid=280988 comm="dbus-update-activation-environment --systemd --ver" label="snap.confined-shell.confined-shell (complain)")
dbus-daemon[280907]: [session uid=1000 pid=280907] Activated service 'org.freedesktop.systemd1' failed: Process org.freedesktop.systemd1 exited with status 1
dbus-update-activation-environment: warning: error sending to systemd: org.freedesktop.DBus.Error.Spawn.ChildExited: Process org.freedesktop.systemd1 exited with status 1

I don’t see any existing interface that would allow this call.

Am I missing something that exists already?

Or, would this be a sensible capability to add to the desktop-launch interface?

Or, would this be something for another interface?

Hi alan_g,

Could you perhaps use snappy-debug to see what happens in terms of policy violations as described here under “Using snappy-debug to show violations”

Do you mind sharing your snapcraft.yaml content within triple quotes, to show interfaces in use?

We needed something like this for our desktop prototype too, but ended up updating the environment from an unconfined script run before we launched the confined desktop executable.

If anyone does pursue a snapd interface for this, note that it would enable a fairly trivial sandbox escape. Consider:

  1. run dbus-update-activation-environment --systemd LD_PRELOAD=$SNAP/some-lib.so
  2. make a D-Bus call that will trigger an unconfined daemon to launch (or just call StartServiceByName if one of your interfaces allows it).
  3. the daemon is started with our LD_PRELOAD, which could include an init function to run code immediately, or replace some function it expects will be called. Either way we’ve got unconfined code execution.

The same could be done with LD_LIBRARY_PATH, and probably a bunch of other environment variables.

Here’s the snappy-debug message:

= AppArmor =
Time: Mar 16 09:21:50
Log: apparmor="DENIED" operation="dbus_method_call"  bus="session" path="/org/freedesktop/DBus" interface="org.freedesktop.DBus" member="UpdateActivationEnvironment" mask="send" name="org.freedesktop.DBus" pid=329774 label="snap.confined-shell.confined-shell" peer_label="unconfined"
DBus access

The snapcraft.yaml:

name: confined-shell
adopt-info: miriway
summary: A minimal Mir based confined shell for testing support for such things
description: |
  The current iteration is based on Miriway, swaybg and wofi.
  
  To activate the wofi launcher press `Meta+a`. This will show snaps publishing a
  .desktop file, but only Wayland based snaps will run successfully.
  
  To exit the shell press Ctrl-Alt-BkSp (long press if apps are running)
  
  For the greeter (e.g. GDM) to recognise the confined-shell session run:
  
      /snap/confined-shell/current/bin/setup.sh
confinement: strict
grade: stable
base: core22

environment:
  SHELL: bash
  LC_ALL: C.UTF-8
  PATH: $SNAP/usr/local/bin/:$SNAP/bin/:$SNAP/usr/bin/:${PATH}
  # XDG config
  XDG_DATA_DIRS:   $SNAP/usr/share
  XDG_CONFIG_DIRS: $SNAP/etc/xdg
  XDG_CACHE_HOME:  $SNAP_USER_COMMON/.cache
  XDG_CONFIG_HOME: $SNAP_USER_DATA/.config
  # Prep for Mir
  MIR_SERVER_PLATFORM_PATH: ${SNAP}/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/mir/server-platform
  # graphics
  LIBINPUT_QUIRKS_DIR:       $SNAP/usr/share/libinput

layout:
  /usr/share/X11/xkb:
    bind: $SNAP/usr/share/X11/xkb
  /etc/fonts:
    bind: $SNAP/etc/fonts
  /usr/share/fonts:
    bind: $SNAP/usr/share/fonts
  /usr/bin/xkbcomp:
    symlink: $SNAP/usr/bin/xkbcomp
  /usr/share/icons:
    bind: $SNAP/usr/share/icons
  /usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0:
    bind: $SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0
  /usr/share/libdrm:  # Needed by mesa-core22 on AMD GPUs
    bind: $SNAP_COMMON/graphics/usr/share/libdrm
  /usr/share/drirc.d:  # Used by mesa-core22 for app specific workarounds
    bind: $SNAP_COMMON/graphics/usr/share/drirc.d
  /usr/share/X11/XErrorDB:   # Used by graphics-core22 for X11
    bind: $SNAP_COMMON/graphics/usr/share/X11/XErrorDB
  /usr/share/X11/locale:   # Used by graphics-core22 for X11
    bind: $SNAP_COMMON/graphics/usr/share/X11/locale
  /etc/gtk-3.0:
    bind: $SNAP/etc/gtk-3.0

apps:
  confined-shell:
    command-chain:
      - bin/run-shell
      - bin/graphics-core22-wrapper
    command: usr/local/bin/miriway
    desktop: usr/share/wayland-sessions/confined-shell.desktop
    slots:
      - wayland
    plugs:
      - login-session-control
      - x11
      - hardware-observe
    environment:
      XDG_DATA_DIRS: $SNAP/usr/share:/var/lib/snapd/desktop

parts:
  miriway:
    source: https://github.com/Miriway/Miriway.git
    override-pull: |
      craftctl default
      server_version=`git rev-list --count HEAD`
      mir_version=`LANG=C apt-cache policy mir-graphics-drivers-desktop | sed -rne 's/^\s+Candidate:\s+([^-]*)-.+$/\1/p'`
      recipe_version=`git -C ${CRAFT_PROJECT_DIR} rev-list --count HEAD`
      craftctl set version=$server_version-mir$mir_version-snap$recipe_version
      if echo $mir_version | grep -e '+dev' -e '~rc' -q; then craftctl set grade=devel; else craftctl set grade=stable; fi
    plugin: cmake
    build-packages:
      - build-essential
      - pkg-config
      - libmiral-dev
      - g++
    stage-packages:
      - libmiral5
      - mir-graphics-drivers-desktop
    stage:
      - -usr/share/wayland-sessions/miriway.desktop

  wofi:
    plugin: nil
    stage-packages:
      - wofi

  swaybg:
    plugin: nil
    stage-packages:
      - swaybg
      - ubuntu-wallpapers

  yambar:
    plugin: meson
    meson-parameters:
      - -Dbackend-x11=disabled
      - -Dbackend-wayland=enabled
    build-packages:
      - meson
      - ninja-build
      - wayland-protocols
      - libasound2-dev
      - libfcft-dev
      - libfontconfig-dev
      - libharfbuzz-dev
      - libinotifytools0-dev
      - libjson-c-dev
      - libmpdclient-dev
      - libpixman-1-dev
      - libtllist-dev
      - libudev-dev
      - libwayland-dev
      - libyaml-dev
      - scdoc
      - flex
      - bison
    source: https://codeberg.org/dnkl/yambar.git
    stage-packages:
      - fonts-font-awesome
      - libasound2
      - libfcft4
      - libjson-c5
      - libmpdclient2
      - libpipewire-0.3-0
      - libpixman-1-0
      - libpulse0
      - libudev1
      - libwayland-client0
      - libwayland-cursor0
      - libxcb-cursor0
      - libxcb-randr0
      - libxcb-render0
      - libxcb-util1
      - libxcb-xkb1
      - libxcb1
      - libyaml-0-2

  icons:
    plugin: nil
    stage-packages: [dmz-cursor-theme]

  glue:
    plugin: dump
    source: glue

  env:
    plugin: cmake
    source: env

  misc:
    plugin: nil
    stage-packages:
    - libxcb1
    - libpulse0
    - libsndfile1
    - libasyncns0
    - liblua5.2-0
    - libslang2
    - libglu1-mesa
    - libgpm2
    - libgtk3-nocsd0
    - libgdk-pixbuf2.0-bin # GDK pixbuf
    - libglib2.0-0
    - dbus
    build-packages:
      - libglib2.0-0
      - libgdk-pixbuf2.0-0
      - librsvg2-dev # So the libpixbufloader-svg.so loader can be loaded by gdk-pixbuf-query-loaders
    override-build: |
      snapcraftctl build
      update-mime-database $SNAPCRAFT_PART_INSTALL/usr/share/mime
    override-prime: |
      snapcraftctl prime
      # Compile the gsettings schemas
      /usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/glib-2.0/glib-compile-schemas "$SNAPCRAFT_PRIME/usr/share/glib-2.0/schemas"
      # Index the pixbuf loaders
      GDK_PIXBUF_MODULEDIR=$SNAPCRAFT_PRIME/usr/lib/${SNAPCRAFT_ARCH_TRIPLET}/gdk-pixbuf-2.0/2.10.0/loaders \
      "/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0/gdk-pixbuf-query-loaders" > "$SNAPCRAFT_PRIME/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0/2.10.0/loaders.cache"
      sed s!$SNAPCRAFT_PRIME!!g --in-place "$SNAPCRAFT_PRIME/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/gdk-pixbuf-2.0/2.10.0/loaders.cache"

  graphics-core22:
    after:
      - miriway
      - env
      - yambar
      - wofi
      - swaybg
      - icons
      - glue
      - misc
    source: https://github.com/MirServer/graphics-core22.git
    plugin: dump
    override-prime: |
      craftctl default
      ${CRAFT_PART_SRC}/bin/graphics-core22-cleanup mesa-core22
      rm -rf ${CRAFT_PRIME}/{bug,doc,lintian,man}
    prime:
      - bin/graphics-core22-wrapper

plugs:
  desktop-launch:
  opengl:
  graphics-core22:
    interface: content
    target: $SNAP/graphics
    default-provider: mesa-core22/edge

architectures:
  - build-on: amd64
  - build-on: arm64
  - build-on: armhf

package-repositories:
  - type: apt
    ppa: mir-team/release

(The full snap is https://github.com/MirServer/confined-shell-wip/tree/refresh-appearance)

It can be installed from the store:

snap install confined-shell --channel edge/pr14

But needs mesa-core22 (from edge) installed to satisfy the graphics-core22 interface.

Yes, it should be a tightly controlled interface, if it should be done at all.