github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/builtin/hidraw_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 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  	. "gopkg.in/check.v1"
    24  
    25  	"github.com/snapcore/snapd/interfaces"
    26  	"github.com/snapcore/snapd/interfaces/apparmor"
    27  	"github.com/snapcore/snapd/interfaces/builtin"
    28  	"github.com/snapcore/snapd/interfaces/udev"
    29  	"github.com/snapcore/snapd/snap"
    30  	"github.com/snapcore/snapd/snap/snaptest"
    31  	"github.com/snapcore/snapd/testutil"
    32  )
    33  
    34  type HidrawInterfaceSuite struct {
    35  	testutil.BaseTest
    36  	iface interfaces.Interface
    37  
    38  	// OS Snap
    39  	testSlot1            *interfaces.ConnectedSlot
    40  	testSlot1Info        *snap.SlotInfo
    41  	testSlot2            *interfaces.ConnectedSlot
    42  	testSlot2Info        *snap.SlotInfo
    43  	missingPathSlot      *interfaces.ConnectedSlot
    44  	missingPathSlotInfo  *snap.SlotInfo
    45  	badPathSlot1         *interfaces.ConnectedSlot
    46  	badPathSlot1Info     *snap.SlotInfo
    47  	badPathSlot2         *interfaces.ConnectedSlot
    48  	badPathSlot2Info     *snap.SlotInfo
    49  	badPathSlot3         *interfaces.ConnectedSlot
    50  	badPathSlot3Info     *snap.SlotInfo
    51  	badInterfaceSlot     *interfaces.ConnectedSlot
    52  	badInterfaceSlotInfo *snap.SlotInfo
    53  
    54  	// Gadget Snap
    55  	testUDev1             *interfaces.ConnectedSlot
    56  	testUDev1Info         *snap.SlotInfo
    57  	testUDev2             *interfaces.ConnectedSlot
    58  	testUDev2Info         *snap.SlotInfo
    59  	testUDevBadValue1     *interfaces.ConnectedSlot
    60  	testUDevBadValue1Info *snap.SlotInfo
    61  	testUDevBadValue2     *interfaces.ConnectedSlot
    62  	testUDevBadValue2Info *snap.SlotInfo
    63  	testUDevBadValue3     *interfaces.ConnectedSlot
    64  	testUDevBadValue3Info *snap.SlotInfo
    65  
    66  	// Consuming Snap
    67  	testPlugPort1     *interfaces.ConnectedPlug
    68  	testPlugPort1Info *snap.PlugInfo
    69  	testPlugPort2     *interfaces.ConnectedPlug
    70  	testPlugPort2Info *snap.PlugInfo
    71  	testPlugPort3     *interfaces.ConnectedPlug
    72  	testPlugPort3Info *snap.PlugInfo
    73  }
    74  
    75  var _ = Suite(&HidrawInterfaceSuite{
    76  	iface: builtin.MustInterface("hidraw"),
    77  })
    78  
    79  func (s *HidrawInterfaceSuite) SetUpTest(c *C) {
    80  	osSnapInfo := snaptest.MockInfo(c, `
    81  name: ubuntu-core
    82  version: 0
    83  type: os
    84  slots:
    85      test-port-1:
    86          interface: hidraw
    87          path: /dev/hidraw0
    88      test-port-2:
    89          interface: hidraw
    90          path: /dev/hidraw987
    91      missing-path: hidraw
    92      bad-path-1:
    93          interface: hidraw
    94          path: path
    95      bad-path-2:
    96          interface: hidraw
    97          path: /dev/hid0
    98      bad-path-3:
    99          interface: hidraw
   100          path: /dev/hidraw9271
   101      bad-interface: other-interface
   102  `, nil)
   103  	s.testSlot1Info = osSnapInfo.Slots["test-port-1"]
   104  	s.testSlot1 = interfaces.NewConnectedSlot(s.testSlot1Info, nil, nil)
   105  	s.testSlot2Info = osSnapInfo.Slots["test-port-2"]
   106  	s.testSlot2 = interfaces.NewConnectedSlot(s.testSlot2Info, nil, nil)
   107  	s.missingPathSlotInfo = osSnapInfo.Slots["missing-path"]
   108  	s.missingPathSlot = interfaces.NewConnectedSlot(s.missingPathSlotInfo, nil, nil)
   109  	s.badPathSlot1Info = osSnapInfo.Slots["bad-path-1"]
   110  	s.badPathSlot1 = interfaces.NewConnectedSlot(s.badPathSlot1Info, nil, nil)
   111  	s.badPathSlot2Info = osSnapInfo.Slots["bad-path-2"]
   112  	s.badPathSlot2 = interfaces.NewConnectedSlot(s.badPathSlot2Info, nil, nil)
   113  	s.badPathSlot3Info = osSnapInfo.Slots["bad-path-3"]
   114  	s.badPathSlot3 = interfaces.NewConnectedSlot(s.badPathSlot3Info, nil, nil)
   115  	s.badInterfaceSlotInfo = osSnapInfo.Slots["bad-interface"]
   116  	s.badInterfaceSlot = interfaces.NewConnectedSlot(s.badInterfaceSlotInfo, nil, nil)
   117  
   118  	gadgetSnapInfo := snaptest.MockInfo(c, `
   119  name: some-device
   120  version: 0
   121  type: gadget
   122  slots:
   123    test-udev-1:
   124        interface: hidraw
   125        usb-vendor: 0x0001
   126        usb-product: 0x0001
   127        path: /dev/hidraw-canbus
   128    test-udev-2:
   129        interface: hidraw
   130        usb-vendor: 0xffff
   131        usb-product: 0xffff
   132        path: /dev/hidraw-mydevice
   133    test-udev-bad-value-1:
   134        interface: hidraw
   135        usb-vendor: -1
   136        usb-product: 0xffff
   137        path: /dev/hidraw-mydevice
   138    test-udev-bad-value-2:
   139        interface: hidraw
   140        usb-vendor: 0x1234
   141        usb-product: 0x10000
   142        path: /dev/hidraw-mydevice
   143    test-udev-bad-value-3:
   144        interface: hidraw
   145        usb-vendor: 0x789a
   146        usb-product: 0x4321
   147        path: /dev/my-device
   148  `, nil)
   149  	s.testUDev1Info = gadgetSnapInfo.Slots["test-udev-1"]
   150  	s.testUDev1 = interfaces.NewConnectedSlot(s.testUDev1Info, nil, nil)
   151  	s.testUDev2Info = gadgetSnapInfo.Slots["test-udev-2"]
   152  	s.testUDev2 = interfaces.NewConnectedSlot(s.testUDev2Info, nil, nil)
   153  	s.testUDevBadValue1Info = gadgetSnapInfo.Slots["test-udev-bad-value-1"]
   154  	s.testUDevBadValue1 = interfaces.NewConnectedSlot(s.testUDevBadValue1Info, nil, nil)
   155  	s.testUDevBadValue2Info = gadgetSnapInfo.Slots["test-udev-bad-value-2"]
   156  	s.testUDevBadValue2 = interfaces.NewConnectedSlot(s.testUDevBadValue2Info, nil, nil)
   157  	s.testUDevBadValue3Info = gadgetSnapInfo.Slots["test-udev-bad-value-3"]
   158  	s.testUDevBadValue3 = interfaces.NewConnectedSlot(s.testUDevBadValue3Info, nil, nil)
   159  
   160  	consumingSnapInfo := snaptest.MockInfo(c, `
   161  name: client-snap
   162  version: 0
   163  plugs:
   164      plug-for-device-1:
   165          interface: hidraw
   166      plug-for-device-2:
   167          interface: hidraw
   168      plug-for-device-3:
   169          interface: hidraw
   170  
   171  apps:
   172      app-accessing-1-device:
   173          command: foo
   174          plugs: [hidraw]
   175      app-accessing-2-devices:
   176          command: bar
   177          plugs: [plug-for-device-1, plug-for-device-2]
   178      app-accessing-3rd-device:
   179          command: baz
   180          plugs: [plug-for-device-3]
   181  `, nil)
   182  	s.testPlugPort1Info = consumingSnapInfo.Plugs["plug-for-device-1"]
   183  	s.testPlugPort1 = interfaces.NewConnectedPlug(s.testPlugPort1Info, nil, nil)
   184  	s.testPlugPort2Info = consumingSnapInfo.Plugs["plug-for-device-2"]
   185  	s.testPlugPort2 = interfaces.NewConnectedPlug(s.testPlugPort2Info, nil, nil)
   186  	s.testPlugPort3Info = consumingSnapInfo.Plugs["plug-for-device-3"]
   187  	s.testPlugPort3 = interfaces.NewConnectedPlug(s.testPlugPort3Info, nil, nil)
   188  }
   189  
   190  func (s *HidrawInterfaceSuite) TestName(c *C) {
   191  	c.Assert(s.iface.Name(), Equals, "hidraw")
   192  }
   193  
   194  func (s *HidrawInterfaceSuite) TestSanitizeCoreSnapSlots(c *C) {
   195  	for _, slot := range []*snap.SlotInfo{s.testSlot1Info, s.testSlot2Info} {
   196  		c.Assert(interfaces.BeforePrepareSlot(s.iface, slot), IsNil)
   197  	}
   198  }
   199  
   200  func (s *HidrawInterfaceSuite) TestSanitizeBadCoreSnapSlots(c *C) {
   201  	// Slots without the "path" attribute are rejected.
   202  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.missingPathSlotInfo), ErrorMatches,
   203  		`hidraw slots must have a path attribute`)
   204  
   205  	// Slots with incorrect value of the "path" attribute are rejected.
   206  	for _, slot := range []*snap.SlotInfo{s.badPathSlot1Info, s.badPathSlot2Info, s.badPathSlot3Info} {
   207  		c.Assert(interfaces.BeforePrepareSlot(s.iface, slot), ErrorMatches, "hidraw path attribute must be a valid device node")
   208  	}
   209  }
   210  
   211  func (s *HidrawInterfaceSuite) TestSanitizeGadgetSnapSlots(c *C) {
   212  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDev1Info), IsNil)
   213  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDev2Info), IsNil)
   214  }
   215  
   216  func (s *HidrawInterfaceSuite) TestSanitizeBadGadgetSnapSlots(c *C) {
   217  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue1Info), ErrorMatches, "hidraw usb-vendor attribute not valid: -1")
   218  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue2Info), ErrorMatches, "hidraw usb-product attribute not valid: 65536")
   219  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.testUDevBadValue3Info), ErrorMatches, "hidraw path attribute specifies invalid symlink location")
   220  }
   221  
   222  func (s *HidrawInterfaceSuite) TestPermanentSlotUDevSnippets(c *C) {
   223  	spec := &udev.Specification{}
   224  	for _, slot := range []*snap.SlotInfo{s.testSlot1Info, s.testSlot2Info} {
   225  		c.Assert(spec.AddPermanentSlot(s.iface, slot), IsNil)
   226  		c.Assert(spec.Snippets(), HasLen, 0)
   227  	}
   228  
   229  	expectedSnippet1 := `# hidraw
   230  IMPORT{builtin}="usb_id"
   231  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", SYMLINK+="hidraw-canbus"`
   232  	c.Assert(spec.AddPermanentSlot(s.iface, s.testUDev1Info), IsNil)
   233  	c.Assert(spec.Snippets(), HasLen, 1)
   234  	snippet := spec.Snippets()[0]
   235  	c.Assert(snippet, Equals, expectedSnippet1)
   236  
   237  	expectedSnippet2 := `# hidraw
   238  IMPORT{builtin}="usb_id"
   239  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", SYMLINK+="hidraw-mydevice"`
   240  	spec = &udev.Specification{}
   241  	c.Assert(spec.AddPermanentSlot(s.iface, s.testUDev2Info), IsNil)
   242  	c.Assert(spec.Snippets(), HasLen, 1)
   243  	snippet = spec.Snippets()[0]
   244  	c.Assert(snippet, Equals, expectedSnippet2)
   245  }
   246  
   247  func (s *HidrawInterfaceSuite) TestConnectedPlugUDevSnippets(c *C) {
   248  	// add the plug for the slot with just path
   249  	spec := &udev.Specification{}
   250  	c.Assert(spec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testSlot1), IsNil)
   251  	c.Assert(spec.Snippets(), HasLen, 2)
   252  	snippet := spec.Snippets()[0]
   253  	expectedSnippet1 := `# hidraw
   254  SUBSYSTEM=="hidraw", KERNEL=="hidraw0", TAG+="snap_client-snap_app-accessing-2-devices"`
   255  	c.Assert(snippet, Equals, expectedSnippet1)
   256  	extraSnippet := spec.Snippets()[1]
   257  	expectedExtraSnippet1 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   258  	c.Assert(extraSnippet, Equals, expectedExtraSnippet1)
   259  
   260  	// add the plug for the first slot with vendor and product ids
   261  	spec = &udev.Specification{}
   262  	c.Assert(spec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testUDev1), IsNil)
   263  	c.Assert(spec.Snippets(), HasLen, 2)
   264  	snippet = spec.Snippets()[0]
   265  	expectedSnippet2 := `# hidraw
   266  IMPORT{builtin}="usb_id"
   267  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", TAG+="snap_client-snap_app-accessing-2-devices"`
   268  	c.Assert(snippet, Equals, expectedSnippet2)
   269  	extraSnippet = spec.Snippets()[1]
   270  	expectedExtraSnippet2 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   271  	c.Assert(extraSnippet, Equals, expectedExtraSnippet2)
   272  
   273  	// add the plug for the second slot with vendor and product ids
   274  	spec = &udev.Specification{}
   275  	c.Assert(spec.AddConnectedPlug(s.iface, s.testPlugPort2, s.testUDev2), IsNil)
   276  	c.Assert(spec.Snippets(), HasLen, 2)
   277  	snippet = spec.Snippets()[0]
   278  	expectedSnippet3 := `# hidraw
   279  IMPORT{builtin}="usb_id"
   280  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", TAG+="snap_client-snap_app-accessing-2-devices"`
   281  	c.Assert(snippet, Equals, expectedSnippet3)
   282  	extraSnippet = spec.Snippets()[1]
   283  	expectedExtraSnippet3 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   284  	c.Assert(extraSnippet, Equals, expectedExtraSnippet3)
   285  }
   286  
   287  func (s *HidrawInterfaceSuite) TestConnectedPlugAppArmorSnippets(c *C) {
   288  	expectedSnippet1 := `/dev/hidraw0 rw,`
   289  	apparmorSpec := &apparmor.Specification{}
   290  	err := apparmorSpec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testSlot1)
   291  	c.Assert(err, IsNil)
   292  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.client-snap.app-accessing-2-devices"})
   293  	snippet := apparmorSpec.SnippetForTag("snap.client-snap.app-accessing-2-devices")
   294  	c.Assert(snippet, DeepEquals, expectedSnippet1)
   295  
   296  	expectedSnippet2 := `/dev/hidraw[0-9]{,[0-9],[0-9][0-9]} rw,`
   297  	apparmorSpec = &apparmor.Specification{}
   298  	err = apparmorSpec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testUDev1)
   299  	c.Assert(err, IsNil)
   300  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.client-snap.app-accessing-2-devices"})
   301  	snippet = apparmorSpec.SnippetForTag("snap.client-snap.app-accessing-2-devices")
   302  	c.Assert(snippet, DeepEquals, expectedSnippet2)
   303  
   304  	expectedSnippet3 := `/dev/hidraw[0-9]{,[0-9],[0-9][0-9]} rw,`
   305  	apparmorSpec = &apparmor.Specification{}
   306  	err = apparmorSpec.AddConnectedPlug(s.iface, s.testPlugPort2, s.testUDev2)
   307  	c.Assert(err, IsNil)
   308  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.client-snap.app-accessing-2-devices"})
   309  	snippet = apparmorSpec.SnippetForTag("snap.client-snap.app-accessing-2-devices")
   310  	c.Assert(snippet, DeepEquals, expectedSnippet3)
   311  }
   312  
   313  func (s *HidrawInterfaceSuite) TestConnectedPlugUDevSnippetsForPath(c *C) {
   314  	expectedSnippet1 := `# hidraw
   315  SUBSYSTEM=="hidraw", KERNEL=="hidraw0", TAG+="snap_client-snap_app-accessing-2-devices"`
   316  	expectedExtraSnippet1 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   317  	udevSpec := &udev.Specification{}
   318  	err := udevSpec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testSlot1)
   319  	c.Assert(err, IsNil)
   320  	c.Assert(udevSpec.Snippets(), HasLen, 2)
   321  	snippet := udevSpec.Snippets()[0]
   322  	c.Assert(snippet, Equals, expectedSnippet1)
   323  	extraSnippet := udevSpec.Snippets()[1]
   324  	c.Assert(extraSnippet, Equals, expectedExtraSnippet1)
   325  
   326  	expectedSnippet2 := `# hidraw
   327  IMPORT{builtin}="usb_id"
   328  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0001", ATTRS{idProduct}=="0001", TAG+="snap_client-snap_app-accessing-2-devices"`
   329  	expectedExtraSnippet2 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   330  	udevSpec = &udev.Specification{}
   331  	err = udevSpec.AddConnectedPlug(s.iface, s.testPlugPort1, s.testUDev1)
   332  	c.Assert(err, IsNil)
   333  	c.Assert(udevSpec.Snippets(), HasLen, 2)
   334  	snippet = udevSpec.Snippets()[0]
   335  	c.Assert(snippet, Equals, expectedSnippet2)
   336  	extraSnippet = udevSpec.Snippets()[1]
   337  	c.Assert(extraSnippet, Equals, expectedExtraSnippet2)
   338  
   339  	expectedSnippet3 := `# hidraw
   340  IMPORT{builtin}="usb_id"
   341  SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="ffff", ATTRS{idProduct}=="ffff", TAG+="snap_client-snap_app-accessing-2-devices"`
   342  	expectedExtraSnippet3 := `TAG=="snap_client-snap_app-accessing-2-devices", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_client-snap_app-accessing-2-devices $devpath $major:$minor"`
   343  	udevSpec = &udev.Specification{}
   344  	err = udevSpec.AddConnectedPlug(s.iface, s.testPlugPort2, s.testUDev2)
   345  	c.Assert(err, IsNil)
   346  	c.Assert(udevSpec.Snippets(), HasLen, 2)
   347  	snippet = udevSpec.Snippets()[0]
   348  	c.Assert(snippet, Equals, expectedSnippet3)
   349  	extraSnippet = udevSpec.Snippets()[1]
   350  	c.Assert(extraSnippet, Equals, expectedExtraSnippet3)
   351  }
   352  
   353  func (s *HidrawInterfaceSuite) TestInterfaces(c *C) {
   354  	c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
   355  }