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 }