github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/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/strutil" 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 # some applications are known to mmap fonts 61 /usr/{,local/}share/fonts/** m, 62 63 # subset of gnome abstraction 64 /etc/gtk-3.0/settings.ini r, 65 owner @{HOME}/.config/gtk-3.0/settings.ini r, 66 # Note: this leaks directory names that wouldn't otherwise be known to the snap 67 owner @{HOME}/.config/gtk-3.0/bookmarks r, 68 69 /usr/share/icons/ r, 70 /usr/share/icons/** r, 71 /usr/share/icons/*/index.theme rk, 72 /usr/share/pixmaps/ r, 73 /usr/share/pixmaps/** r, 74 /usr/share/unity/icons/** r, 75 /usr/share/thumbnailer/icons/** r, 76 /usr/share/themes/** r, 77 78 # The snapcraft desktop part may look for schema files in various locations, so 79 # allow reading system installed schemas. 80 /usr/share/glib*/schemas/{,*} r, 81 /usr/share/gnome/glib*/schemas/{,*} r, 82 /usr/share/ubuntu/glib*/schemas/{,*} r, 83 84 # subset of freedesktop.org 85 owner @{HOME}/.local/share/mime/** r, 86 owner @{HOME}/.config/user-dirs.* r, 87 88 /etc/xdg/user-dirs.conf r, 89 /etc/xdg/user-dirs.defaults r, 90 91 # gmenu 92 dbus (send) 93 bus=session 94 interface=org.gtk.Actions 95 member=Changed 96 peer=(name=org.freedesktop.DBus, label=unconfined), 97 98 # notifications 99 dbus (send) 100 bus=session 101 path=/org/freedesktop/Notifications 102 interface=org.freedesktop.Notifications 103 member="{GetCapabilities,GetServerInformation,Notify,CloseNotification}" 104 peer=(label=unconfined), 105 106 dbus (receive) 107 bus=session 108 path=/org/freedesktop/Notifications 109 interface=org.freedesktop.Notifications 110 member={ActionInvoked,NotificationClosed,NotificationReplied} 111 peer=(label=unconfined), 112 113 # DesktopAppInfo Launched 114 dbus (send) 115 bus=session 116 path=/org/gtk/gio/DesktopAppInfo 117 interface=org.gtk.gio.DesktopAppInfo 118 member=Launched 119 peer=(label=unconfined), 120 121 # Allow requesting interest in receiving media key events. This tells Gnome 122 # settings that our application should be notified when key events we are 123 # interested in are pressed, and allows us to receive those events. 124 dbus (receive, send) 125 bus=session 126 interface=org.gnome.SettingsDaemon.MediaKeys 127 path=/org/gnome/SettingsDaemon/MediaKeys 128 peer=(label=unconfined), 129 dbus (send) 130 bus=session 131 interface=org.freedesktop.DBus.Properties 132 path=/org/gnome/SettingsDaemon/MediaKeys 133 member="Get{,All}" 134 peer=(label=unconfined), 135 136 # Allow accessing the GNOME crypto services prompt APIs as used by 137 # applications using libgcr (such as pinentry-gnome3) for secure pin 138 # entry to unlock GPG keys etc. See: 139 # https://developer.gnome.org/gcr/unstable/GcrPrompt.html 140 # https://developer.gnome.org/gcr/unstable/GcrSecretExchange.html 141 dbus (send) 142 bus=session 143 path=/org/gnome/keyring/Prompter 144 interface=org.gnome.keyring.internal.Prompter 145 member="{BeginPrompting,PerformPrompt,StopPrompting}" 146 peer=(label=unconfined), 147 148 # While the DBus path is not snap-specific, by the time an application 149 # registers the prompt path via DBus, Gcr will check that it isn't 150 # already in use and send the client an error if it is. See: 151 # https://github.com/snapcore/snapd/pull/7673#issuecomment-592229711 152 dbus (receive) 153 bus=session 154 path=/org/gnome/keyring/Prompt/p[0-9]* 155 interface=org.gnome.keyring.internal.Prompter.Callback 156 member="{PromptReady,PromptDone}" 157 peer=(label=unconfined), 158 159 # Allow use of snapd's internal 'xdg-open' 160 /usr/bin/xdg-open ixr, 161 # While /usr/share/applications comes from the base runtime of the snap, it 162 # has some things that snaps actually need, so allow access to those and deny 163 # access to the others 164 /usr/share/applications/ r, 165 /usr/share/applications/mimeapps.list r, 166 /usr/share/applications/xdg-open.desktop r, 167 # silence noisy denials from desktop files in core* snaps that aren't usable by 168 # snaps 169 deny /usr/share/applications/python*.desktop r, 170 deny /usr/share/applications/vim.desktop r, 171 deny /usr/share/applications/snap-handle-link.desktop r, # core16 172 173 dbus (send) 174 bus=session 175 path=/ 176 interface=com.canonical.SafeLauncher 177 member=OpenURL 178 peer=(label=unconfined), 179 # ... and this allows access to the new xdg-open service which 180 # is now part of snapd itself. 181 dbus (send) 182 bus=session 183 path=/io/snapcraft/Launcher 184 interface=io.snapcraft.Launcher 185 member={OpenURL,OpenFile} 186 peer=(label=unconfined), 187 188 # Allow checking status, activating and locking the screensaver 189 # gnome/kde/freedesktop.org 190 dbus (send) 191 bus=session 192 path="/{,org/freedesktop/,org/gnome/}ScreenSaver" 193 interface="org.{freedesktop,gnome}.ScreenSaver" 194 member="{GetActive,GetActiveTime,Lock,SetActive}" 195 peer=(label=unconfined), 196 197 dbus (receive) 198 bus=session 199 path="/{,org/freedesktop/,org/gnome/}ScreenSaver" 200 interface="org.{freedesktop,gnome}.ScreenSaver" 201 member=ActiveChanged 202 peer=(label=unconfined), 203 204 # Allow unconfined to introspect us 205 dbus (receive) 206 bus=session 207 interface=org.freedesktop.DBus.Introspectable 208 member=Introspect 209 peer=(label=unconfined), 210 211 # Allow use of snapd's internal 'xdg-settings' 212 /usr/bin/xdg-settings ixr, 213 dbus (send) 214 bus=session 215 path=/io/snapcraft/Settings 216 interface=io.snapcraft.Settings 217 member={Check,CheckSub,Get,GetSub,Set,SetSub} 218 peer=(label=unconfined), 219 220 # Allow access to xdg-document-portal file system. Access control is 221 # handled by bind mounting a snap-specific sub-tree to this location 222 # (ie, this is /run/user/<uid>/doc/by-app/snap.@{SNAP_INSTANCE_NAME} 223 # on the host). 224 owner /run/user/[0-9]*/doc/{,*/} r, 225 # Allow rw access without owner match to the documents themselves since 226 # the user guided the access and can specify anything DAC allows. 227 /run/user/[0-9]*/doc/*/** rw, 228 229 # Allow access to xdg-desktop-portal and xdg-document-portal 230 dbus (receive, send) 231 bus=session 232 interface=org.freedesktop.portal.* 233 path=/org/freedesktop/portal/{desktop,documents}{,/**} 234 peer=(label=unconfined), 235 236 dbus (receive, send) 237 bus=session 238 interface=org.freedesktop.DBus.Properties 239 path=/org/freedesktop/portal/{desktop,documents}{,/**} 240 peer=(label=unconfined), 241 242 # The portals service is normally running and newer versions of 243 # xdg-desktop-portal include AssumedAppArmor=unconfined. Since older 244 # systems don't have this and because gtkfilechoosernativeportal.c relies on 245 # service activation, allow sends to peer=(name=org.freedesktop.portal.Desktop) 246 # for service activation. 247 dbus (send) 248 bus=session 249 interface=org.freedesktop.portal.* 250 path=/org/freedesktop/portal/{desktop,documents}{,/**} 251 peer=(name=org.freedesktop.portal.Desktop), 252 dbus (send) 253 bus=session 254 interface=org.freedesktop.DBus.Properties 255 path=/org/freedesktop/portal/{desktop,documents}{,/**} 256 peer=(name=org.freedesktop.portal.Desktop), 257 258 # These accesses are noisy and applications can't do anything with the found 259 # icon files, so explicitly deny to silence the denials 260 deny /var/lib/snapd/desktop/icons/{,**/} r, 261 262 # These accesses occur when flatpaks are on the system since it updates 263 # XDG_DATA_DIRS to contain $HOME/.local/share/flatpak/exports/share. Until 264 # we have better XDG_DATA_DIRS handling, silence these noisy denials. 265 # https://github.com/snapcrafters/discord/issues/23#issuecomment-637607843 266 deny @{HOME}/.local/share/flatpak/exports/share/** r, 267 268 # Allow access to the IBus portal (IBUS_USE_PORTAL=1) 269 dbus (send) 270 bus=session 271 path=/org/freedesktop/IBus 272 interface=org.freedesktop.IBus.Portal 273 member=CreateInputContext 274 peer=(name=org.freedesktop.portal.IBus), 275 276 dbus (send, receive) 277 bus=session 278 path=/org/freedesktop/IBus/InputContext_[0-9]* 279 interface=org.freedesktop.IBus.InputContext 280 peer=(label=unconfined), 281 ` 282 283 type desktopInterface struct { 284 commonInterface 285 } 286 287 func (iface *desktopInterface) fontconfigDirs() []string { 288 fontDirs := []string{ 289 dirs.SystemFontsDir, 290 dirs.SystemLocalFontsDir, 291 } 292 return append(fontDirs, dirs.SystemFontconfigCacheDirs...) 293 } 294 295 func (iface *desktopInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 296 spec.AddSnippet(desktopConnectedPlugAppArmor) 297 298 // Allow mounting document portal 299 emit := spec.AddUpdateNSf 300 emit(" # Mount the document portal\n") 301 emit(" mount options=(bind) /run/user/[0-9]*/doc/by-app/snap.%s/ -> /run/user/[0-9]*/doc/,\n", plug.Snap().InstanceName()) 302 emit(" umount /run/user/[0-9]*/doc/,\n\n") 303 304 if !release.OnClassic { 305 // We only need the font mount rules on classic systems 306 return nil 307 } 308 309 // Allow mounting fonts 310 for _, dir := range iface.fontconfigDirs() { 311 source := "/var/lib/snapd/hostfs" + dir 312 target := dirs.StripRootDir(dir) 313 emit(" # Read-only access to %s\n", target) 314 emit(" mount options=(bind) %s/ -> %s/,\n", source, target) 315 emit(" remount options=(bind, ro) %s/,\n", target) 316 emit(" umount %s/,\n\n", target) 317 } 318 319 return nil 320 } 321 322 func (iface *desktopInterface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 323 appId := "snap." + plug.Snap().InstanceName() 324 spec.AddUserMountEntry(osutil.MountEntry{ 325 Name: "$XDG_RUNTIME_DIR/doc/by-app/" + appId, 326 Dir: "$XDG_RUNTIME_DIR/doc", 327 Options: []string{"bind", "rw", osutil.XSnapdIgnoreMissing()}, 328 }) 329 330 if !release.OnClassic { 331 // We only need the font mount rules on classic systems 332 return nil 333 } 334 335 for _, dir := range iface.fontconfigDirs() { 336 if !osutil.IsDirectory(dir) { 337 continue 338 } 339 if release.DistroLike("arch", "fedora") { 340 // XXX: on Arch and Fedora 32+ there is a known 341 // incompatibility between the binary fonts cache files 342 // and ones expected by desktop snaps; even though the 343 // cache format level is same for both, the host 344 // generated cache files cause instability, segfaults or 345 // incorrect rendering of fonts, for this reason do not 346 // mount the cache directories on those distributions, 347 // see https://bugs.launchpad.net/snapd/+bug/1877109 348 if strutil.ListContains(dirs.SystemFontconfigCacheDirs, dir) { 349 continue 350 } 351 } 352 // Since /etc/fonts/fonts.conf in the snap mount ns is the same 353 // as on the host, we need to preserve the original directory 354 // paths for the fontconfig runtime to poke the correct 355 // locations 356 spec.AddMountEntry(osutil.MountEntry{ 357 Name: "/var/lib/snapd/hostfs" + dir, 358 Dir: dirs.StripRootDir(dir), 359 Options: []string{"bind", "ro"}, 360 }) 361 } 362 363 return nil 364 } 365 366 func init() { 367 registerIface(&desktopInterface{ 368 commonInterface: commonInterface{ 369 name: "desktop", 370 summary: desktopSummary, 371 implicitOnClassic: true, 372 baseDeclarationSlots: desktopBaseDeclarationSlots, 373 }, 374 }) 375 }