github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/fwupd_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  	"os"
    24  	"path/filepath"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/dirs"
    29  	"github.com/snapcore/snapd/interfaces"
    30  	"github.com/snapcore/snapd/interfaces/apparmor"
    31  	"github.com/snapcore/snapd/interfaces/builtin"
    32  	"github.com/snapcore/snapd/interfaces/dbus"
    33  	"github.com/snapcore/snapd/interfaces/mount"
    34  	"github.com/snapcore/snapd/interfaces/seccomp"
    35  	"github.com/snapcore/snapd/snap"
    36  	"github.com/snapcore/snapd/testutil"
    37  )
    38  
    39  type FwupdInterfaceSuite struct {
    40  	iface        interfaces.Interface
    41  	appSlotInfo  *snap.SlotInfo
    42  	appSlot      *interfaces.ConnectedSlot
    43  	coreSlotInfo *snap.SlotInfo
    44  	coreSlot     *interfaces.ConnectedSlot
    45  	plugInfo     *snap.PlugInfo
    46  	plug         *interfaces.ConnectedPlug
    47  }
    48  
    49  const mockPlugSnapInfoYaml = `name: uefi-fw-tools
    50  version: 1.0
    51  apps:
    52   app:
    53    command: foo
    54    plugs: [fwupd]
    55  `
    56  
    57  const mockAppSlotSnapInfoYaml = `name: uefi-fw-tools
    58  version: 1.0
    59  apps:
    60   app2:
    61    command: foo
    62    slots: [fwupd]
    63  `
    64  
    65  const mockCoreSlotSnapInfoYaml = `name: core
    66  type: os
    67  version: 1.0
    68  slots:
    69    fwupd:
    70  `
    71  
    72  var _ = Suite(&FwupdInterfaceSuite{
    73  	iface: builtin.MustInterface("fwupd"),
    74  })
    75  
    76  func (s *FwupdInterfaceSuite) SetUpTest(c *C) {
    77  	s.plug, s.plugInfo = MockConnectedPlug(c, mockPlugSnapInfoYaml, nil, "fwupd")
    78  	s.appSlot, s.appSlotInfo = MockConnectedSlot(c, mockAppSlotSnapInfoYaml, nil, "fwupd")
    79  	s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, mockCoreSlotSnapInfoYaml, nil, "fwupd")
    80  }
    81  
    82  func (s *FwupdInterfaceSuite) TestName(c *C) {
    83  	c.Assert(s.iface.Name(), Equals, "fwupd")
    84  }
    85  
    86  // The label glob when all apps are bound to the fwupd slot
    87  func (s *FwupdInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelAll(c *C) {
    88  	app1 := &snap.AppInfo{Name: "app1"}
    89  	app2 := &snap.AppInfo{Name: "app2"}
    90  	slot := &snap.SlotInfo{
    91  		Snap: &snap.Info{
    92  			SuggestedName: "uefi-fw-tools",
    93  			Apps:          map[string]*snap.AppInfo{"app1": app1, "app2": app2},
    94  		},
    95  		Name:      "fwupd",
    96  		Interface: "fwupd",
    97  		Apps:      map[string]*snap.AppInfo{"app1": app1, "app2": app2},
    98  	}
    99  
   100  	// connected plugs have a non-nil security snippet for apparmor
   101  	apparmorSpec := &apparmor.Specification{}
   102  	err := apparmorSpec.AddConnectedPlug(s.iface, s.plug, interfaces.NewConnectedSlot(slot, nil, nil))
   103  	c.Assert(err, IsNil)
   104  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   105  	c.Assert(apparmorSpec.SnippetForTag("snap.uefi-fw-tools.app"), testutil.Contains, `peer=(label="snap.uefi-fw-tools.*"),`)
   106  }
   107  
   108  // The label uses alternation when some, but not all, apps is bound to the fwupd slot
   109  func (s *FwupdInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelSome(c *C) {
   110  	app1 := &snap.AppInfo{Name: "app1"}
   111  	app2 := &snap.AppInfo{Name: "app2"}
   112  	app3 := &snap.AppInfo{Name: "app3"}
   113  	slot := &snap.SlotInfo{
   114  		Snap: &snap.Info{
   115  			SuggestedName: "uefi-fw-tools",
   116  			Apps:          map[string]*snap.AppInfo{"app1": app1, "app2": app2, "app3": app3},
   117  		},
   118  		Name:      "fwupd",
   119  		Interface: "fwupd",
   120  		Apps:      map[string]*snap.AppInfo{"app1": app1, "app2": app2},
   121  	}
   122  
   123  	apparmorSpec := &apparmor.Specification{}
   124  	err := apparmorSpec.AddConnectedPlug(s.iface, s.plug, interfaces.NewConnectedSlot(slot, nil, nil))
   125  	c.Assert(err, IsNil)
   126  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   127  	c.Assert(apparmorSpec.SnippetForTag("snap.uefi-fw-tools.app"), testutil.Contains, `peer=(label="snap.uefi-fw-tools.{app1,app2}"),`)
   128  }
   129  
   130  // The label uses short form when exactly one app is bound to the fwupd slot
   131  func (s *FwupdInterfaceSuite) TestConnectedPlugSnippetUsesSlotLabelOne(c *C) {
   132  	apparmorSpec := &apparmor.Specification{}
   133  	err := apparmorSpec.AddConnectedPlug(s.iface, s.plug, s.appSlot)
   134  	c.Assert(err, IsNil)
   135  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   136  	c.Assert(apparmorSpec.SnippetForTag("snap.uefi-fw-tools.app"), testutil.Contains, `peer=(label="snap.uefi-fw-tools.app2"),`)
   137  }
   138  
   139  func (s *FwupdInterfaceSuite) TestConnectedPlugSnippetToImplicitSlot(c *C) {
   140  	apparmorSpec := &apparmor.Specification{}
   141  	err := apparmorSpec.AddConnectedPlug(s.iface, s.plug, s.coreSlot)
   142  	c.Assert(err, IsNil)
   143  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   144  	c.Assert(apparmorSpec.SnippetForTag("snap.uefi-fw-tools.app"), testutil.Contains, `peer=(label=unconfined),`)
   145  }
   146  
   147  func (s *FwupdInterfaceSuite) TestUsedSecuritySystems(c *C) {
   148  	// connected plugs have a non-nil security snippet for apparmor
   149  	apparmorSpec := &apparmor.Specification{}
   150  	err := apparmorSpec.AddConnectedPlug(s.iface, s.plug, s.appSlot)
   151  	c.Assert(err, IsNil)
   152  	err = apparmorSpec.AddConnectedSlot(s.iface, s.plug, s.appSlot)
   153  	c.Assert(err, IsNil)
   154  	err = apparmorSpec.AddPermanentSlot(s.iface, s.appSlotInfo)
   155  	c.Assert(err, IsNil)
   156  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app", "snap.uefi-fw-tools.app2"})
   157  
   158  	dbusSpec := &dbus.Specification{}
   159  	err = dbusSpec.AddPermanentSlot(s.iface, s.appSlotInfo)
   160  	c.Assert(err, IsNil)
   161  	c.Assert(dbusSpec.SecurityTags(), HasLen, 1)
   162  
   163  	// UpdateNS rules are only applied if the permanent slot is provided by
   164  	// an app snap
   165  	updateNS := apparmorSpec.UpdateNS()
   166  	c.Check(updateNS, testutil.Contains, "  # Read-write access to /boot\n")
   167  
   168  	// When connecting to the implicit slot on Classic systems, we
   169  	// don't generate slot-side AppArmor rules.
   170  	apparmorSpec = &apparmor.Specification{}
   171  	err = apparmorSpec.AddConnectedPlug(s.iface, s.plug, s.coreSlot)
   172  	c.Assert(err, IsNil)
   173  	c.Assert(apparmorSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   174  	apparmorSpec = &apparmor.Specification{}
   175  	err = apparmorSpec.AddConnectedSlot(s.iface, s.plug, s.coreSlot)
   176  	c.Assert(err, IsNil)
   177  	err = apparmorSpec.AddPermanentSlot(s.iface, s.coreSlotInfo)
   178  	c.Assert(err, IsNil)
   179  	c.Assert(apparmorSpec.SecurityTags(), HasLen, 0)
   180  
   181  	// The same is true for D-Bus rules
   182  	dbusSpec = &dbus.Specification{}
   183  	err = dbusSpec.AddPermanentSlot(s.iface, s.coreSlotInfo)
   184  	c.Assert(err, IsNil)
   185  	c.Assert(dbusSpec.SecurityTags(), HasLen, 0)
   186  }
   187  
   188  func (s *FwupdInterfaceSuite) TestMountPermanentSlot(c *C) {
   189  	tmpdir := c.MkDir()
   190  	dirs.SetRootDir(tmpdir)
   191  
   192  	c.Assert(os.MkdirAll(filepath.Join(tmpdir, "/boot"), 0777), IsNil)
   193  
   194  	// If the permanent slot is provided by an app snap, the boot partition
   195  	// should be bind mounted from the host system if they exist.
   196  	mountSpec := &mount.Specification{}
   197  	c.Assert(mountSpec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil)
   198  
   199  	entries := mountSpec.MountEntries()
   200  	c.Assert(entries, HasLen, 1)
   201  
   202  	const hostfs = "/var/lib/snapd/hostfs"
   203  	c.Check(entries[0].Name, Equals, filepath.Join(hostfs, dirs.GlobalRootDir, "/boot"))
   204  	c.Check(entries[0].Dir, Equals, "/boot")
   205  	c.Check(entries[0].Options, DeepEquals, []string{"rbind", "rw"})
   206  }
   207  
   208  func (s *FwupdInterfaceSuite) TestPermanentSlotSnippetSecComp(c *C) {
   209  	seccompSpec := &seccomp.Specification{}
   210  	err := seccompSpec.AddPermanentSlot(s.iface, s.appSlotInfo)
   211  	c.Assert(err, IsNil)
   212  	c.Assert(seccompSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app2"})
   213  	c.Check(seccompSpec.SnippetForTag("snap.uefi-fw-tools.app2"), testutil.Contains, "bind\n")
   214  
   215  	// On classic systems, fwupd is an implicit slot
   216  	seccompSpec = &seccomp.Specification{}
   217  	err = seccompSpec.AddPermanentSlot(s.iface, s.coreSlotInfo)
   218  	c.Assert(err, IsNil)
   219  	c.Assert(seccompSpec.SecurityTags(), HasLen, 0)
   220  }
   221  
   222  func (s *FwupdInterfaceSuite) TestPermanentSlotDBus(c *C) {
   223  	dbusSpec := &dbus.Specification{}
   224  	err := dbusSpec.AddPermanentSlot(s.iface, s.appSlotInfo)
   225  	c.Assert(err, IsNil)
   226  	c.Assert(dbusSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app2"})
   227  	c.Assert(dbusSpec.SnippetForTag("snap.uefi-fw-tools.app2"), testutil.Contains, `<allow own="org.freedesktop.fwupd"/>`)
   228  
   229  	// The implicit slot found on classic systems does not generate any rules
   230  	dbusSpec = &dbus.Specification{}
   231  	err = dbusSpec.AddPermanentSlot(s.iface, s.coreSlotInfo)
   232  	c.Assert(err, IsNil)
   233  	c.Assert(dbusSpec.SecurityTags(), HasLen, 0)
   234  }
   235  
   236  func (s *FwupdInterfaceSuite) TestConnectedPlugSnippetSecComp(c *C) {
   237  	seccompSpec := &seccomp.Specification{}
   238  	err := seccompSpec.AddConnectedPlug(s.iface, s.plug, s.appSlot)
   239  	c.Assert(err, IsNil)
   240  	c.Assert(seccompSpec.SecurityTags(), DeepEquals, []string{"snap.uefi-fw-tools.app"})
   241  	c.Check(seccompSpec.SnippetForTag("snap.uefi-fw-tools.app"), testutil.Contains, "bind\n")
   242  }
   243  
   244  func (s *FwupdInterfaceSuite) TestInterfaces(c *C) {
   245  	c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface)
   246  }