gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/netlink_driver_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2021 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  	"gitee.com/mysnapcore/mysnapd/interfaces"
    26  	"gitee.com/mysnapcore/mysnapd/interfaces/apparmor"
    27  	"gitee.com/mysnapcore/mysnapd/interfaces/builtin"
    28  	"gitee.com/mysnapcore/mysnapd/interfaces/seccomp"
    29  	"gitee.com/mysnapcore/mysnapd/snap"
    30  	"gitee.com/mysnapcore/mysnapd/snap/snaptest"
    31  	"gitee.com/mysnapcore/mysnapd/testutil"
    32  )
    33  
    34  type NetlinkDriverInterfaceSuite struct {
    35  	testutil.BaseTest
    36  
    37  	iface interfaces.Interface
    38  
    39  	// slots from gadget
    40  	gadgetNetlinkSlotInfo       *snap.SlotInfo
    41  	gadgetNetlinkSlot           *interfaces.ConnectedSlot
    42  	gadgetMissingNumberSlotInfo *snap.SlotInfo
    43  	gadgetMissingNumberSlot     *interfaces.ConnectedSlot
    44  	gadgetMissingNameSlotInfo   *snap.SlotInfo
    45  	gadgetMissingNameSlot       *interfaces.ConnectedSlot
    46  	gadgetBadNumberSlotInfo     *snap.SlotInfo
    47  	gadgetBadNumberSlot         *interfaces.ConnectedSlot
    48  	gadgetBadNameSlotInfo       *snap.SlotInfo
    49  	gadgetBadNameSlot           *interfaces.ConnectedSlot
    50  	gadgetBadNameStringSlotInfo *snap.SlotInfo
    51  	gadgetBadNameStringSlot     *interfaces.ConnectedSlot
    52  
    53  	// slot from core
    54  	osNetlinkSlotInfo *snap.SlotInfo
    55  	osNetlinkSlot     *interfaces.ConnectedSlot
    56  
    57  	// plugs from app
    58  	appToGadgetPlugDriverInfo            *snap.PlugInfo
    59  	appToGadgetPlugDriver                *interfaces.ConnectedPlug
    60  	appToCorePlugDriverInfo              *snap.PlugInfo
    61  	appToCorePlugDriver                  *interfaces.ConnectedPlug
    62  	appMissingFamilyNamePlugDriverInfo   *snap.PlugInfo
    63  	appMissingFamilyNamePlugDriver       *interfaces.ConnectedPlug
    64  	appBadFamilyNamePlugDriverInfo       *snap.PlugInfo
    65  	appBadFamilyNamePlugDriver           *interfaces.ConnectedPlug
    66  	appBadFamilyNameStringPlugDriverInfo *snap.PlugInfo
    67  	appBadFamilyNameStringPlugDriver     *interfaces.ConnectedPlug
    68  }
    69  
    70  var _ = Suite(&NetlinkDriverInterfaceSuite{
    71  	iface: builtin.MustInterface("netlink-driver"),
    72  })
    73  
    74  func (s *NetlinkDriverInterfaceSuite) SetUpTest(c *C) {
    75  	gadgetInfo := snaptest.MockInfo(c, `
    76  name: my-device
    77  version: 0
    78  type: gadget
    79  slots:
    80      my-driver:
    81          interface: netlink-driver
    82          family: 100
    83          family-name: foo-driver
    84      missing-number:
    85          interface: netlink-driver
    86          family-name: missing-number
    87      missing-name:
    88          interface: netlink-driver
    89          family: 400
    90      bad-number:
    91          interface: netlink-driver
    92          family: one-hundred
    93          family-name: foo-driver
    94      bad-family-name:
    95          interface: netlink-driver
    96          family: 100
    97          family-name: foo---------
    98      bad-family-name-string:
    99          interface: netlink-driver
   100          family: 100
   101          family-name: 12123323443432
   102  `, nil)
   103  	s.gadgetNetlinkSlotInfo = gadgetInfo.Slots["my-driver"]
   104  	s.gadgetNetlinkSlot = interfaces.NewConnectedSlot(s.gadgetNetlinkSlotInfo, nil, nil)
   105  	s.gadgetMissingNumberSlotInfo = gadgetInfo.Slots["missing-number"]
   106  	s.gadgetMissingNumberSlot = interfaces.NewConnectedSlot(s.gadgetMissingNumberSlotInfo, nil, nil)
   107  	s.gadgetMissingNameSlotInfo = gadgetInfo.Slots["missing-name"]
   108  	s.gadgetMissingNameSlot = interfaces.NewConnectedSlot(s.gadgetMissingNameSlotInfo, nil, nil)
   109  	s.gadgetBadNumberSlotInfo = gadgetInfo.Slots["bad-number"]
   110  	s.gadgetBadNumberSlot = interfaces.NewConnectedSlot(s.gadgetBadNumberSlotInfo, nil, nil)
   111  	s.gadgetBadNameSlotInfo = gadgetInfo.Slots["bad-family-name"]
   112  	s.gadgetBadNameSlot = interfaces.NewConnectedSlot(s.gadgetBadNameSlotInfo, nil, nil)
   113  	s.gadgetBadNameStringSlotInfo = gadgetInfo.Slots["bad-family-name-string"]
   114  	s.gadgetBadNameStringSlot = interfaces.NewConnectedSlot(s.gadgetBadNameStringSlotInfo, nil, nil)
   115  
   116  	osInfo := snaptest.MockInfo(c, `
   117  name: my-core
   118  version: 0
   119  type: os
   120  slots:
   121      my-driver:
   122          interface: netlink-driver
   123          family: 777
   124          family-name: seven-7-seven
   125  `, nil)
   126  	s.osNetlinkSlotInfo = osInfo.Slots["my-driver"]
   127  	s.osNetlinkSlot = interfaces.NewConnectedSlot(s.osNetlinkSlotInfo, nil, nil)
   128  
   129  	// Snap Consumers
   130  	consumingSnapInfo := snaptest.MockInfo(c, `
   131  name: client-snap
   132  version: 0
   133  plugs:
   134    plug-for-netlink-driver-777:
   135      interface: netlink-driver
   136      family-name: seven-7-seven
   137    plug-for-netlink-driver-foo:
   138      interface: netlink-driver
   139      family-name: foo-driver
   140    missing-family-name:
   141      interface: netlink-driver
   142    invalid-family-name:
   143      interface: netlink-driver
   144      family-name: ---foo-----
   145    invalid-family-name-string:
   146      interface: netlink-driver
   147      family-name: 1213123
   148  apps:
   149    netlink-test:
   150      command: bin/foo.sh
   151      plugs: 
   152        - plug-for-netlink-driver-777
   153        - plug-for-netlink-driver-foo
   154  `, nil)
   155  	s.appToCorePlugDriverInfo = consumingSnapInfo.Plugs["plug-for-netlink-driver-777"]
   156  	s.appToCorePlugDriver = interfaces.NewConnectedPlug(s.appToCorePlugDriverInfo, nil, nil)
   157  
   158  	s.appToGadgetPlugDriverInfo = consumingSnapInfo.Plugs["plug-for-netlink-driver-foo"]
   159  	s.appToGadgetPlugDriver = interfaces.NewConnectedPlug(s.appToCorePlugDriverInfo, nil, nil)
   160  
   161  	s.appBadFamilyNamePlugDriverInfo = consumingSnapInfo.Plugs["invalid-family-name"]
   162  	s.appBadFamilyNamePlugDriver = interfaces.NewConnectedPlug(s.appBadFamilyNamePlugDriverInfo, nil, nil)
   163  
   164  	s.appBadFamilyNameStringPlugDriverInfo = consumingSnapInfo.Plugs["invalid-family-name-string"]
   165  	s.appBadFamilyNameStringPlugDriver = interfaces.NewConnectedPlug(s.appBadFamilyNameStringPlugDriverInfo, nil, nil)
   166  
   167  	s.appMissingFamilyNamePlugDriverInfo = consumingSnapInfo.Plugs["missing-family-name"]
   168  	s.appMissingFamilyNamePlugDriver = interfaces.NewConnectedPlug(s.appMissingFamilyNamePlugDriverInfo, nil, nil)
   169  }
   170  
   171  func (s *NetlinkDriverInterfaceSuite) TestStaticInfo(c *C) {
   172  	si := interfaces.StaticInfoOf(s.iface)
   173  	c.Assert(si.ImplicitOnCore, Equals, false)
   174  	c.Assert(si.ImplicitOnClassic, Equals, false)
   175  	c.Assert(si.Summary, Equals, "allows operating a kernel driver module exposing itself via a netlink protocol family")
   176  	c.Assert(si.BaseDeclarationSlots, testutil.Contains, "netlink-driver")
   177  }
   178  
   179  func (s *NetlinkDriverInterfaceSuite) TestAutoConnect(c *C) {
   180  	// ensure the plug definitions in the YAML didn't change
   181  	c.Check(s.appToCorePlugDriverInfo.Attrs["family-name"], Equals, "seven-7-seven")
   182  	c.Check(s.osNetlinkSlotInfo.Attrs["family-name"], Equals, "seven-7-seven")
   183  
   184  	// ensure the plug definitions in the YAML didn't change
   185  	c.Check(s.appToGadgetPlugDriverInfo.Attrs["family-name"], Equals, "foo-driver")
   186  	c.Check(s.gadgetNetlinkSlotInfo.Attrs["family-name"], Equals, "foo-driver")
   187  
   188  	// with matching family-name attributes, it works
   189  	c.Check(s.iface.AutoConnect(s.appToCorePlugDriverInfo, s.osNetlinkSlotInfo), Equals, true)
   190  	c.Check(s.iface.AutoConnect(s.appToGadgetPlugDriverInfo, s.gadgetNetlinkSlotInfo), Equals, true)
   191  
   192  	// with different family-name attributes, it doesn't
   193  	c.Check(s.iface.AutoConnect(s.appToCorePlugDriverInfo, s.gadgetNetlinkSlotInfo), Equals, false)
   194  	c.Check(s.iface.AutoConnect(s.appToGadgetPlugDriverInfo, s.osNetlinkSlotInfo), Equals, false)
   195  }
   196  
   197  func (s *NetlinkDriverInterfaceSuite) TestInterfaces(c *C) {
   198  	c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
   199  }
   200  
   201  func (s *NetlinkDriverInterfaceSuite) TestSanitizeSlotGadgetSnap(c *C) {
   202  	// netlink slot on gadget accepted
   203  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetNetlinkSlotInfo), IsNil)
   204  
   205  	// slots without number attribute are rejected
   206  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetMissingNumberSlotInfo), ErrorMatches,
   207  		"netlink-driver slot must have a family number attribute")
   208  
   209  	// slots with number attribute that isnt a number
   210  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetBadNumberSlotInfo), ErrorMatches,
   211  		"netlink-driver slot family number attribute must be an int")
   212  
   213  	// slots without family-name
   214  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetMissingNameSlotInfo), ErrorMatches,
   215  		"netlink-driver slot must have a family-name attribute")
   216  
   217  	// slots with family-name attribute that isn't a string
   218  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetBadNameStringSlotInfo), ErrorMatches,
   219  		`netlink-driver slot family-name attribute must be a string`)
   220  
   221  	// slots with bad family-name
   222  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.gadgetBadNameSlotInfo), ErrorMatches,
   223  		`netlink-driver slot family-name "foo---------" is invalid`)
   224  }
   225  
   226  func (s *NetlinkDriverInterfaceSuite) TestSanitizePlugAppSnap(c *C) {
   227  	// netlink plug on app accepted
   228  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appToCorePlugDriverInfo), IsNil)
   229  
   230  	// plugs without family-name are rejected
   231  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appMissingFamilyNamePlugDriverInfo), ErrorMatches,
   232  		"netlink-driver plug must have a family-name attribute")
   233  
   234  	// slots with family-name attribute that isn't a string
   235  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appBadFamilyNameStringPlugDriverInfo), ErrorMatches,
   236  		`netlink-driver plug family-name attribute must be a string`)
   237  
   238  	// slots with bad family-name
   239  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appBadFamilyNamePlugDriverInfo), ErrorMatches,
   240  		`netlink-driver plug family-name "---foo-----" is invalid`)
   241  }
   242  
   243  func (s *NetlinkDriverInterfaceSuite) TestSanitizeSlotOsSnap(c *C) {
   244  	// netlink slot on OS accepted
   245  	c.Assert(interfaces.BeforePrepareSlot(s.iface, s.osNetlinkSlotInfo), IsNil)
   246  }
   247  
   248  func (s *NetlinkDriverInterfaceSuite) TestSanitizePlug(c *C) {
   249  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appToCorePlugDriverInfo), IsNil)
   250  	c.Assert(interfaces.BeforePreparePlug(s.iface, s.appToGadgetPlugDriverInfo), IsNil)
   251  }
   252  
   253  func (s *NetlinkDriverInterfaceSuite) TestApparmorConnectedPlug(c *C) {
   254  	spec := &apparmor.Specification{}
   255  	c.Assert(spec.AddConnectedPlug(s.iface, s.appToCorePlugDriver, s.gadgetNetlinkSlot), IsNil)
   256  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.client-snap.netlink-test"})
   257  	c.Assert(spec.SnippetForTag("snap.client-snap.netlink-test"), testutil.Contains, `network netlink,`)
   258  }
   259  
   260  func (s *NetlinkDriverInterfaceSuite) TestSecCompConnectedPlug(c *C) {
   261  	spec := &seccomp.Specification{}
   262  	c.Assert(spec.AddConnectedPlug(s.iface, s.appToCorePlugDriver, s.osNetlinkSlot), IsNil)
   263  	c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.client-snap.netlink-test"})
   264  	c.Assert(spec.SnippetForTag("snap.client-snap.netlink-test"), testutil.Contains, `socket AF_NETLINK - 777`)
   265  
   266  	spec2 := &seccomp.Specification{}
   267  	c.Assert(spec2.AddConnectedPlug(s.iface, s.appToGadgetPlugDriver, s.gadgetNetlinkSlot), IsNil)
   268  	c.Assert(spec2.SecurityTags(), DeepEquals, []string{"snap.client-snap.netlink-test"})
   269  	c.Assert(spec2.SnippetForTag("snap.client-snap.netlink-test"), testutil.Contains, `socket AF_NETLINK - 100`)
   270  }