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