github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/interfaces/builtin/x11.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2018 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  	"strings"
    25  
    26  	"github.com/snapcore/snapd/interfaces"
    27  	"github.com/snapcore/snapd/interfaces/apparmor"
    28  	"github.com/snapcore/snapd/interfaces/mount"
    29  	"github.com/snapcore/snapd/interfaces/seccomp"
    30  	"github.com/snapcore/snapd/interfaces/udev"
    31  	"github.com/snapcore/snapd/osutil"
    32  	"github.com/snapcore/snapd/snap"
    33  )
    34  
    35  const x11Summary = `allows interacting with or running as an X11 server`
    36  
    37  const x11BaseDeclarationSlots = `
    38    x11:
    39      allow-installation:
    40        slot-snap-type:
    41          - app
    42          - core
    43      deny-connection:
    44        on-classic: false
    45      deny-auto-connection:
    46        on-classic: false
    47  `
    48  
    49  const x11PermanentSlotAppArmor = `
    50  # Description: Allow operating as an X11 display server. This gives privileged access
    51  # to the system.
    52  
    53  # needed since X11 is a display server and needs to configure tty devices
    54  capability sys_tty_config,
    55  /dev/tty[0-9]* rw,
    56  
    57  # Needed for mode setting via drmSetMaster() and drmDropMaster()
    58  capability sys_admin,
    59  
    60  # NOTE: this allows reading and inserting all input events
    61  /dev/input/* rw,
    62  
    63  # For using udev
    64  network netlink raw,
    65  /run/udev/data/c13:[0-9]* r,
    66  /run/udev/data/+input:input[0-9]* r,
    67  /run/udev/data/+platform:* r,
    68  
    69  # the unix socket to use to connect to the display
    70  unix (bind, listen, accept)
    71       type=stream
    72       addr="@/tmp/.X11-unix/X[0-9]*",
    73  unix (bind, listen, accept)
    74       type=stream
    75       addr="@/tmp/.ICE-unix/[0-9]*",
    76  
    77  # On systems with Tegra drivers, X11 needs to create the socket for clients to
    78  # use.
    79  unix (bind, listen, accept)
    80       type=dgram
    81       addr="@nvidia[0-9a-f]*",
    82  
    83  # For Xorg to detect screens
    84  /sys/devices/pci**/boot_vga r,
    85  /sys/devices/pci**/resources r,
    86  `
    87  
    88  const x11PermanentSlotSecComp = `
    89  # Description: Allow operating as an X11 server. This gives privileged access
    90  # to the system.
    91  # Needed for server launch
    92  bind
    93  listen
    94  # Needed by server upon client connect
    95  accept
    96  accept4
    97  # for udev
    98  socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
    99  `
   100  
   101  const x11ConnectedSlotAppArmor = `
   102  # Description: Allow clients access to the X11 server socket
   103  unix (connect, receive, send, accept)
   104      type=stream
   105      addr="@/tmp/.X11-unix/X[0-9]*"
   106      peer=(label=###PLUG_SECURITY_TAGS###),
   107  # TODO: deprecate and remove this if it doesn't break X11 server snaps.
   108  unix (connect, receive, send, accept)
   109      type=stream
   110      addr="@/tmp/.ICE-unix/[0-9]*"
   111      peer=(label=###PLUG_SECURITY_TAGS###),
   112  `
   113  
   114  const x11ConnectedPlugAppArmor = `
   115  # Description: Can access the X server. Restricted because X does not prevent
   116  # eavesdropping or apps interfering with one another.
   117  
   118  # The X abstraction doesn't check the peer label, but in this case that's
   119  # ok because x11ConnectedSlotAppArmor will limit which clients can connect
   120  # to the slot implementation.
   121  #include <abstractions/X>
   122  #include <abstractions/fonts>
   123  owner @{HOME}/.local/share/fonts/{,**} r,
   124  /var/cache/fontconfig/   r,
   125  /var/cache/fontconfig/** mr,
   126  
   127  # Allow access to the user specific copy of the xauth file specified
   128  # in the XAUTHORITY environment variable, that "snap run" creates on
   129  # startup.
   130  owner /run/user/[0-9]*/.Xauthority r,
   131  
   132  # Allow reading an Xwayland Xauth file
   133  # (see https://gitlab.gnome.org/GNOME/mutter/merge_requests/626)
   134  owner /run/user/[0-9]*/.mutter-Xwaylandauth.* r,
   135  owner /run/user/[0-9]*/mutter/Xauthority r,
   136  
   137  
   138  # Needed by QtSystems on X to detect mouse and keyboard. Note, the 'netlink
   139  # raw' rule is not finely mediated by apparmor so we mediate with seccomp arg
   140  # filtering.
   141  network netlink raw,
   142  /run/udev/data/c13:[0-9]* r,
   143  /run/udev/data/+input:* r,
   144  
   145  # Deny access to ICE granted by abstractions/X
   146  # See: https://bugs.launchpad.net/snapd/+bug/1901489
   147  deny owner @{HOME}/.ICEauthority r,
   148  deny owner /run/user/*/ICEauthority r,
   149  deny unix (connect, receive, send)
   150      type=stream
   151      peer=(addr="@/tmp/.ICE-unix/[0-9]*"),
   152  `
   153  
   154  const x11ConnectedPlugSecComp = `
   155  # Description: Can access the X server. Restricted because X does not prevent
   156  # eavesdropping or apps interfering with one another.
   157  
   158  # Needed by QtSystems on X to detect mouse and keyboard
   159  socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
   160  bind
   161  `
   162  
   163  type x11Interface struct {
   164  	commonInterface
   165  }
   166  
   167  func (iface *x11Interface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   168  	if implicitSystemConnectedSlot(slot) {
   169  		// X11 slot is provided by the host system. Bring the host's
   170  		// /tmp/.X11-unix/ directory over to the snap mount namespace.
   171  		return spec.AddMountEntry(osutil.MountEntry{
   172  			Name:    "/var/lib/snapd/hostfs/tmp/.X11-unix",
   173  			Dir:     "/tmp/.X11-unix",
   174  			Options: []string{"bind", "ro"},
   175  		})
   176  	}
   177  
   178  	// X11 slot is provided by another snap on the system. Bring that snap's
   179  	// /tmp/.X11-unix/ directory over to the snap mount namespace. Here we
   180  	// rely on the predictable naming of the private /tmp directory of the
   181  	// slot-side snap which is currently provided by snap-confine.
   182  
   183  	// But if the same snap is providing both the plug and the slot, this is
   184  	// not necessary.
   185  	if plug.Snap().InstanceName() == slot.Snap().InstanceName() {
   186  		return nil
   187  	}
   188  	slotSnapName := slot.Snap().InstanceName()
   189  	return spec.AddMountEntry(osutil.MountEntry{
   190  		Name:    fmt.Sprintf("/var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix", slotSnapName),
   191  		Dir:     "/tmp/.X11-unix",
   192  		Options: []string{"bind", "ro"},
   193  	})
   194  }
   195  
   196  func (iface *x11Interface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   197  	if err := iface.commonInterface.AppArmorConnectedPlug(spec, plug, slot); err != nil {
   198  		return err
   199  	}
   200  	// Consult the comments in MountConnectedPlug for the rationale of the control flow.
   201  	if implicitSystemConnectedSlot(slot) {
   202  		spec.AddUpdateNS(`
   203  		/{,var/lib/snapd/hostfs/}tmp/.X11-unix/ rw,
   204  		mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/.X11-unix/ -> /tmp/.X11-unix/,
   205  		mount options=(ro, remount, bind) -> /tmp/.X11-unix/,
   206  		mount options=(rslave) -> /tmp/.X11-unix/,
   207  		umount /tmp/.X11-unix/,
   208  		`)
   209  		return nil
   210  	}
   211  	if plug.Snap().InstanceName() == slot.Snap().InstanceName() {
   212  		return nil
   213  	}
   214  	slotSnapName := slot.Snap().InstanceName()
   215  	spec.AddUpdateNS(fmt.Sprintf(`
   216  	/tmp/.X11-unix/ rw,
   217  	/var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix/ rw,
   218  	mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix/ -> /tmp/.X11-unix/,
   219  	mount options=(ro, remount, bind) -> /tmp/.X11-unix/,
   220  	mount options=(rslave) -> /tmp/.X11-unix/,
   221  	umount /tmp/.X11-unix/,
   222  	`, slotSnapName, slotSnapName))
   223  	return nil
   224  }
   225  
   226  func (iface *x11Interface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   227  	if !implicitSystemConnectedSlot(slot) {
   228  		old := "###PLUG_SECURITY_TAGS###"
   229  		new := plugAppLabelExpr(plug)
   230  		snippet := strings.Replace(x11ConnectedSlotAppArmor, old, new, -1)
   231  		spec.AddSnippet(snippet)
   232  	}
   233  	return nil
   234  }
   235  
   236  func (iface *x11Interface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error {
   237  	if !implicitSystemPermanentSlot(slot) {
   238  		spec.AddSnippet(x11PermanentSlotSecComp)
   239  	}
   240  	return nil
   241  }
   242  
   243  func (iface *x11Interface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error {
   244  	if !implicitSystemPermanentSlot(slot) {
   245  		spec.AddSnippet(x11PermanentSlotAppArmor)
   246  	}
   247  	return nil
   248  }
   249  
   250  func (iface *x11Interface) UDevPermanentSlot(spec *udev.Specification, slot *snap.SlotInfo) error {
   251  	if !implicitSystemPermanentSlot(slot) {
   252  		spec.TriggerSubsystem("input")
   253  		spec.TagDevice(`KERNEL=="tty[0-9]*"`)
   254  		spec.TagDevice(`KERNEL=="mice"`)
   255  		spec.TagDevice(`KERNEL=="mouse[0-9]*"`)
   256  		spec.TagDevice(`KERNEL=="event[0-9]*"`)
   257  		spec.TagDevice(`KERNEL=="ts[0-9]*"`)
   258  	}
   259  	return nil
   260  }
   261  
   262  func init() {
   263  	registerIface(&x11Interface{commonInterface{
   264  		name:                  "x11",
   265  		summary:               x11Summary,
   266  		implicitOnClassic:     true,
   267  		baseDeclarationSlots:  x11BaseDeclarationSlots,
   268  		connectedPlugAppArmor: x11ConnectedPlugAppArmor,
   269  		connectedPlugSecComp:  x11ConnectedPlugSecComp,
   270  	}})
   271  }