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 }