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 }