Permalink
Fetching contributors…
Cannot retrieve contributors at this time
630 lines (539 sloc) 18.2 KB
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-2017 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package builtin
import (
"strings"
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/seccomp"
"github.com/snapcore/snapd/snap"
)
const unity7Summary = `allows interacting with Unity 7 services`
const unity7BaseDeclarationSlots = `
unity7:
allow-installation:
slot-snap-type:
- core
`
const unity7ConnectedPlugAppArmor = `
# Description: Can access Unity7. Note, Unity 7 runs on X and requires access
# to various DBus services and this environment does not prevent eavesdropping
# or apps interfering with one another.
#include <abstractions/dbus-strict>
#include <abstractions/dbus-session-strict>
#include <abstractions/X>
#include <abstractions/fonts>
owner @{HOME}/.local/share/fonts/{,**} r,
/var/cache/fontconfig/ r,
/var/cache/fontconfig/** mr,
# subset of gnome abstraction
/etc/gnome/defaults.list r,
/usr/share/gnome/applications/ r,
/usr/share/applications/mimeinfo.cache r,
/etc/gtk-*/* r,
/usr/lib{,32,64}/gtk-*/** mr,
/usr/lib{,32,64}/gdk-pixbuf-*/** mr,
/usr/lib/@{multiarch}/gtk-*/** mr,
/usr/lib/@{multiarch}/gdk-pixbuf-*/** mr,
/etc/pango/* r,
/usr/lib{,32,64}/pango/** mr,
/usr/lib/@{multiarch}/pango/** mr,
/usr/share/icons/ r,
/usr/share/icons/** r,
/usr/share/icons/*/index.theme rk,
/usr/share/pixmaps/ r,
/usr/share/pixmaps/** r,
/usr/share/unity/icons/** r,
/usr/share/thumbnailer/icons/** r,
/usr/share/themes/** r,
# The snapcraft desktop part may look for schema files in various locations, so
# allow reading system installed schemas.
/usr/share/glib*/schemas/{,*} r,
/usr/share/gnome/glib*/schemas/{,*} r,
/usr/share/ubuntu/glib*/schemas/{,*} r,
# Snappy's 'xdg-open' talks to the snapd-xdg-open service which currently works
# only in environments supporting dbus-send (eg, X11). In the future once
# snappy's xdg-open supports all snaps images, this access may move to another
# interface.
/usr/bin/xdg-open ixr,
/usr/share/applications/{,*} r,
/usr/bin/dbus-send ixr,
# This allow access to the first version of the snapd-xdg-open
# version which was shipped outside of snapd
dbus (send)
bus=session
path=/
interface=com.canonical.SafeLauncher
member=OpenURL
peer=(label=unconfined),
# ... and this allows access to the new xdg-open service which
# is now part of snapd itself.
dbus (send)
bus=session
path=/io/snapcraft/Launcher
interface=io.snapcraft.Launcher
member=OpenURL
peer=(label=unconfined),
# input methods (ibus)
# subset of ibus abstraction
/usr/lib/@{multiarch}/gtk-2.0/[0-9]*/immodules/im-ibus.so mr,
owner @{HOME}/.config/ibus/ r,
owner @{HOME}/.config/ibus/bus/ r,
owner @{HOME}/.config/ibus/bus/* r,
# allow communicating with ibus-daemon (this allows sniffing key events)
unix (connect, receive, send)
type=stream
peer=(addr="@/tmp/ibus/dbus-*"),
# input methods (mozc)
# allow communicating with mozc server (TODO: investigate if allows sniffing)
unix (connect, receive, send)
type=stream
peer=(addr="@tmp/.mozc.*"),
# input methods (fcitx)
# allow communicating with fcitx dbus service
dbus send
bus=fcitx
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member={Hello,AddMatch,RemoveMatch,GetNameOwner,NameHasOwner,StartServiceByName}
peer=(name=org.freedesktop.DBus),
owner @{HOME}/.config/fcitx/dbus/* r,
# allow creating an input context
dbus send
bus={fcitx,session}
path=/inputmethod
interface=org.fcitx.Fcitx.InputMethod
member=CreateIC*
peer=(label=unconfined),
# allow setting up and tearing down the input context
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.fcitx.Fcitx.InputContext
member="{Close,Destroy,Enable}IC"
peer=(label=unconfined),
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.fcitx.Fcitx.InputContext
member=Reset
peer=(label=unconfined),
# allow service to send us signals
dbus receive
bus=fcitx
peer=(label=unconfined),
dbus receive
bus=session
interface=org.fcitx.Fcitx.*
peer=(label=unconfined),
# use the input context
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.fcitx.Fcitx.InputContext
member="Focus{In,Out}"
peer=(label=unconfined),
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.fcitx.Fcitx.InputContext
member="{CommitPreedit,Set*}"
peer=(label=unconfined),
# this is an information leak and allows key and mouse sniffing. If the input
# context path were tied to the process' security label, this would not be an
# issue.
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.fcitx.Fcitx.InputContext
member="{MouseEvent,ProcessKeyEvent}"
peer=(label=unconfined),
# this method does not exist with the sunpinyin backend (at least), so allow
# it for other input methods. This may consitute an information leak (which,
# again, could be avoided if the path were tied to the process' security
# label).
dbus send
bus={fcitx,session}
path=/inputcontext_[0-9]*
interface=org.freedesktop.DBus.Properties
member=GetAll
peer=(label=unconfined),
# Needed by QtSystems on X to detect mouse and keyboard. Note, the 'netlink
# raw' rule is not finely mediated by apparmor so we mediate with seccomp arg
# filtering.
network netlink raw,
/run/udev/data/c13:[0-9]* r,
/run/udev/data/+input:* r,
# subset of freedesktop.org
/usr/share/mime/** r,
owner @{HOME}/.local/share/mime/** r,
owner @{HOME}/.config/user-dirs.* r,
/etc/xdg/user-dirs.conf r,
/etc/xdg/user-dirs.defaults r,
# gtk settings (subset of gnome abstraction)
owner @{HOME}/.config/gtk-2.0/gtkfilechooser.ini r,
owner @{HOME}/.config/gtk-3.0/settings.ini r,
# Note: this leaks directory names that wouldn't otherwise be known to the snap
owner @{HOME}/.config/gtk-3.0/bookmarks r,
# accessibility
#include <abstractions/dbus-accessibility-strict>
dbus (send)
bus=session
path=/org/a11y/bus
interface=org.a11y.Bus
member=GetAddress
peer=(label=unconfined),
dbus (send)
bus=session
path=/org/a11y/bus
interface=org.freedesktop.DBus.Properties
member=Get{,All}
peer=(label=unconfined),
# unfortunate, but org.a11y.atspi is not designed for separation
dbus (receive, send)
bus=accessibility
path=/org/a11y/atspi/**
peer=(label=unconfined),
# org.freedesktop.Accounts
dbus (send)
bus=system
path=/org/freedesktop/Accounts
interface=org.freedesktop.DBus.Introspectable
member=Introspect
peer=(label=unconfined),
dbus (send)
bus=system
path=/org/freedesktop/Accounts
interface=org.freedesktop.Accounts
member=FindUserById
peer=(label=unconfined),
# Get() is an information leak
# TODO: verify what it is leaking
dbus (receive, send)
bus=system
path=/org/freedesktop/Accounts/User[0-9]*
interface=org.freedesktop.DBus.Properties
member={Get,PropertiesChanged}
peer=(label=unconfined),
# gmenu
# Note: the gmenu DBus api was not designed for application isolation and apps
# may specify anything as their 'path'. For example, these work in the many
# cases:
# - /org/gtk/Application/anonymous{,/**}
# - /com/canonical/unity/gtk/window/[0-9]*
# but libreoffice does:
# - /org/libreoffice{,/**}
# As such, cannot mediate by DBus path so we'll be as strict as we can in the
# other mediated parts
dbus (send)
bus=session
interface=org.gtk.Actions
member=Changed
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
interface=org.gtk.Actions
member={Activate,DescribeAll,SetState}
peer=(label=unconfined),
dbus (receive)
bus=session
interface=org.gtk.Menus
member={Start,End}
peer=(label=unconfined),
dbus (send)
bus=session
interface=org.gtk.Menus
member=Changed
peer=(name=org.freedesktop.DBus, label=unconfined),
# Ubuntu menus
dbus (send)
bus=session
path="/com/ubuntu/MenuRegistrar"
interface="com.ubuntu.MenuRegistrar"
member="{Register,Unregister}{App,Surface}Menu"
peer=(label=unconfined),
# url helper
dbus (send)
bus=session
interface=com.canonical.SafeLauncher.OpenURL
peer=(label=unconfined),
# new url helper (part of snap userd)
dbus (send)
bus=session
interface=io.snapcraft.Launcher.OpenURL
peer=(label=unconfined),
# dbusmenu
dbus (send)
bus=session
path=/{MenuBar{,/[0-9A-F]*},com/canonical/menu/[0-9A-F]*}
interface=com.canonical.dbusmenu
member="{LayoutUpdated,ItemsPropertiesUpdated}"
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
path=/{MenuBar{,/[0-9A-F]*},com/canonical/menu/[0-9A-F]*}
interface="{com.canonical.dbusmenu,org.freedesktop.DBus.Properties}"
member=Get*
peer=(label=unconfined),
dbus (receive)
bus=session
path=/{MenuBar{,/[0-9A-F]*},com/canonical/menu/[0-9A-F]*}
interface=com.canonical.dbusmenu
member="{AboutTo*,Event*}"
peer=(label=unconfined),
dbus (receive)
bus=session
path=/{MenuBar{,/[0-9A-F]*},com/canonical/menu/[0-9A-F]*}
interface=org.freedesktop.DBus.Introspectable
member=Introspect
peer=(label=unconfined),
# app-indicators
dbus (send)
bus=session
path=/StatusNotifierWatcher
interface=org.freedesktop.DBus.Introspectable
member=Introspect
peer=(name=org.kde.StatusNotifierWatcher, label=unconfined),
dbus (send)
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member="{GetConnectionUnixProcessID,RequestName,ReleaseName}"
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (bind)
bus=session
name=org.kde.StatusNotifierItem-[0-9]*,
dbus (send)
bus=session
path=/StatusNotifierWatcher
interface=org.freedesktop.DBus.Properties
member=Get
peer=(name=org.kde.StatusNotifierWatcher, label=unconfined),
dbus (send)
bus=session
path=/{StatusNotifierWatcher,org/ayatana/NotificationItem/*}
interface=org.kde.StatusNotifierWatcher
member=RegisterStatusNotifierItem
peer=(label=unconfined),
dbus (send)
bus=session
path=/{StatusNotifierItem,org/ayatana/NotificationItem/*}
interface=org.kde.StatusNotifierItem
member="New{AttentionIcon,Icon,IconThemePath,OverlayIcon,Status,Title,ToolTip}"
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
path=/{StatusNotifierItem,org/ayatana/NotificationItem/*}
interface=org.kde.StatusNotifierItem
member={Activate,ContextMenu,Scroll,SecondaryActivate,XAyatanaSecondaryActivate}
peer=(label=unconfined),
dbus (send)
bus=session
path=/{StatusNotifierItem/menu,org/ayatana/NotificationItem/*/Menu}
interface=com.canonical.dbusmenu
member="{LayoutUpdated,ItemsPropertiesUpdated}"
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
path=/{StatusNotifierItem,StatusNotifierItem/menu,org/ayatana/NotificationItem/**}
interface={org.freedesktop.DBus.Properties,com.canonical.dbusmenu}
member={Get*,AboutTo*,Event*}
peer=(label=unconfined),
# notifications
dbus (send)
bus=session
path=/org/freedesktop/Notifications
interface=org.freedesktop.Notifications
member="{GetCapabilities,GetServerInformation,Notify}"
peer=(label=unconfined),
dbus (receive)
bus=session
path=/org/freedesktop/Notifications
interface=org.freedesktop.Notifications
member={ActionInvoked,NotificationClosed}
peer=(label=unconfined),
dbus (send)
bus=session
path=/org/ayatana/NotificationItem/*
interface=org.kde.StatusNotifierItem
member=XAyatanaNew*
peer=(name=org.freedesktop.DBus, label=unconfined),
# unity launcher
dbus (send)
bus=session
path=/com/canonical/unity/launcherentry/[0-9]*
interface=com.canonical.Unity.LauncherEntry
member=Update
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (send)
bus=session
path=/com/canonical/unity/launcherentry/[0-9]*
interface=com.canonical.dbusmenu
member="{LayoutUpdated,ItemsPropertiesUpdated}"
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (receive)
bus=session
path=/com/canonical/unity/launcherentry/[0-9]*
interface="{com.canonical.dbusmenu,org.freedesktop.DBus.Properties}"
member=Get*
peer=(label=unconfined),
# unity messaging menu
# first, allow finding the desktop file
/usr/share/applications/ r,
# this leaks the names of snaps with desktop files
/var/lib/snapd/desktop/applications/ r,
/var/lib/snapd/desktop/applications/mimeinfo.cache r,
/var/lib/snapd/desktop/applications/@{SNAP_NAME}_*.desktop r,
# then allow talking to Unity DBus service
dbus (send)
bus=session
interface=org.freedesktop.DBus.Properties
path=/com/canonical/indicator/messages/service
member=GetAll
peer=(label=unconfined),
dbus (send)
bus=session
path=/com/canonical/indicator/messages/service
interface=com.canonical.indicator.messages.service
member={Register,Unregister}Application
peer=(label=unconfined),
dbus (receive)
bus=session
interface=org.freedesktop.DBus.Properties
path=/com/canonical/indicator/messages/###UNITY_SNAP_NAME###_*_desktop
member=GetAll
peer=(label=unconfined),
dbus (receive, send)
bus=session
interface=com.canonical.indicator.messages.application
path=/com/canonical/indicator/messages/###UNITY_SNAP_NAME###_*_desktop
peer=(label=unconfined),
# This rule is meant to be covered by abstractions/dbus-session-strict but
# the unity launcher code has a typo that uses /org/freedesktop/dbus as the
# path instead of /org/freedesktop/DBus, so we need to all it here.
dbus (send)
bus=session
path=/org/freedesktop/dbus
interface=org.freedesktop.DBus
member=NameHasOwner
peer=(name=org.freedesktop.DBus, label=unconfined),
# appmenu
dbus (send)
bus=session
path=/org/freedesktop/DBus
interface=org.freedesktop.DBus
member=ListNames
peer=(name=org.freedesktop.DBus, label=unconfined),
dbus (send)
bus=session
path=/com/canonical/AppMenu/Registrar
interface=com.canonical.AppMenu.Registrar
member="{RegisterWindow,UnregisterWindow}"
peer=(label=unconfined),
dbus (send)
bus=session
path=/com/canonical/AppMenu/Registrar
interface=com.canonical.dbusmenu
member=UnregisterWindow
peer=(label=unconfined),
dbus (receive)
bus=session
path=/com/canonical/menu/[0-9]*
interface="{org.freedesktop.DBus.Properties,com.canonical.dbusmenu}"
member="{GetAll,GetLayout}"
peer=(label=unconfined),
# Allow requesting interest in receiving media key events. This tells Gnome
# settings that our application should be notified when key events we are
# interested in are pressed, and allows us to receive those events.
dbus (receive, send)
bus=session
interface=org.gnome.SettingsDaemon.MediaKeys
path=/org/gnome/SettingsDaemon/MediaKeys
peer=(label=unconfined),
dbus (send)
bus=session
interface=org.freedesktop.DBus.Properties
path=/org/gnome/SettingsDaemon/MediaKeys
member="Get{,All}"
peer=(label=unconfined),
# Allow checking status, activating and locking the screensaver
# mate
dbus (send)
bus=session
path="/{,org/mate/}ScreenSaver"
interface=org.mate.ScreenSaver
member="{GetActive,GetActiveTime,Lock,SetActive}"
peer=(label=unconfined),
dbus (receive)
bus=session
path="/{,org/mate/}ScreenSaver"
interface=org.mate.ScreenSaver
member=ActiveChanged
peer=(label=unconfined),
# Unity
dbus (send)
bus=session
interface=com.canonical.Unity.Session
path=/com/canonical/Unity/Session
member="{ActivateScreenSaver,IsLocked,Lock}"
peer=(label=unconfined),
`
const unity7ConnectedPlugSeccomp = `
# Description: Can access Unity7. Note, Unity 7 runs on X and requires access
# to various DBus services and this environment does not prevent eavesdropping
# or apps interfering with one another.
# Needed by QtSystems on X to detect mouse and keyboard
socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
bind
`
type unity7Interface struct{}
func (iface *unity7Interface) Name() string {
return "unity7"
}
func (iface *unity7Interface) StaticInfo() interfaces.StaticInfo {
return interfaces.StaticInfo{
Summary: unity7Summary,
ImplicitOnClassic: true,
BaseDeclarationSlots: unity7BaseDeclarationSlots,
}
}
func (iface *unity7Interface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
// Unity7 will take the desktop filename and convert all '-' (and '.',
// but we don't care about that here because the rule above already
// does that) to '_'. Since we know that the desktop filename starts
// with the snap name, perform this conversion on the snap name.
new := strings.Replace(plug.Snap().Name(), "-", "_", -1)
old := "###UNITY_SNAP_NAME###"
snippet := strings.Replace(unity7ConnectedPlugAppArmor, old, new, -1)
spec.AddSnippet(snippet)
return nil
}
func (iface *unity7Interface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
spec.AddSnippet(unity7ConnectedPlugSeccomp)
return nil
}
func (iface *unity7Interface) BeforePrepareSlot(slot *snap.SlotInfo) error {
return sanitizeSlotReservedForOS(iface, slot)
}
func (iface *unity7Interface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
// allow what declarations allowed
return true
}
func init() {
registerIface(&unity7Interface{})
}