gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/x11_test.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_test 21 22 import ( 23 "fmt" 24 25 . "gopkg.in/check.v1" 26 27 "gitee.com/mysnapcore/mysnapd/dirs" 28 "gitee.com/mysnapcore/mysnapd/interfaces" 29 "gitee.com/mysnapcore/mysnapd/interfaces/apparmor" 30 "gitee.com/mysnapcore/mysnapd/interfaces/builtin" 31 "gitee.com/mysnapcore/mysnapd/interfaces/mount" 32 "gitee.com/mysnapcore/mysnapd/interfaces/seccomp" 33 "gitee.com/mysnapcore/mysnapd/interfaces/udev" 34 "gitee.com/mysnapcore/mysnapd/osutil" 35 "gitee.com/mysnapcore/mysnapd/release" 36 "gitee.com/mysnapcore/mysnapd/snap" 37 "gitee.com/mysnapcore/mysnapd/testutil" 38 ) 39 40 type X11InterfaceSuite struct { 41 iface interfaces.Interface 42 coreSlotInfo *snap.SlotInfo 43 coreSlot *interfaces.ConnectedSlot 44 corePlugInfo *snap.PlugInfo 45 corePlug *interfaces.ConnectedPlug 46 classicSlotInfo *snap.SlotInfo 47 classicSlot *interfaces.ConnectedSlot 48 plugInfo *snap.PlugInfo 49 plug *interfaces.ConnectedPlug 50 } 51 52 var _ = Suite(&X11InterfaceSuite{ 53 iface: builtin.MustInterface("x11"), 54 }) 55 56 const x11MockPlugSnapInfoYaml = `name: consumer 57 version: 0 58 apps: 59 app: 60 plugs: [x11] 61 ` 62 63 // an x11 slot on an x11 snap (as installed on a core/all-snap system) 64 const x11CoreYaml = `name: x11 65 version: 0 66 apps: 67 app: 68 slots: [x11-provider] 69 plugs: [x11-consumer] 70 plugs: 71 x11-consumer: 72 interface: x11 73 slots: 74 x11-provider: 75 interface: x11 76 ` 77 78 // an x11 slot on the core snap (as automatically added on classic) 79 const x11ClassicYaml = `name: core 80 version: 0 81 type: os 82 slots: 83 x11: 84 interface: x11 85 ` 86 87 func (s *X11InterfaceSuite) SetUpTest(c *C) { 88 s.plug, s.plugInfo = MockConnectedPlug(c, x11MockPlugSnapInfoYaml, nil, "x11") 89 s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, x11CoreYaml, nil, "x11-provider") 90 s.corePlug, s.corePlugInfo = MockConnectedPlug(c, x11CoreYaml, nil, "x11-consumer") 91 s.classicSlot, s.classicSlotInfo = MockConnectedSlot(c, x11ClassicYaml, nil, "x11") 92 } 93 94 func (s *X11InterfaceSuite) TestName(c *C) { 95 c.Assert(s.iface.Name(), Equals, "x11") 96 } 97 98 func (s *X11InterfaceSuite) TestSanitizeSlot(c *C) { 99 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.coreSlotInfo), IsNil) 100 c.Assert(interfaces.BeforePrepareSlot(s.iface, s.classicSlotInfo), IsNil) 101 } 102 103 func (s *X11InterfaceSuite) TestSanitizePlug(c *C) { 104 c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil) 105 } 106 107 func (s *X11InterfaceSuite) TestMountSpec(c *C) { 108 // case A: x11 slot is provided by the system 109 spec := &mount.Specification{} 110 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.classicSlot), IsNil) 111 c.Assert(spec.MountEntries(), DeepEquals, []osutil.MountEntry{{ 112 Name: "/var/lib/snapd/hostfs/tmp/.X11-unix", 113 Dir: "/tmp/.X11-unix", 114 Options: []string{"bind", "ro"}, 115 }}) 116 c.Assert(spec.UserMountEntries(), HasLen, 0) 117 118 // case B: x11 slot is provided by another snap on the system 119 spec = &mount.Specification{} 120 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 121 c.Assert(spec.MountEntries(), DeepEquals, []osutil.MountEntry{{ 122 Name: "/var/lib/snapd/hostfs/tmp/snap.x11/tmp/.X11-unix", 123 Dir: "/tmp/.X11-unix", 124 Options: []string{"bind", "ro"}, 125 }}) 126 c.Assert(spec.UserMountEntries(), HasLen, 0) 127 128 // case C: x11 slot is both provided and consumed by a snap on the system. 129 spec = &mount.Specification{} 130 c.Assert(spec.AddConnectedPlug(s.iface, s.corePlug, s.coreSlot), IsNil) 131 c.Assert(spec.MountEntries(), HasLen, 0) 132 c.Assert(spec.UserMountEntries(), HasLen, 0) 133 } 134 135 func (s *X11InterfaceSuite) TestAppArmorSpec(c *C) { 136 // case A: x11 slot is provided by the classic system 137 restore := release.MockOnClassic(true) 138 defer restore() 139 140 // Plug side connection permissions 141 spec := &apparmor.Specification{} 142 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.classicSlot), IsNil) 143 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 144 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "fontconfig") 145 c.Assert(spec.UpdateNS(), HasLen, 1) 146 c.Assert(spec.UpdateNS()[0], testutil.Contains, `mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/.X11-unix/ -> /tmp/.X11-unix/,`) 147 148 // case B: x11 slot is provided by another snap on the system 149 restore = release.MockOnClassic(false) 150 defer restore() 151 152 // Plug side connection permissions 153 spec = &apparmor.Specification{} 154 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 155 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 156 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "fontconfig") 157 c.Assert(spec.UpdateNS(), HasLen, 1) 158 c.Assert(spec.UpdateNS()[0], testutil.Contains, `mount options=(rw, bind) /var/lib/snapd/hostfs/tmp/snap.x11/tmp/.X11-unix/ -> /tmp/.X11-unix/,`) 159 160 // Slot side connection permissions 161 spec = &apparmor.Specification{} 162 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.coreSlot), IsNil) 163 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.x11.app"}) 164 c.Assert(spec.SnippetForTag("snap.x11.app"), testutil.Contains, `peer=(label="snap.consumer.app"),`) 165 c.Assert(spec.UpdateNS(), HasLen, 0) 166 167 // Slot side permantent permissions 168 spec = &apparmor.Specification{} 169 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 170 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.x11.app"}) 171 c.Assert(spec.SnippetForTag("snap.x11.app"), testutil.Contains, "capability sys_tty_config,") 172 c.Assert(spec.UpdateNS(), HasLen, 0) 173 174 // case C: x11 slot is both provided and consumed by a snap on the system. 175 spec = &apparmor.Specification{} 176 c.Assert(spec.AddConnectedPlug(s.iface, s.corePlug, s.coreSlot), IsNil) 177 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.x11.app"}) 178 c.Assert(spec.SnippetForTag("snap.x11.app"), testutil.Contains, "fontconfig") 179 // Self-connection does not need bind mounts, so no additional permissions are provided to snap-update-ns. 180 c.Assert(spec.UpdateNS(), HasLen, 0) 181 } 182 183 func (s *X11InterfaceSuite) TestAppArmorSpecOnClassic(c *C) { 184 // on a classic system with x11 slot coming from the core snap. 185 restore := release.MockOnClassic(true) 186 defer restore() 187 188 // connected plug to classic slot 189 spec := &apparmor.Specification{} 190 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.classicSlot), IsNil) 191 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 192 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "owner /run/user/[0-9]*/.Xauthority r,") 193 194 // connected classic slot to plug 195 spec = &apparmor.Specification{} 196 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.classicSlot), IsNil) 197 c.Assert(spec.SecurityTags(), HasLen, 0) 198 199 // permanent classic slot 200 spec = &apparmor.Specification{} 201 c.Assert(spec.AddPermanentSlot(s.iface, s.classicSlotInfo), IsNil) 202 c.Assert(spec.SecurityTags(), HasLen, 0) 203 } 204 205 func (s *X11InterfaceSuite) TestSecCompOnClassic(c *C) { 206 // on a classic system with x11 slot coming from the core snap. 207 restore := release.MockOnClassic(true) 208 defer restore() 209 210 seccompSpec := &seccomp.Specification{} 211 err := seccompSpec.AddPermanentSlot(s.iface, s.classicSlotInfo) 212 c.Assert(err, IsNil) 213 err = seccompSpec.AddConnectedPlug(s.iface, s.plug, s.classicSlot) 214 c.Assert(err, IsNil) 215 216 // app snap has additional seccomp rules 217 c.Assert(seccompSpec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 218 c.Assert(seccompSpec.SnippetForTag("snap.consumer.app"), testutil.Contains, "bind\n") 219 } 220 221 func (s *X11InterfaceSuite) TestSecCompOnCore(c *C) { 222 // on a core system with x11 slot coming from a snap. 223 restore := release.MockOnClassic(false) 224 defer restore() 225 226 seccompSpec := &seccomp.Specification{} 227 err := seccompSpec.AddPermanentSlot(s.iface, s.coreSlotInfo) 228 c.Assert(err, IsNil) 229 err = seccompSpec.AddConnectedPlug(s.iface, s.plug, s.coreSlot) 230 c.Assert(err, IsNil) 231 232 // both app and x11 have secomp rules set 233 c.Assert(seccompSpec.SecurityTags(), DeepEquals, []string{"snap.consumer.app", "snap.x11.app"}) 234 c.Assert(seccompSpec.SnippetForTag("snap.x11.app"), testutil.Contains, "listen\n") 235 c.Assert(seccompSpec.SnippetForTag("snap.consumer.app"), testutil.Contains, "bind\n") 236 } 237 238 func (s *X11InterfaceSuite) TestUDev(c *C) { 239 // on a core system with x11 slot coming from a regular app snap. 240 restore := release.MockOnClassic(false) 241 defer restore() 242 243 spec := &udev.Specification{} 244 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 245 c.Assert(spec.Snippets(), HasLen, 6) 246 c.Assert(spec.Snippets(), testutil.Contains, `# x11 247 KERNEL=="event[0-9]*", TAG+="snap_x11_app"`) 248 c.Assert(spec.Snippets(), testutil.Contains, `# x11 249 KERNEL=="mice", TAG+="snap_x11_app"`) 250 c.Assert(spec.Snippets(), testutil.Contains, `# x11 251 KERNEL=="mouse[0-9]*", TAG+="snap_x11_app"`) 252 c.Assert(spec.Snippets(), testutil.Contains, `# x11 253 KERNEL=="ts[0-9]*", TAG+="snap_x11_app"`) 254 c.Assert(spec.Snippets(), testutil.Contains, `# x11 255 KERNEL=="tty[0-9]*", TAG+="snap_x11_app"`) 256 c.Assert(spec.Snippets(), testutil.Contains, fmt.Sprintf(`TAG=="snap_x11_app", RUN+="%v/snap-device-helper $env{ACTION} snap_x11_app $devpath $major:$minor"`, dirs.DistroLibExecDir)) 257 c.Assert(spec.TriggeredSubsystems(), DeepEquals, []string{"input"}) 258 259 // on a classic system with x11 slot coming from the core snap. 260 restore = release.MockOnClassic(true) 261 defer restore() 262 263 spec = &udev.Specification{} 264 c.Assert(spec.AddPermanentSlot(s.iface, s.classicSlotInfo), IsNil) 265 c.Assert(spec.Snippets(), HasLen, 0) 266 c.Assert(spec.TriggeredSubsystems(), IsNil) 267 } 268 269 func (s *X11InterfaceSuite) TestStaticInfo(c *C) { 270 si := interfaces.StaticInfoOf(s.iface) 271 c.Assert(si.ImplicitOnCore, Equals, false) 272 c.Assert(si.ImplicitOnClassic, Equals, true) 273 c.Assert(si.Summary, Equals, `allows interacting with or running as an X11 server`) 274 c.Assert(si.BaseDeclarationSlots, testutil.Contains, "x11") 275 c.Assert(si.AffectsPlugOnRefresh, Equals, true) 276 } 277 278 func (s *X11InterfaceSuite) TestAutoConnect(c *C) { 279 c.Assert(s.iface.AutoConnect(s.plugInfo, s.coreSlotInfo), Equals, true) 280 c.Assert(s.iface.AutoConnect(s.plugInfo, s.classicSlotInfo), Equals, true) 281 } 282 283 func (s *X11InterfaceSuite) TestInterfaces(c *C) { 284 c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface) 285 }