github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/desktop_legacy.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  	"strings"
    24  
    25  	"github.com/snapcore/snapd/interfaces"
    26  	"github.com/snapcore/snapd/interfaces/apparmor"
    27  )
    28  
    29  const desktopLegacySummary = `allows privileged access to desktop legacy methods`
    30  
    31  // While this gives privileged access to legacy methods we should auto-connect
    32  // this transitional interface since most desktop applications will need it.
    33  // When safe alternative methods are added to the desktop interface by default,
    34  // we can consider making this manually connected.
    35  const desktopLegacyBaseDeclarationSlots = `
    36    desktop-legacy:
    37      allow-installation:
    38        slot-snap-type:
    39          - core
    40  `
    41  
    42  const desktopLegacyConnectedPlugAppArmor = `
    43  # Description: Can access common desktop legacy methods. This gives privileged
    44  # access to the user's input.
    45  
    46  # accessibility (a11y)
    47  #include <abstractions/dbus-session-strict>
    48  dbus (send)
    49      bus=session
    50      path=/org/a11y/bus
    51      interface=org.a11y.Bus
    52      member=GetAddress
    53      peer=(label=unconfined),
    54  
    55  #include <abstractions/dbus-accessibility-strict>
    56  
    57  # Allow the accessibility services in the user session to send us any events
    58  dbus (receive)
    59      bus=accessibility
    60      peer=(label=unconfined),
    61  
    62  # Allow querying for capabilities and registering
    63  dbus (send)
    64      bus=accessibility
    65      path="/org/a11y/atspi/accessible/root"
    66      interface="org.a11y.atspi.Socket"
    67      member="Embed"
    68      peer=(name=org.a11y.atspi.Registry, label=unconfined),
    69  dbus (send)
    70      bus=accessibility
    71      path="/org/a11y/atspi/registry"
    72      interface="org.a11y.atspi.Registry"
    73      member="GetRegisteredEvents"
    74      peer=(name=org.a11y.atspi.Registry, label=unconfined),
    75  dbus (send)
    76      bus=accessibility
    77      path="/org/a11y/atspi/registry/deviceeventcontroller"
    78      interface="org.a11y.atspi.DeviceEventController"
    79      member="Get{DeviceEvent,Keystroke}Listeners"
    80      peer=(name=org.a11y.atspi.Registry, label=unconfined),
    81  dbus (send)
    82      bus=accessibility
    83      path="/org/a11y/atspi/registry/deviceeventcontroller"
    84      interface="org.a11y.atspi.DeviceEventController"
    85      member="NotifyListenersSync"
    86      peer=(name=org.a11y.atspi.Registry, label=unconfined),
    87  
    88  # org.a11y.atspi is not designed for application isolation and these rules
    89  # can be used to send change events for other processes.
    90  dbus (send)
    91      bus=accessibility
    92      path="/org/a11y/atspi/accessible/root"
    93      interface="org.a11y.atspi.Event.Object"
    94      member="ChildrenChanged"
    95      peer=(name=org.freedesktop.DBus, label=unconfined),
    96  dbus (send)
    97      bus=accessibility
    98      path="/org/a11y/atspi/accessible/root"
    99      interface="org.a11y.atspi.Accessible"
   100      member="Get*"
   101      peer=(label=unconfined),
   102  dbus (send)
   103      bus=accessibility
   104      path="/org/a11y/atspi/accessible/[0-9]*"
   105      interface="org.a11y.atspi.Event.Object"
   106      member="{ChildrenChanged,PropertyChange,StateChanged,TextCaretMoved}"
   107      peer=(name=org.freedesktop.DBus, label=unconfined),
   108  dbus (send)
   109      bus=accessibility
   110      path="/org/a11y/atspi/accessible/[0-9]*"
   111      interface="org.freedesktop.DBus.Properties"
   112      member="Get{,All}"
   113      peer=(label=unconfined),
   114  
   115  dbus (send)
   116      bus=accessibility
   117      path="/org/a11y/atspi/cache"
   118      interface="org.a11y.atspi.Cache"
   119      member="{Add,Remove}Accessible"
   120      peer=(name=org.freedesktop.DBus, label=unconfined),
   121  
   122  
   123  # ibus
   124  # subset of ibus abstraction
   125  /usr/lib/@{multiarch}/gtk-2.0/[0-9]*/immodules/im-ibus.so mr,
   126  owner @{HOME}/.config/ibus/      r,
   127  owner @{HOME}/.config/ibus/bus/  r,
   128  owner @{HOME}/.config/ibus/bus/* r,
   129  
   130  # allow communicating with ibus-daemon (this allows sniffing key events)
   131  unix (connect, receive, send)
   132      type=stream
   133      peer=(addr="@/tmp/ibus/dbus-*"),
   134  
   135  # abstract path in ibus >= 1.5.22 uses $XDG_CACHE_HOME (ie, @{HOME}/.cache)
   136  # This should use this, but due to LP: #1856738 we cannot
   137  #unix (connect, receive, send)
   138  #    type=stream
   139  #    peer=(addr="@@{HOME}/.cache/ibus/dbus-*"),
   140  unix (connect, receive, send)
   141       type=stream
   142       peer=(addr="@/home/*/.cache/ibus/dbus-*"),
   143  
   144  
   145  # mozc
   146  # allow communicating with mozc server
   147  unix (connect, receive, send)
   148       type=stream
   149       peer=(addr="@tmp/.mozc.*"),
   150  
   151  
   152  # fcitx
   153  # allow communicating with fcitx dbus service
   154  dbus send
   155      bus=fcitx
   156      path=/org/freedesktop/DBus
   157      interface=org.freedesktop.DBus
   158      member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
   159      peer=(name=org.freedesktop.DBus),
   160  
   161  owner @{HOME}/.config/fcitx/dbus/* r,
   162  
   163  # allow creating an input context
   164  dbus send
   165      bus={fcitx,session}
   166      path=/inputmethod
   167      interface=org.fcitx.Fcitx.InputMethod
   168      member=CreateIC*
   169      peer=(label=unconfined),
   170  
   171  # allow setting up and tearing down the input context
   172  dbus send
   173      bus={fcitx,session}
   174      path=/inputcontext_[0-9]*
   175      interface=org.fcitx.Fcitx.InputContext
   176      member="{Close,Destroy,Enable}IC"
   177      peer=(label=unconfined),
   178  
   179  dbus send
   180      bus={fcitx,session}
   181      path=/inputcontext_[0-9]*
   182      interface=org.fcitx.Fcitx.InputContext
   183      member=Reset
   184      peer=(label=unconfined),
   185  
   186  # allow service to send us signals
   187  dbus receive
   188      bus=fcitx
   189      peer=(label=unconfined),
   190  
   191  dbus receive
   192      bus=session
   193      interface=org.fcitx.Fcitx.*
   194      peer=(label=unconfined),
   195  
   196  # use the input context
   197  dbus send
   198      bus={fcitx,session}
   199      path=/inputcontext_[0-9]*
   200      interface=org.fcitx.Fcitx.InputContext
   201      member="Focus{In,Out}"
   202      peer=(label=unconfined),
   203  
   204  dbus send
   205      bus={fcitx,session}
   206      path=/inputcontext_[0-9]*
   207      interface=org.fcitx.Fcitx.InputContext
   208      member="{CommitPreedit,Set*}"
   209      peer=(label=unconfined),
   210  
   211  # this is an information leak and allows key and mouse sniffing. If the input
   212  # context path were tied to the process' security label, this would not be an
   213  # issue.
   214  dbus send
   215      bus={fcitx,session}
   216      path=/inputcontext_[0-9]*
   217      interface=org.fcitx.Fcitx.InputContext
   218      member="{MouseEvent,ProcessKeyEvent}"
   219      peer=(label=unconfined),
   220  
   221  # this method does not exist with the sunpinyin backend (at least), so allow
   222  # it for other input methods. This may consitute an information leak (which,
   223  # again, could be avoided if the path were tied to the process' security
   224  # label).
   225  dbus send
   226      bus={fcitx,session}
   227      path=/inputcontext_[0-9]*
   228      interface=org.freedesktop.DBus.Properties
   229      member=GetAll
   230      peer=(label=unconfined),
   231  
   232  # gtk2/gvfs gtk_show_uri()
   233  dbus (send)
   234      bus=session
   235      path=/org/gtk/vfs/mounttracker
   236      interface=org.gtk.vfs.MountTracker
   237      member=ListMountableInfo,
   238  dbus (send)
   239      bus=session
   240      path=/org/gtk/vfs/mounttracker
   241      interface=org.gtk.vfs.MountTracker
   242      member=LookupMount,
   243  
   244  ###SNAP_DESKTOP_FILE_RULES###
   245  # Snaps are unable to use the data in mimeinfo.cache (since they can't execute
   246  # the returned desktop file themselves). unity messaging menu doesn't require
   247  # mimeinfo.cache and xdg-mime will fallback to reading the desktop files
   248  # directly to look for MimeType. Since reading the snap's own desktop files is
   249  # allowed, we can safely deny access to this file (and xdg-mime will either
   250  # return one of the snap's mimetypes, or none).
   251  deny /var/lib/snapd/desktop/applications/mimeinfo.cache r,
   252  
   253  # glib-networking's GLib proxy (different than the portal's proxy service
   254  # org.freedesktop.portal.ProxyResolver). The Lookup API allows specifying
   255  # various URLs (eg, file://, http:// and https://) which will be given to the
   256  # unconfined glib-pacrunner.
   257  dbus (send)
   258      bus=session
   259      path=/org/gtk/GLib/PACRunner
   260      interface=org.gtk.GLib.PACRunner
   261      member=Lookup
   262      peer=(label=unconfined),
   263  
   264  # app-indicators
   265  dbus (send)
   266      bus=session
   267      path=/StatusNotifierWatcher
   268      interface=org.freedesktop.DBus.Introspectable
   269      member=Introspect
   270      peer=(name=org.kde.StatusNotifierWatcher, label=unconfined),
   271  
   272  dbus (send)
   273      bus=session
   274      path=/org/freedesktop/DBus
   275      interface=org.freedesktop.DBus
   276      member="{GetConnectionUnixProcessID,RequestName,ReleaseName}"
   277      peer=(name=org.freedesktop.DBus, label=unconfined),
   278  
   279  dbus (bind)
   280      bus=session
   281      name=org.kde.StatusNotifierItem-[0-9]*,
   282  
   283  dbus (send)
   284      bus=session
   285      path=/StatusNotifierWatcher
   286      interface=org.freedesktop.DBus.Properties
   287      member=Get
   288      peer=(name=org.kde.StatusNotifierWatcher, label=unconfined),
   289  
   290  dbus (send)
   291      bus=session
   292      path=/{StatusNotifierWatcher,org/ayatana/NotificationItem/*}
   293      interface=org.kde.StatusNotifierWatcher
   294      member=RegisterStatusNotifierItem
   295      peer=(label=unconfined),
   296  
   297  dbus (send)
   298      bus=session
   299      path=/{StatusNotifierItem,org/ayatana/NotificationItem/*}
   300      interface=org.kde.StatusNotifierItem
   301      member="New{AttentionIcon,Icon,IconThemePath,OverlayIcon,Status,Title,ToolTip}"
   302      peer=(name=org.freedesktop.DBus, label=unconfined),
   303  
   304  dbus (receive)
   305      bus=session
   306      path=/{StatusNotifierItem,org/ayatana/NotificationItem/*}
   307      interface=org.kde.StatusNotifierItem
   308      member={Activate,ContextMenu,Scroll,SecondaryActivate,XAyatanaSecondaryActivate}
   309      peer=(label=unconfined),
   310  
   311  dbus (send)
   312      bus=session
   313      path=/{StatusNotifierItem/menu,org/ayatana/NotificationItem/*/Menu}
   314      interface=com.canonical.dbusmenu
   315      member="{LayoutUpdated,ItemsPropertiesUpdated}"
   316      peer=(name=org.freedesktop.DBus, label=unconfined),
   317  
   318  dbus (receive)
   319      bus=session
   320      path=/{StatusNotifierItem,StatusNotifierItem/menu,org/ayatana/NotificationItem/**}
   321      interface={org.freedesktop.DBus.Properties,com.canonical.dbusmenu}
   322      member={Get*,AboutTo*,Event*}
   323      peer=(label=unconfined),
   324  
   325  # notifications
   326  dbus (send)
   327      bus=session
   328      path=/org/freedesktop/Notifications
   329      interface=org.freedesktop.Notifications
   330      member="{GetCapabilities,GetServerInformation,Notify,CloseNotification}"
   331      peer=(label=unconfined),
   332  
   333  dbus (receive)
   334      bus=session
   335      path=/org/freedesktop/Notifications
   336      interface=org.freedesktop.Notifications
   337      member={ActionInvoked,NotificationClosed,NotificationReplied}
   338      peer=(label=unconfined),
   339  
   340  dbus (send)
   341      bus=session
   342      path=/org/ayatana/NotificationItem/*
   343      interface=org.kde.StatusNotifierItem
   344      member=XAyatanaNew*
   345      peer=(name=org.freedesktop.DBus, label=unconfined),
   346  `
   347  
   348  const desktopLegacyConnectedPlugSecComp = `
   349  # Description: Can access common desktop legacy methods. This gives privileged
   350  # access to the user's input.
   351  
   352  listen
   353  accept
   354  accept4
   355  `
   356  
   357  type desktopLegacyInterface struct {
   358  	commonInterface
   359  }
   360  
   361  func (iface *desktopLegacyInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   362  	snippet := strings.Join(getDesktopFileRules(plug.Snap().DesktopPrefix()), "\n")
   363  	spec.AddSnippet(strings.Replace(desktopLegacyConnectedPlugAppArmor, "###SNAP_DESKTOP_FILE_RULES###", snippet+"\n", -1))
   364  
   365  	return nil
   366  }
   367  
   368  func init() {
   369  	registerIface(&desktopLegacyInterface{
   370  		commonInterface: commonInterface{
   371  			name:                 "desktop-legacy",
   372  			summary:              desktopLegacySummary,
   373  			implicitOnClassic:    true,
   374  			baseDeclarationSlots: desktopLegacyBaseDeclarationSlots,
   375  			connectedPlugSecComp: desktopLegacyConnectedPlugSecComp,
   376  		},
   377  	})
   378  }