gitee.com/mysnapcore/mysnapd@v0.1.0/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  	"gitee.com/mysnapcore/mysnapd/interfaces"
    27  	"gitee.com/mysnapcore/mysnapd/interfaces/apparmor"
    28  	"gitee.com/mysnapcore/mysnapd/interfaces/mount"
    29  	"gitee.com/mysnapcore/mysnapd/interfaces/seccomp"
    30  	"gitee.com/mysnapcore/mysnapd/interfaces/udev"
    31  	"gitee.com/mysnapcore/mysnapd/osutil"
    32  	"gitee.com/mysnapcore/mysnapd/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  # TODO: enable rules for writing Xwayland Xauth files for clients to read when
    88  # something like gnome-shell is running confined with an x11 slot
    89  `
    90  
    91  const x11PermanentSlotSecComp = `
    92  # Description: Allow operating as an X11 server. This gives privileged access
    93  # to the system.
    94  # Needed for server launch
    95  bind
    96  listen
    97  # Needed by server upon client connect
    98  accept
    99  accept4
   100  # for udev
   101  socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
   102  `
   103  
   104  const x11ConnectedSlotAppArmor = `
   105  # Description: Allow clients access to the X11 server socket
   106  unix (connect, receive, send, accept)
   107      type=stream
   108      addr="@/tmp/.X11-unix/X[0-9]*"
   109      peer=(label=###PLUG_SECURITY_TAGS###),
   110  # TODO: deprecate and remove this if it doesn't break X11 server snaps.
   111  unix (connect, receive, send, accept)
   112      type=stream
   113      addr="@/tmp/.ICE-unix/[0-9]*"
   114      peer=(label=###PLUG_SECURITY_TAGS###),
   115  `
   116  
   117  const x11ConnectedPlugAppArmor = `
   118  # Description: Can access the X server. Restricted because X does not prevent
   119  # eavesdropping or apps interfering with one another.
   120  
   121  # The X abstraction doesn't check the peer label, but in this case that's
   122  # ok because x11ConnectedSlotAppArmor will limit which clients can connect
   123  # to the slot implementation.
   124  #include <abstractions/X>
   125  #include <abstractions/fonts>
   126  owner @{HOME}/.local/share/fonts/{,**} r,
   127  /var/cache/fontconfig/   r,
   128  /var/cache/fontconfig/** mr,
   129  
   130  # Allow access to the user specific copy of the xauth file specified
   131  # in the XAUTHORITY environment variable, that "snap run" creates on
   132  # startup.
   133  owner /run/user/[0-9]*/.Xauthority r,
   134  
   135  # Allow reading an Xwayland Xauth file
   136  # (see https://gitlab.gnome.org/GNOME/mutter/merge_requests/626)
   137  owner /run/user/[0-9]*/.mutter-Xwaylandauth.* r,
   138  owner /run/user/[0-9]*/mutter/Xauthority r,
   139  
   140  # Allow reading KDE Plasma's Xwayland Xauth file
   141  owner /run/user/[0-9]*/xauth_* r,
   142  
   143  
   144  # Needed by QtSystems on X to detect mouse and keyboard. Note, the 'netlink
   145  # raw' rule is not finely mediated by apparmor so we mediate with seccomp arg
   146  # filtering.
   147  network netlink raw,
   148  /run/udev/data/c13:[0-9]* r,
   149  /run/udev/data/+input:* r,
   150  
   151  # Deny access to ICE granted by abstractions/X
   152  # See: https://bugs.launchpad.net/snapd/+bug/1901489
   153  deny owner @{HOME}/.ICEauthority r,
   154  deny owner /run/user/*/ICEauthority r,
   155  deny unix (connect, receive, send)
   156      type=stream
   157      peer=(addr="@/tmp/.ICE-unix/[0-9]*"),
   158  `
   159  
   160  const x11ConnectedPlugSecComp = `
   161  # Description: Can access the X server. Restricted because X does not prevent
   162  # eavesdropping or apps interfering with one another.
   163  
   164  # Needed by QtSystems on X to detect mouse and keyboard
   165  socket AF_NETLINK - NETLINK_KOBJECT_UEVENT
   166  bind
   167  `
   168  
   169  type x11Interface struct {
   170  	commonInterface
   171  }
   172  
   173  func (iface *x11Interface) MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   174  	if implicitSystemConnectedSlot(slot) {
   175  		// X11 slot is provided by the host system. Bring the host's
   176  		// /tmp/.X11-unix/ directory over to the snap mount namespace.
   177  		return spec.AddMountEntry(osutil.MountEntry{
   178  			Name:    "/var/lib/snapd/hostfs/tmp/.X11-unix",
   179  			Dir:     "/tmp/.X11-unix",
   180  			Options: []string{"bind", "ro"},
   181  		})
   182  	}
   183  
   184  	// X11 slot is provided by another snap on the system. Bring that snap's
   185  	// /tmp/.X11-unix/ directory over to the snap mount namespace. Here we
   186  	// rely on the predictable naming of the private /tmp directory of the
   187  	// slot-side snap which is currently provided by snap-confine.
   188  
   189  	// But if the same snap is providing both the plug and the slot, this is
   190  	// not necessary.
   191  	if plug.Snap().InstanceName() == slot.Snap().InstanceName() {
   192  		return nil
   193  	}
   194  	slotSnapName := slot.Snap().InstanceName()
   195  	return spec.AddMountEntry(osutil.MountEntry{
   196  		Name:    fmt.Sprintf("/var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix", slotSnapName),
   197  		Dir:     "/tmp/.X11-unix",
   198  		Options: []string{"bind", "ro"},
   199  	})
   200  }
   201  
   202  func (iface *x11Interface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   203  	if err := iface.commonInterface.AppArmorConnectedPlug(spec, plug, slot); err != nil {
   204  		return err
   205  	}
   206  	// Consult the comments in MountConnectedPlug for the rationale of the control flow.
   207  	if implicitSystemConnectedSlot(slot) {
   208  		spec.AddUpdateNS(`
   209  		/{,var/lib/snapd/hostfs/}tmp/.X11-unix/ rw,
   210  		mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/.X11-unix/ -> /tmp/.X11-unix/,
   211  		mount options=(ro, remount, bind) -> /tmp/.X11-unix/,
   212  		mount options=(rslave) -> /tmp/.X11-unix/,
   213  		umount /tmp/.X11-unix/,
   214  		`)
   215  		return nil
   216  	}
   217  	if plug.Snap().InstanceName() == slot.Snap().InstanceName() {
   218  		return nil
   219  	}
   220  	slotSnapName := slot.Snap().InstanceName()
   221  	spec.AddUpdateNS(fmt.Sprintf(`
   222  	/tmp/.X11-unix/ rw,
   223  	/var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix/ rw,
   224  	mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/snap.%s/tmp/.X11-unix/ -> /tmp/.X11-unix/,
   225  	mount options=(ro, remount, bind) -> /tmp/.X11-unix/,
   226  	mount options=(rslave) -> /tmp/.X11-unix/,
   227  	umount /tmp/.X11-unix/,
   228  	`, slotSnapName, slotSnapName))
   229  	return nil
   230  }
   231  
   232  func (iface *x11Interface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   233  	if !implicitSystemConnectedSlot(slot) {
   234  		old := "###PLUG_SECURITY_TAGS###"
   235  		new := plugAppLabelExpr(plug)
   236  		snippet := strings.Replace(x11ConnectedSlotAppArmor, old, new, -1)
   237  		spec.AddSnippet(snippet)
   238  	}
   239  	return nil
   240  }
   241  
   242  func (iface *x11Interface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error {
   243  	if !implicitSystemPermanentSlot(slot) {
   244  		spec.AddSnippet(x11PermanentSlotSecComp)
   245  	}
   246  	return nil
   247  }
   248  
   249  func (iface *x11Interface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error {
   250  	if !implicitSystemPermanentSlot(slot) {
   251  		spec.AddSnippet(x11PermanentSlotAppArmor)
   252  	}
   253  	return nil
   254  }
   255  
   256  func (iface *x11Interface) UDevPermanentSlot(spec *udev.Specification, slot *snap.SlotInfo) error {
   257  	if !implicitSystemPermanentSlot(slot) {
   258  		spec.TriggerSubsystem("input")
   259  		spec.TagDevice(`KERNEL=="tty[0-9]*"`)
   260  		spec.TagDevice(`KERNEL=="mice"`)
   261  		spec.TagDevice(`KERNEL=="mouse[0-9]*"`)
   262  		spec.TagDevice(`KERNEL=="event[0-9]*"`)
   263  		spec.TagDevice(`KERNEL=="ts[0-9]*"`)
   264  	}
   265  	return nil
   266  }
   267  
   268  func init() {
   269  	registerIface(&x11Interface{commonInterface{
   270  		name:                  "x11",
   271  		summary:               x11Summary,
   272  		implicitOnClassic:     true,
   273  		baseDeclarationSlots:  x11BaseDeclarationSlots,
   274  		connectedPlugAppArmor: x11ConnectedPlugAppArmor,
   275  		connectedPlugSecComp:  x11ConnectedPlugSecComp,
   276  		// affects the plug snap because of mount backend
   277  		affectsPlugOnRefresh: true,
   278  	}})
   279  }