github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/browser_support.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-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  	"fmt"
    24  
    25  	"github.com/snapcore/snapd/interfaces"
    26  	"github.com/snapcore/snapd/interfaces/apparmor"
    27  	"github.com/snapcore/snapd/interfaces/seccomp"
    28  	"github.com/snapcore/snapd/snap"
    29  )
    30  
    31  const browserSupportSummary = `allows access to various APIs needed by modern web browsers`
    32  
    33  const browserSupportBaseDeclarationSlots = `
    34    browser-support:
    35      allow-installation:
    36        slot-snap-type:
    37          - core
    38      deny-connection:
    39        plug-attributes:
    40          allow-sandbox: true
    41      deny-auto-connection:
    42        plug-attributes:
    43          allow-sandbox: true
    44  `
    45  
    46  const browserSupportConnectedPlugAppArmor = `
    47  # Description: Can access various APIs needed by modern browsers (eg, Google
    48  # Chrome/Chromium and Mozilla) and file paths they expect. This interface is
    49  # transitional and is only in place while upstream's work to change their paths
    50  # and snappy is updated to properly mediate the APIs.
    51  
    52  # This allows raising the OOM score of other processes owned by the user.
    53  owner @{PROC}/@{pid}/oom_score_adj rw,
    54  
    55  # Chrome/Chromium should be fixed to honor TMPDIR or the snap packaging
    56  # adjusted to use LD_PRELOAD technique from LP: #1577514
    57  /var/tmp/ r,
    58  owner /var/tmp/etilqs_* rw,
    59  
    60  # Chrome/Chromium should be modified to use snap.$SNAP_INSTANCE_NAME.* or
    61  # the snap packaging adjusted to use LD_PRELOAD technique from LP: #1577514
    62  owner /{dev,run}/shm/{,.}org.chromium.* mrw,
    63  owner /{dev,run}/shm/{,.}com.google.Chrome.* mrw,
    64  owner /{dev,run}/shm/.io.nwjs.* mrw,
    65  
    66  # Chrome's Singleton API sometimes causes an ouid/fsuid mismatch denial, so
    67  # for now, allow non-owner read on the singleton socket (LP: #1731012). See
    68  # https://forum.snapcraft.io/t/electron-snap-killed-when-using-app-makesingleinstance-api/2667/20
    69  # parallel-installs: $XDG_RUNTIME_DIR is not remapped, need to use SNAP_INSTANCE_NAME
    70  /run/user/[0-9]*/snap.@{SNAP_INSTANCE_NAME}/{,.}org.chromium.*/SS r,
    71  /run/user/[0-9]*/snap.@{SNAP_INSTANCE_NAME}/{,.}com.google.Chrome.*/SS r,
    72  
    73  # Allow reading platform files
    74  /run/udev/data/+platform:* r,
    75  
    76  # miscellaneous accesses
    77  @{PROC}/vmstat r,
    78  
    79  # Chromium content api sometimes queries about huge pages. Allow status of
    80  # hugepages and transparent_hugepage, but not the pages themselves.
    81  /sys/kernel/mm/{hugepages,transparent_hugepage}/{,**} r,
    82  
    83  # Chromium content api in gnome-shell reads this
    84  /etc/opt/chrome/{,**} r,
    85  /etc/chromium/{,**} r,
    86  
    87  # Chrome/Chromium should be adjusted to not use gconf. It is only used with
    88  # legacy systems that don't have snapd
    89  deny dbus (send)
    90      bus=session
    91      interface="org.gnome.GConf.Server",
    92  
    93  # webbrowser-app/webapp-container tries to read this file to determine if it is
    94  # confined or not, so explicitly deny to avoid noise in the logs.
    95  deny @{PROC}/@{pid}/attr/{,apparmor/}current r,
    96  
    97  # This is an information leak but disallowing it leads to developer confusion
    98  # when using the chromium content api file chooser due to a (harmless) glib
    99  # warning and the noisy AppArmor denial.
   100  owner @{PROC}/@{pid}/mounts r,
   101  owner @{PROC}/@{pid}/mountinfo r,
   102  
   103  # Since snapd still uses SECCOMP_RET_KILL, we have added a workaround rule to
   104  # allow mknod on character devices since chromium unconditionally performs
   105  # a mknod() to create the /dev/nvidiactl device, regardless of if it exists or
   106  # not or if the process has CAP_MKNOD or not. Since we don't want to actually
   107  # grant the ability to create character devices, explicitly deny the
   108  # capability. When snapd uses SECCOMP_RET_ERRNO, we can remove this rule.
   109  # https://forum.snapcraft.io/t/call-for-testing-chromium-62-0-3202-62/2569/46
   110  deny capability mknod,
   111  `
   112  
   113  const browserSupportConnectedPlugAppArmorWithSandbox = `
   114  # TODO: should this be somewhere else?
   115  /etc/mailcap r,
   116  
   117  # While /usr/share/applications comes from the base runtime of the snap, it
   118  # has some things that snaps actually need, so allow access to those and deny
   119  # access to the others. This is duplicated from desktop for compatibility with
   120  # existing snaps.
   121  /usr/share/applications/ r,
   122  /usr/share/applications/mimeapps.list r,
   123  /usr/share/applications/xdg-open.desktop r,
   124  # silence noisy denials from desktop files in core* snaps that aren't usable by
   125  # snaps
   126  deny /usr/share/applications/python*.desktop r,
   127  deny /usr/share/applications/vim.desktop r,
   128  deny /usr/share/applications/snap-handle-link.desktop r,  # core16
   129  
   130  # Chromium content api unfortunately needs these for normal operation
   131  owner @{PROC}/@{pid}/fd/[0-9]* w,
   132  
   133  # Various files in /run/udev/data needed by Chrome Settings. Leaks device
   134  # information.
   135  # input
   136  /run/udev/data/c1:[0-9]* r,   # /dev/psaux
   137  /run/udev/data/c10:[0-9]* r,  # /dev/adbmouse
   138  /run/udev/data/c13:[0-9]* r,  # /dev/input/*
   139  /run/udev/data/c180:[0-9]* r, # /dev/vrbuttons
   140  /run/udev/data/c4:[0-9]* r,   # /dev/tty*, /dev/ttyS*
   141  /run/udev/data/c5:[0-9]* r,   # /dev/tty, /dev/console, etc
   142  /run/udev/data/c7:[0-9]* r,   # /dev/vcs*
   143  /run/udev/data/+hid:* r,
   144  /run/udev/data/+input:input[0-9]* r,
   145  
   146  # screen
   147  /run/udev/data/c29:[0-9]* r,  # /dev/fb*
   148  /run/udev/data/+backlight:* r,
   149  /run/udev/data/+leds:* r,
   150  
   151  # sound
   152  /run/udev/data/c116:[0-9]* r, # alsa
   153  /run/udev/data/+sound:card[0-9]* r,
   154  
   155  # miscellaneous
   156  /run/udev/data/c108:[0-9]* r, # /dev/ppp
   157  /run/udev/data/c189:[0-9]* r, # USB serial converters
   158  /run/udev/data/c89:[0-9]* r,  # /dev/i2c-*
   159  /run/udev/data/c81:[0-9]* r,  # video4linux (/dev/video*, etc)
   160  /run/udev/data/c202:[0-9]* r, # /dev/cpu/*/msr
   161  /run/udev/data/c203:[0-9]* r, # /dev/cuse
   162  /run/udev/data/+acpi:* r,
   163  /run/udev/data/+hwmon:hwmon[0-9]* r,
   164  /run/udev/data/+i2c:* r,
   165  /sys/devices/**/bConfigurationValue r,
   166  /sys/devices/**/descriptors r,
   167  /sys/devices/**/manufacturer r,
   168  /sys/devices/**/product r,
   169  /sys/devices/**/revision r,
   170  /sys/devices/**/serial r,
   171  /sys/devices/**/vendor r,
   172  /sys/devices/system/node/node[0-9]*/meminfo r,
   173  
   174  # Allow getting the manufacturer and model of the
   175  # computer where Chrome/chromium is currently running.
   176  # This is going to be used by the upcoming Hardware Platform
   177  # extension API.
   178  # https://chromium.googlesource.com/chromium/src.git/+/84618eee98fdf7548905e883e63e4f693800fcfa
   179  /sys/devices/virtual/dmi/id/product_name r,
   180  /sys/devices/virtual/dmi/id/sys_vendor r,
   181  
   182  # Chromium content api tries to read these. It is an information disclosure
   183  # since these contain the names of snaps. Chromium operates fine without the
   184  # access so just block it.
   185  deny /sys/devices/virtual/block/loop[0-9]*/loop/backing_file r,
   186  deny /sys/devices/virtual/block/dm-[0-9]*/dm/name r,
   187  
   188  # networking
   189  /run/udev/data/n[0-9]* r,
   190  /run/udev/data/+bluetooth:hci[0-9]* r,
   191  /run/udev/data/+rfkill:rfkill[0-9]* r,
   192  /run/udev/data/c241:[0-9]* r, # /dev/vhost-vsock
   193  
   194  # storage
   195  /run/udev/data/b1:[0-9]* r,   # /dev/ram*
   196  /run/udev/data/b7:[0-9]* r,   # /dev/loop*
   197  /run/udev/data/b8:[0-9]* r,   # /dev/sd*
   198  /run/udev/data/b11:[0-9]* r,  # /dev/scd* and sr*
   199  /run/udev/data/b230:[0-9]* r, # /dev/zvol*
   200  /run/udev/data/c21:[0-9]* r,  # /dev/sg*
   201  /run/udev/data/+usb:[0-9]* r,
   202  
   203  # experimental
   204  /run/udev/data/b252:[0-9]* r,
   205  /run/udev/data/b253:[0-9]* r,
   206  /run/udev/data/b259:[0-9]* r,
   207  /run/udev/data/c24[0-9]:[0-9]* r,
   208  /run/udev/data/c25[0-4]:[0-9]* r,
   209  
   210  /sys/bus/**/devices/ r,
   211  
   212  # Google Cloud Print
   213  unix (bind)
   214       type=stream
   215       addr="@[0-9A-F]*._service_*",
   216  
   217  # Policy needed only when using the chrome/chromium setuid sandbox
   218  capability sys_ptrace,
   219  ptrace (trace) peer=snap.@{SNAP_INSTANCE_NAME}.**,
   220  unix (receive, send) peer=(label=snap.@{SNAP_INSTANCE_NAME}.**),
   221  
   222  # If this were going to be allowed to all snaps, then for all the following
   223  # rules we would want to wrap in a 'browser_sandbox' profile, but a limitation
   224  # in AppArmor profile transitions prevents this.
   225  #
   226  # @{INSTALL_DIR}/@{SNAP_NAME}/@{SNAP_REVISION}/opt/google/chrome{,-beta,-unstable}/chrome-sandbox cx -> browser_sandbox,
   227  # profile browser_sandbox {
   228  #   ...
   229  #   # This rule needs to work but generates a parser error
   230  #   @{INSTALL_DIR}/@{SNAP_NAME}/@{SNAP_REVISION}/opt/google/chrome/chrome px -> snap.@{SNAP_INSTANCE_NAME}.@{SNAP_APP},
   231  #   @{INSTALL_DIR}/@{SNAP_INSTANCE_NAME}/@{SNAP_REVISION}/opt/google/chrome/chrome px -> snap.@{SNAP_INSTANCE_NAME}.@{SNAP_APP},
   232  #   ...
   233  # }
   234  
   235  # Required for dropping into PID namespace. Keep in mind that until the
   236  # process drops this capability it can escape confinement, but once it
   237  # drops CAP_SYS_ADMIN we are ok.
   238  capability sys_admin,
   239  
   240  # All of these are for sanely dropping from root and chrooting
   241  capability chown,
   242  capability fsetid,
   243  capability setgid,
   244  capability setuid,
   245  capability sys_chroot,
   246  
   247  # User namespace sandbox
   248  owner @{PROC}/@{pid}/setgroups rw,
   249  owner @{PROC}/@{pid}/uid_map rw,
   250  owner @{PROC}/@{pid}/gid_map rw,
   251  
   252  # Webkit uses a particular SHM names # LP: 1578217
   253  owner /{dev,run}/shm/WK2SharedMemory.* mrw,
   254  
   255  # Chromium content api on (at least) later versions of Ubuntu just use this
   256  owner /{dev,run}/shm/shmfd-* mrw,
   257  
   258  # Clearing the PG_Referenced and ACCESSED/YOUNG bits provides a method to
   259  # measure approximately how much memory a process is using via /proc/self/smaps
   260  # (man 5 proc). This access allows the snap to clear references for pids from
   261  # other snaps and the system, so it is limited to snaps that specify:
   262  # allow-sandbox: true.
   263  owner @{PROC}/@{pid}/clear_refs w,
   264  
   265  # Allow setting realtime priorities. Clients require RLIMIT_RTTIME in the first
   266  # place and client authorization is done via PolicyKit. Note that setrlimit()
   267  # is allowed by default seccomp policy but requires 'capability sys_resource',
   268  # which we deny be default.
   269  # http://git.0pointer.net/rtkit.git/tree/README
   270  dbus (send)
   271      bus=system
   272      path=/org/freedesktop/RealtimeKit1
   273      interface=org.freedesktop.DBus.Properties
   274      member=Get
   275      peer=(name=org.freedesktop.RealtimeKit1, label=unconfined),
   276  dbus (send)
   277      bus=system
   278      path=/org/freedesktop/RealtimeKit1
   279      interface=org.freedesktop.RealtimeKit1
   280      member=MakeThread{HighPriority,Realtime}
   281      peer=(name=org.freedesktop.RealtimeKit1, label=unconfined),
   282  `
   283  
   284  const browserSupportConnectedPlugSecComp = `
   285  # Description: Can access various APIs needed by modern browsers (eg, Google
   286  # Chrome/Chromium and Mozilla) and file paths they expect. This interface is
   287  # transitional and is only in place while upstream's work to change their paths
   288  # and snappy is updated to properly mediate the APIs.
   289  
   290  # for anonymous sockets
   291  bind
   292  listen
   293  accept
   294  accept4
   295  
   296  # TODO: fine-tune when seccomp arg filtering available in stable distro
   297  # releases
   298  setpriority
   299  
   300  # Since snapd still uses SECCOMP_RET_KILL, add a workaround rule to allow mknod
   301  # on character devices since chromium unconditionally performs a mknod() to
   302  # create the /dev/nvidiactl device, regardless of if it exists or not or if the
   303  # process has CAP_MKNOD or not. Since we don't want to actually grant the
   304  # ability to create character devices, we added an explicit deny AppArmor rule
   305  # for this capability. When snapd uses SECCOMP_RET_ERRNO, we can remove this
   306  # rule.
   307  # https://forum.snapcraft.io/t/call-for-testing-chromium-62-0-3202-62/2569/46
   308  mknod - |S_IFCHR -
   309  mknodat - - |S_IFCHR -
   310  `
   311  
   312  const browserSupportConnectedPlugSecCompWithSandbox = `
   313  # Policy needed only when using the chrome/chromium setuid sandbox
   314  chroot
   315  sched_setscheduler
   316  
   317  # TODO: fine-tune when seccomp arg filtering available in stable distro
   318  # releases
   319  setuid
   320  setgid
   321  
   322  # Policy needed for Mozilla userns sandbox
   323  unshare
   324  quotactl
   325  
   326  # The Breakpad crash reporter uses ptrace to read register/memory state
   327  # from the crashed process, but it doesn't need to modify any state; see
   328  # https://bugzilla.mozilla.org/show_bug.cgi?id=1461848.
   329  #
   330  # These rules allow that but don't allow ptrace operations that
   331  # write registers, which can be used to bypass security; see
   332  # https://lkml.org/lkml/2016/5/26/354.
   333  ptrace PTRACE_ATTACH
   334  ptrace PTRACE_DETACH
   335  ptrace PTRACE_GETREGS
   336  ptrace PTRACE_GETFPREGS
   337  ptrace PTRACE_GETFPXREGS
   338  ptrace PTRACE_GETREGSET
   339  ptrace PTRACE_PEEKDATA
   340  ptrace PTRACE_PEEKUSER
   341  ptrace PTRACE_CONT
   342  `
   343  
   344  type browserSupportInterface struct{}
   345  
   346  func (iface *browserSupportInterface) Name() string {
   347  	return "browser-support"
   348  }
   349  
   350  func (iface *browserSupportInterface) StaticInfo() interfaces.StaticInfo {
   351  	return interfaces.StaticInfo{
   352  		Summary:              browserSupportSummary,
   353  		ImplicitOnCore:       true,
   354  		ImplicitOnClassic:    true,
   355  		BaseDeclarationSlots: browserSupportBaseDeclarationSlots,
   356  	}
   357  }
   358  
   359  func (iface *browserSupportInterface) BeforePreparePlug(plug *snap.PlugInfo) error {
   360  	// It's fine if allow-sandbox isn't specified, but it it is,
   361  	// it needs to be bool
   362  	if v, ok := plug.Attrs["allow-sandbox"]; ok {
   363  		if _, ok = v.(bool); !ok {
   364  			return fmt.Errorf("browser-support plug requires bool with 'allow-sandbox'")
   365  		}
   366  	}
   367  
   368  	return nil
   369  }
   370  
   371  func (iface *browserSupportInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   372  	var allowSandbox bool
   373  	_ = plug.Attr("allow-sandbox", &allowSandbox)
   374  	spec.AddSnippet(browserSupportConnectedPlugAppArmor)
   375  	if allowSandbox {
   376  		spec.AddSnippet(browserSupportConnectedPlugAppArmorWithSandbox)
   377  	} else {
   378  		spec.SetSuppressPtraceTrace()
   379  	}
   380  	return nil
   381  }
   382  
   383  func (iface *browserSupportInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   384  	var allowSandbox bool
   385  	_ = plug.Attr("allow-sandbox", &allowSandbox)
   386  	snippet := browserSupportConnectedPlugSecComp
   387  	if allowSandbox {
   388  		snippet += browserSupportConnectedPlugSecCompWithSandbox
   389  	}
   390  	spec.AddSnippet(snippet)
   391  	return nil
   392  }
   393  
   394  func (iface *browserSupportInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
   395  	return true
   396  }
   397  
   398  func init() {
   399  	registerIface(&browserSupportInterface{})
   400  }