github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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 in gnome-shell reads this
    80  /etc/opt/chrome/{,**} r,
    81  /etc/chromium/{,**} r,
    82  
    83  # Chrome/Chromium should be adjusted to not use gconf. It is only used with
    84  # legacy systems that don't have snapd
    85  deny dbus (send)
    86      bus=session
    87      interface="org.gnome.GConf.Server",
    88  
    89  # webbrowser-app/webapp-container tries to read this file to determine if it is
    90  # confined or not, so explicitly deny to avoid noise in the logs.
    91  deny @{PROC}/@{pid}/attr/current r,
    92  
    93  # This is an information leak but disallowing it leads to developer confusion
    94  # when using the chromium content api file chooser due to a (harmless) glib
    95  # warning and the noisy AppArmor denial.
    96  owner @{PROC}/@{pid}/mounts r,
    97  owner @{PROC}/@{pid}/mountinfo r,
    98  
    99  # Since snapd still uses SECCOMP_RET_KILL, we have added a workaround rule to
   100  # allow mknod on character devices since chromium unconditionally performs
   101  # a mknod() to create the /dev/nvidiactl device, regardless of if it exists or
   102  # not or if the process has CAP_MKNOD or not. Since we don't want to actually
   103  # grant the ability to create character devices, explicitly deny the
   104  # capability. When snapd uses SECCOMP_RET_ERRNO, we can remove this rule.
   105  # https://forum.snapcraft.io/t/call-for-testing-chromium-62-0-3202-62/2569/46
   106  deny capability mknod,
   107  `
   108  
   109  const browserSupportConnectedPlugAppArmorWithSandbox = `
   110  # Leaks installed applications
   111  # TODO: should this be somewhere else?
   112  /etc/mailcap r,
   113  # Snaps should be using xdg-open from the runtime instead of reading these
   114  # files directly since the snap is unable to do anything with these files
   115  # but these accesses have been allowed for a long time and remain so as not
   116  # to break existing snaps. These could be changed to explicit deny rules,
   117  # but that provides a worse debugging experience. Combined, the risks
   118  # outweigh the benefits of closing this information leak for the small
   119  # number of snaps allowed to use allow-sandbox: true. Reference:
   120  # https://forum.snapcraft.io/t/cannot-open-pdf-attachment-with-thunderbird/11845
   121  /usr/share/applications/{,*} r,
   122  /var/lib/snapd/desktop/applications/{,*} r,
   123  owner @{PROC}/@{pid}/fd/[0-9]* w,
   124  
   125  # Various files in /run/udev/data needed by Chrome Settings. Leaks device
   126  # information.
   127  # input
   128  /run/udev/data/c1:[0-9]* r,   # /dev/psaux
   129  /run/udev/data/c10:[0-9]* r,  # /dev/adbmouse
   130  /run/udev/data/c13:[0-9]* r,  # /dev/input/*
   131  /run/udev/data/c180:[0-9]* r, # /dev/vrbuttons
   132  /run/udev/data/c4:[0-9]* r,   # /dev/tty*, /dev/ttyS*
   133  /run/udev/data/c5:[0-9]* r,   # /dev/tty, /dev/console, etc
   134  /run/udev/data/c7:[0-9]* r,   # /dev/vcs*
   135  /run/udev/data/+hid:* r,
   136  /run/udev/data/+input:input[0-9]* r,
   137  
   138  # screen
   139  /run/udev/data/c29:[0-9]* r,  # /dev/fb*
   140  /run/udev/data/+backlight:* r,
   141  /run/udev/data/+leds:* r,
   142  
   143  # sound
   144  /run/udev/data/c116:[0-9]* r, # alsa
   145  /run/udev/data/+sound:card[0-9]* r,
   146  
   147  # miscellaneous
   148  /run/udev/data/c108:[0-9]* r, # /dev/ppp
   149  /run/udev/data/c189:[0-9]* r, # USB serial converters
   150  /run/udev/data/c89:[0-9]* r,  # /dev/i2c-*
   151  /run/udev/data/c81:[0-9]* r,  # video4linux (/dev/video*, etc)
   152  /run/udev/data/c202:[0-9]* r, # /dev/cpu/*/msr
   153  /run/udev/data/c203:[0-9]* r, # /dev/cuse
   154  /run/udev/data/+acpi:* r,
   155  /run/udev/data/+hwmon:hwmon[0-9]* r,
   156  /run/udev/data/+i2c:* r,
   157  /sys/devices/**/bConfigurationValue r,
   158  /sys/devices/**/descriptors r,
   159  /sys/devices/**/manufacturer r,
   160  /sys/devices/**/product r,
   161  /sys/devices/**/revision r,
   162  /sys/devices/**/serial r,
   163  /sys/devices/**/vendor r,
   164  /sys/devices/system/node/node[0-9]*/meminfo r,
   165  
   166  # Chromium content api tries to read these. It is an information disclosure
   167  # since these contain the names of snaps. Chromium operates fine without the
   168  # access so just block it.
   169  deny /sys/devices/virtual/block/loop[0-9]*/loop/backing_file r,
   170  deny /sys/devices/virtual/block/dm-[0-9]*/dm/name r,
   171  
   172  # networking
   173  /run/udev/data/n[0-9]* r,
   174  /run/udev/data/+bluetooth:hci[0-9]* r,
   175  /run/udev/data/+rfkill:rfkill[0-9]* r,
   176  /run/udev/data/c241:[0-9]* r, # /dev/vhost-vsock
   177  
   178  # storage
   179  /run/udev/data/b1:[0-9]* r,   # /dev/ram*
   180  /run/udev/data/b7:[0-9]* r,   # /dev/loop*
   181  /run/udev/data/b8:[0-9]* r,   # /dev/sd*
   182  /run/udev/data/b11:[0-9]* r,  # /dev/scd* and sr*
   183  /run/udev/data/b230:[0-9]* r, # /dev/zvol*
   184  /run/udev/data/c21:[0-9]* r,  # /dev/sg*
   185  /run/udev/data/+usb:[0-9]* r,
   186  
   187  # experimental
   188  /run/udev/data/b252:[0-9]* r,
   189  /run/udev/data/b253:[0-9]* r,
   190  /run/udev/data/b259:[0-9]* r,
   191  /run/udev/data/c24[0-9]:[0-9]* r,
   192  /run/udev/data/c25[0-4]:[0-9]* r,
   193  
   194  /sys/bus/**/devices/ r,
   195  
   196  # Google Cloud Print
   197  unix (bind)
   198       type=stream
   199       addr="@[0-9A-F]*._service_*",
   200  
   201  # Policy needed only when using the chrome/chromium setuid sandbox
   202  capability sys_ptrace,
   203  ptrace (trace) peer=snap.@{SNAP_INSTANCE_NAME}.**,
   204  unix (receive, send) peer=(label=snap.@{SNAP_INSTANCE_NAME}.**),
   205  
   206  # If this were going to be allowed to all snaps, then for all the following
   207  # rules we would want to wrap in a 'browser_sandbox' profile, but a limitation
   208  # in AppArmor profile transitions prevents this.
   209  #
   210  # @{INSTALL_DIR}/@{SNAP_NAME}/@{SNAP_REVISION}/opt/google/chrome{,-beta,-unstable}/chrome-sandbox cx -> browser_sandbox,
   211  # profile browser_sandbox {
   212  #   ...
   213  #   # This rule needs to work but generates a parser error
   214  #   @{INSTALL_DIR}/@{SNAP_NAME}/@{SNAP_REVISION}/opt/google/chrome/chrome px -> snap.@{SNAP_INSTANCE_NAME}.@{SNAP_APP},
   215  #   @{INSTALL_DIR}/@{SNAP_INSTANCE_NAME}/@{SNAP_REVISION}/opt/google/chrome/chrome px -> snap.@{SNAP_INSTANCE_NAME}.@{SNAP_APP},
   216  #   ...
   217  # }
   218  
   219  # Required for dropping into PID namespace. Keep in mind that until the
   220  # process drops this capability it can escape confinement, but once it
   221  # drops CAP_SYS_ADMIN we are ok.
   222  capability sys_admin,
   223  
   224  # All of these are for sanely dropping from root and chrooting
   225  capability chown,
   226  capability fsetid,
   227  capability setgid,
   228  capability setuid,
   229  capability sys_chroot,
   230  
   231  # User namespace sandbox
   232  owner @{PROC}/@{pid}/setgroups rw,
   233  owner @{PROC}/@{pid}/uid_map rw,
   234  owner @{PROC}/@{pid}/gid_map rw,
   235  
   236  # Webkit uses a particular SHM names # LP: 1578217
   237  owner /{dev,run}/shm/WK2SharedMemory.* mrw,
   238  
   239  # Chromium content api on (at least) later versions of Ubuntu just use this
   240  owner /{dev,run}/shm/shmfd-* mrw,
   241  
   242  # Clearing the PG_Referenced and ACCESSED/YOUNG bits provides a method to
   243  # measure approximately how much memory a process is using via /proc/self/smaps
   244  # (man 5 proc). This access allows the snap to clear references for pids from
   245  # other snaps and the system, so it is limited to snaps that specify:
   246  # allow-sandbox: true.
   247  owner @{PROC}/@{pid}/clear_refs w,
   248  `
   249  
   250  const browserSupportConnectedPlugSecComp = `
   251  # Description: Can access various APIs needed by modern browsers (eg, Google
   252  # Chrome/Chromium and Mozilla) and file paths they expect. This interface is
   253  # transitional and is only in place while upstream's work to change their paths
   254  # and snappy is updated to properly mediate the APIs.
   255  
   256  # for anonymous sockets
   257  bind
   258  listen
   259  accept
   260  accept4
   261  
   262  # TODO: fine-tune when seccomp arg filtering available in stable distro
   263  # releases
   264  setpriority
   265  
   266  # Since snapd still uses SECCOMP_RET_KILL, add a workaround rule to allow mknod
   267  # on character devices since chromium unconditionally performs a mknod() to
   268  # create the /dev/nvidiactl device, regardless of if it exists or not or if the
   269  # process has CAP_MKNOD or not. Since we don't want to actually grant the
   270  # ability to create character devices, we added an explicit deny AppArmor rule
   271  # for this capability. When snapd uses SECCOMP_RET_ERRNO, we can remove this
   272  # rule.
   273  # https://forum.snapcraft.io/t/call-for-testing-chromium-62-0-3202-62/2569/46
   274  mknod - |S_IFCHR -
   275  mknodat - - |S_IFCHR -
   276  `
   277  
   278  const browserSupportConnectedPlugSecCompWithSandbox = `
   279  # Policy needed only when using the chrome/chromium setuid sandbox
   280  chroot
   281  sched_setscheduler
   282  
   283  # TODO: fine-tune when seccomp arg filtering available in stable distro
   284  # releases
   285  setuid
   286  setgid
   287  
   288  # Policy needed for Mozilla userns sandbox
   289  unshare
   290  quotactl
   291  
   292  # The Breakpad crash reporter uses ptrace to read register/memory state
   293  # from the crashed process, but it doesn't need to modify any state; see
   294  # https://bugzilla.mozilla.org/show_bug.cgi?id=1461848.
   295  #
   296  # These rules allow that but don't allow ptrace operations that
   297  # write registers, which can be used to bypass security; see
   298  # https://lkml.org/lkml/2016/5/26/354.
   299  ptrace PTRACE_ATTACH
   300  ptrace PTRACE_DETACH
   301  ptrace PTRACE_GETREGS
   302  ptrace PTRACE_GETFPREGS
   303  ptrace PTRACE_GETFPXREGS
   304  ptrace PTRACE_GETREGSET
   305  ptrace PTRACE_PEEKDATA
   306  ptrace PTRACE_PEEKUSER
   307  ptrace PTRACE_CONT
   308  `
   309  
   310  type browserSupportInterface struct{}
   311  
   312  func (iface *browserSupportInterface) Name() string {
   313  	return "browser-support"
   314  }
   315  
   316  func (iface *browserSupportInterface) StaticInfo() interfaces.StaticInfo {
   317  	return interfaces.StaticInfo{
   318  		Summary:              browserSupportSummary,
   319  		ImplicitOnCore:       true,
   320  		ImplicitOnClassic:    true,
   321  		BaseDeclarationSlots: browserSupportBaseDeclarationSlots,
   322  	}
   323  }
   324  
   325  func (iface *browserSupportInterface) BeforePreparePlug(plug *snap.PlugInfo) error {
   326  	// It's fine if allow-sandbox isn't specified, but it it is,
   327  	// it needs to be bool
   328  	if v, ok := plug.Attrs["allow-sandbox"]; ok {
   329  		if _, ok = v.(bool); !ok {
   330  			return fmt.Errorf("browser-support plug requires bool with 'allow-sandbox'")
   331  		}
   332  	}
   333  
   334  	return nil
   335  }
   336  
   337  func (iface *browserSupportInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   338  	var allowSandbox bool
   339  	_ = plug.Attr("allow-sandbox", &allowSandbox)
   340  	spec.AddSnippet(browserSupportConnectedPlugAppArmor)
   341  	if allowSandbox {
   342  		spec.AddSnippet(browserSupportConnectedPlugAppArmorWithSandbox)
   343  	} else {
   344  		spec.SetSuppressPtraceTrace()
   345  	}
   346  	return nil
   347  }
   348  
   349  func (iface *browserSupportInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   350  	var allowSandbox bool
   351  	_ = plug.Attr("allow-sandbox", &allowSandbox)
   352  	snippet := browserSupportConnectedPlugSecComp
   353  	if allowSandbox {
   354  		snippet += browserSupportConnectedPlugSecCompWithSandbox
   355  	}
   356  	spec.AddSnippet(snippet)
   357  	return nil
   358  }
   359  
   360  func (iface *browserSupportInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
   361  	return true
   362  }
   363  
   364  func init() {
   365  	registerIface(&browserSupportInterface{})
   366  }