github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/builtin/desktop.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2017 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package builtin
    21  
    22  import (
    23  	"github.com/snapcore/snapd/dirs"
    24  	"github.com/snapcore/snapd/interfaces"
    25  	"github.com/snapcore/snapd/interfaces/apparmor"
    26  	"github.com/snapcore/snapd/interfaces/mount"
    27  	"github.com/snapcore/snapd/osutil"
    28  	"github.com/snapcore/snapd/release"
    29  	"github.com/snapcore/snapd/snap"
    30  )
    31  
    32  const desktopSummary = `allows access to basic graphical desktop resources`
    33  
    34  const desktopBaseDeclarationSlots = `
    35    desktop:
    36      allow-installation:
    37        slot-snap-type:
    38          - core
    39  `
    40  
    41  const desktopConnectedPlugAppArmor = `
    42  # Description: Can access basic graphical desktop resources. To be used with
    43  # other interfaces (eg, wayland).
    44  
    45  #include <abstractions/dbus-strict>
    46  #include <abstractions/dbus-session-strict>
    47  
    48  # Allow finding the DBus session bus id (eg, via dbus_bus_get_id())
    49  dbus (send)
    50       bus=session
    51       path=/org/freedesktop/DBus
    52       interface=org.freedesktop.DBus
    53       member=GetId
    54       peer=(name=org.freedesktop.DBus, label=unconfined),
    55  
    56  #include <abstractions/fonts>
    57  owner @{HOME}/.local/share/fonts/{,**} r,
    58  /var/cache/fontconfig/   r,
    59  /var/cache/fontconfig/** mr,
    60  
    61  # subset of gnome abstraction
    62  /etc/gtk-3.0/settings.ini r,
    63  owner @{HOME}/.config/gtk-3.0/settings.ini r,
    64  # Note: this leaks directory names that wouldn't otherwise be known to the snap
    65  owner @{HOME}/.config/gtk-3.0/bookmarks r,
    66  
    67  /usr/share/icons/                          r,
    68  /usr/share/icons/**                        r,
    69  /usr/share/icons/*/index.theme             rk,
    70  /usr/share/pixmaps/                        r,
    71  /usr/share/pixmaps/**                      r,
    72  /usr/share/unity/icons/**                  r,
    73  /usr/share/thumbnailer/icons/**            r,
    74  /usr/share/themes/**                       r,
    75  
    76  # The snapcraft desktop part may look for schema files in various locations, so
    77  # allow reading system installed schemas.
    78  /usr/share/glib*/schemas/{,*}              r,
    79  /usr/share/gnome/glib*/schemas/{,*}        r,
    80  /usr/share/ubuntu/glib*/schemas/{,*}       r,
    81  
    82  # subset of freedesktop.org
    83  owner @{HOME}/.local/share/mime/**   r,
    84  owner @{HOME}/.config/user-dirs.* r,
    85  
    86  /etc/xdg/user-dirs.conf r,
    87  /etc/xdg/user-dirs.defaults r,
    88  
    89  # gmenu
    90  dbus (send)
    91       bus=session
    92       interface=org.gtk.Actions
    93       member=Changed
    94       peer=(name=org.freedesktop.DBus, label=unconfined),
    95  
    96  # notifications
    97  dbus (send)
    98      bus=session
    99      path=/org/freedesktop/Notifications
   100      interface=org.freedesktop.Notifications
   101      member="{GetCapabilities,GetServerInformation,Notify,CloseNotification}"
   102      peer=(label=unconfined),
   103  
   104  dbus (receive)
   105      bus=session
   106      path=/org/freedesktop/Notifications
   107      interface=org.freedesktop.Notifications
   108      member={ActionInvoked,NotificationClosed}
   109      peer=(label=unconfined),
   110  
   111  # DesktopAppInfo Launched
   112  dbus (send)
   113      bus=session
   114      path=/org/gtk/gio/DesktopAppInfo
   115      interface=org.gtk.gio.DesktopAppInfo
   116      member=Launched
   117      peer=(label=unconfined),
   118  
   119  # Allow requesting interest in receiving media key events. This tells Gnome
   120  # settings that our application should be notified when key events we are
   121  # interested in are pressed, and allows us to receive those events.
   122  dbus (receive, send)
   123    bus=session
   124    interface=org.gnome.SettingsDaemon.MediaKeys
   125    path=/org/gnome/SettingsDaemon/MediaKeys
   126    peer=(label=unconfined),
   127  dbus (send)
   128    bus=session
   129    interface=org.freedesktop.DBus.Properties
   130    path=/org/gnome/SettingsDaemon/MediaKeys
   131    member="Get{,All}"
   132    peer=(label=unconfined),
   133  
   134  # Allow use of snapd's internal 'xdg-open'
   135  /usr/bin/xdg-open ixr,
   136  /usr/share/applications/{,*} r,
   137  dbus (send)
   138      bus=session
   139      path=/
   140      interface=com.canonical.SafeLauncher
   141      member=OpenURL
   142      peer=(label=unconfined),
   143  # ... and this allows access to the new xdg-open service which
   144  # is now part of snapd itself.
   145  dbus (send)
   146      bus=session
   147      path=/io/snapcraft/Launcher
   148      interface=io.snapcraft.Launcher
   149      member={OpenURL,OpenFile}
   150      peer=(label=unconfined),
   151  
   152  # Allow checking status, activating and locking the screensaver
   153  # gnome/kde/freedesktop.org
   154  dbus (send)
   155      bus=session
   156      path="/{,org/freedesktop/,org/gnome/}ScreenSaver"
   157      interface="org.{freedesktop,gnome}.ScreenSaver"
   158      member="{GetActive,GetActiveTime,Lock,SetActive}"
   159      peer=(label=unconfined),
   160  
   161  dbus (receive)
   162      bus=session
   163      path="/{,org/freedesktop/,org/gnome/}ScreenSaver"
   164      interface="org.{freedesktop,gnome}.ScreenSaver"
   165      member=ActiveChanged
   166      peer=(label=unconfined),
   167  
   168  # Allow unconfined to introspect us
   169  dbus (receive)
   170      bus=session
   171      interface=org.freedesktop.DBus.Introspectable
   172      member=Introspect
   173      peer=(label=unconfined),
   174  
   175  # Allow use of snapd's internal 'xdg-settings'
   176  /usr/bin/xdg-settings ixr,
   177  dbus (send)
   178      bus=session
   179      path=/io/snapcraft/Settings
   180      interface=io.snapcraft.Settings
   181      member={Check,Get,Set}
   182      peer=(label=unconfined),
   183  
   184  ## Allow access to xdg-document-portal file system.  Access control is
   185  ## handled by bind mounting a snap-specific sub-tree to this location.
   186  owner /run/user/[0-9]*/doc/ r,
   187  owner /run/user/[0-9]*/doc/** rw,
   188  
   189  # Allow access to xdg-desktop-portal and xdg-document-portal
   190  dbus (receive, send)
   191      bus=session
   192      interface=org.freedesktop.portal.*
   193      path=/org/freedesktop/portal/{desktop,documents}{,/**}
   194      peer=(label=unconfined),
   195  
   196  dbus (receive, send)
   197      bus=session
   198      interface=org.freedesktop.DBus.Properties
   199      path=/org/freedesktop/portal/{desktop,documents}{,/**}
   200      peer=(label=unconfined),
   201  
   202  # These accesses are noisy and applications can't do anything with the found
   203  # icon files, so explicitly deny to silence the denials
   204  deny /var/lib/snapd/desktop/icons/ r,
   205  `
   206  
   207  type desktopInterface struct{}
   208  
   209  func (iface *desktopInterface) Name() string {
   210  	return "desktop"
   211  }
   212  
   213  func (iface *desktopInterface) StaticInfo() interfaces.StaticInfo {
   214  	return interfaces.StaticInfo{
   215  		Summary:              desktopSummary,
   216  		ImplicitOnClassic:    true,
   217  		BaseDeclarationSlots: desktopBaseDeclarationSlots,
   218  	}
   219  }
   220  
   221  func (iface *desktopInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
   222  	// allow what declarations allowed
   223  	return true
   224  }
   225  
   226  func (iface *desktopInterface) fontconfigDirs() []string {
   227  	fontDirs := []string{
   228  		dirs.SystemFontsDir,
   229  		dirs.SystemLocalFontsDir,
   230  	}
   231  	return append(fontDirs, dirs.SystemFontconfigCacheDirs...)
   232  }
   233  
   234  func (iface *desktopInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   235  	spec.AddSnippet(desktopConnectedPlugAppArmor)
   236  
   237  	// Allow mounting document portal
   238  	emit := spec.EmitUpdateNSFunc()
   239  	emit("  # Mount the document portal\n")
   240  	emit("  mount options=(bind) /run/user/[0-9]*/doc/by-app/snap.%s/ -> /run/user/[0-9]*/doc/,\n", plug.Snap().InstanceName())
   241  	emit("  umount /run/user/[0-9]*/doc/,\n\n")
   242  
   243  	if !release.OnClassic {
   244  		// We only need the font mount rules on classic systems
   245  		return nil
   246  	}
   247  
   248  	// Allow mounting fonts
   249  	for _, dir := range iface.fontconfigDirs() {
   250  		source := "/var/lib/snapd/hostfs" + dir
   251  		target := dirs.StripRootDir(dir)
   252  		emit("  # Read-only access to %s\n", target)
   253  		emit("  mount options=(bind) %s/ -> %s/,\n", source, target)
   254  		emit("  remount options=(bind, ro) %s/,\n", target)
   255  		emit("  umount %s/,\n\n", target)
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  func (iface *desktopInterface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   262  	appId := "snap." + plug.Snap().InstanceName()
   263  	spec.AddUserMountEntry(osutil.MountEntry{
   264  		Name:    "$XDG_RUNTIME_DIR/doc/by-app/" + appId,
   265  		Dir:     "$XDG_RUNTIME_DIR/doc",
   266  		Options: []string{"bind", "rw", osutil.XSnapdIgnoreMissing()},
   267  	})
   268  
   269  	if !release.OnClassic {
   270  		// We only need the font mount rules on classic systems
   271  		return nil
   272  	}
   273  
   274  	for _, dir := range iface.fontconfigDirs() {
   275  		if !osutil.IsDirectory(dir) {
   276  			continue
   277  		}
   278  		// Since /etc/fonts/fonts.conf in the snap mount ns is the same
   279  		// as on the host, we need to preserve the original directory
   280  		// paths for the fontconfig runtime to poke the correct
   281  		// locations
   282  		spec.AddMountEntry(osutil.MountEntry{
   283  			Name:    "/var/lib/snapd/hostfs" + dir,
   284  			Dir:     dirs.StripRootDir(dir),
   285  			Options: []string{"bind", "ro"},
   286  		})
   287  	}
   288  
   289  	return nil
   290  }
   291  
   292  func init() {
   293  	registerIface(&desktopInterface{})
   294  }