Permalink
Browse files

Merge pull request #2424 from tonyespy/add-dev-mem-interfaces

interfaces/builtin: add physical-memory-* and io-ports-control
  • Loading branch information...
2 parents 4776648 + b51c3ec commit aec795f7c9df5c3fe9d97c43b7518cb7764272fe @mvo5 mvo5 committed on GitHub Jan 11, 2017
@@ -36,6 +36,7 @@ var allInterfaces = []interfaces.Interface{
&HidrawInterface{},
&I2cInterface{},
&IioInterface{},
+ &IioPortsControlInterface{},
&LocationControlInterface{},
&LocationObserveInterface{},
&LxdInterface{},
@@ -45,6 +46,8 @@ var allInterfaces = []interfaces.Interface{
&MprisInterface{},
&NetworkManagerInterface{},
&OfonoInterface{},
+ &PhysicalMemoryControlInterface{},
+ &PhysicalMemoryObserveInterface{},
&PppInterface{},
&PulseAudioInterface{},
&SerialPortInterface{},
@@ -44,11 +44,14 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, Contains, &builtin.HidrawInterface{})
c.Check(all, Contains, &builtin.I2cInterface{})
c.Check(all, Contains, &builtin.IioInterface{})
+ c.Check(all, Contains, &builtin.IioPortsControlInterface{})
c.Check(all, Contains, &builtin.LocationControlInterface{})
c.Check(all, Contains, &builtin.LocationObserveInterface{})
c.Check(all, Contains, &builtin.LxdSupportInterface{})
c.Check(all, Contains, &builtin.MirInterface{})
c.Check(all, Contains, &builtin.MprisInterface{})
+ c.Check(all, Contains, &builtin.PhysicalMemoryControlInterface{})
+ c.Check(all, Contains, &builtin.PhysicalMemoryObserveInterface{})
c.Check(all, Contains, &builtin.PulseAudioInterface{})
c.Check(all, Contains, &builtin.SerialPortInterface{})
c.Check(all, Contains, &builtin.TimeControlInterface{})
@@ -280,6 +280,11 @@ slots:
- gadget
- core
deny-auto-connection: true
+ io-ports-control:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
kernel-module-control:
allow-installation:
slot-snap-type:
@@ -404,6 +409,16 @@ slots:
allow-installation:
slot-snap-type:
- core
+ physical-memory-control:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
+ physical-memory-observe:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
ppp:
allow-installation:
slot-snap-type:
@@ -0,0 +1,124 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin
+
+import (
+ "bytes"
+ "fmt"
+
+ "github.com/snapcore/snapd/interfaces"
+)
+
+const ioPortsControlConnectedPlugAppArmor = `
+# Description: Allow write access to all I/O ports.
+# See 'man 4 mem' for details.
+
+capability sys_rawio, # required by iopl
+
+/dev/ports rw,
+`
+
+const ioPortsControlConnectedPlugSecComp = `
+# Description: Allow changes to the I/O port permissions and
+# privilege level of the calling process. In addition to granting
+# unrestricted I/O port access, running at a higher I/O privilege
+# level also allows the process to disable interrupts. This will
+# probably crash the system, and is not recommended.
+ioperm
+iopl
+`
+
+// The type for io-ports-control interface
+type IioPortsControlInterface struct{}
+
+// Getter for the name of the io-ports-control interface
+func (iface *IioPortsControlInterface) Name() string {
+ return "io-ports-control"
+}
+
+func (iface *IioPortsControlInterface) String() string {
+ return iface.Name()
+}
+
+// Check validity of the defined slot
+func (iface *IioPortsControlInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ // Does it have right type?
+ if iface.Name() != slot.Interface {
+ panic(fmt.Sprintf("slot is not of interface %q", iface))
+ }
+
+ // Creation of the slot of this type
+ // is allowed only by a gadget or os snap
+ if !(slot.Snap.Type == "os") {
+ return fmt.Errorf("%s slots only allowed on core snap", iface.Name())
+ }
+ return nil
+}
+
+// Checks and possibly modifies a plug
+func (iface *IioPortsControlInterface) SanitizePlug(plug *interfaces.Plug) error {
+ if iface.Name() != plug.Interface {
+ panic(fmt.Sprintf("plug is not of interface %q", iface))
+ }
+ // Currently nothing is checked on the plug side
+ return nil
+}
+
+// Returns snippet granted on install
+func (iface *IioPortsControlInterface) PermanentSlotSnippet(slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ return nil, nil
+}
+
+// Getter for the security snippet specific to the plug
+func (iface *IioPortsControlInterface) ConnectedPlugSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ switch securitySystem {
+ case interfaces.SecurityAppArmor:
+ return []byte(ioPortsControlConnectedPlugAppArmor), nil
+
+ case interfaces.SecuritySecComp:
+ return []byte(ioPortsControlConnectedPlugSecComp), nil
+
+ case interfaces.SecurityUDev:
+ var tagSnippet bytes.Buffer
+ const udevRule = `KERNEL=="ports", TAG+="%s"`
+ for appName := range plug.Apps {
+ tag := udevSnapSecurityName(plug.Snap.Name(), appName)
+ tagSnippet.WriteString(fmt.Sprintf(udevRule, tag))
+ tagSnippet.WriteString("\n")
+ }
+ return tagSnippet.Bytes(), nil
+ }
+ return nil, nil
+}
+
+// No extra permissions granted on connection
+func (iface *IioPortsControlInterface) ConnectedSlotSnippet(plug *interfaces.Plug, slot *interfaces.Slot, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ return nil, nil
+}
+
+// No permissions granted to plug permanently
+func (iface *IioPortsControlInterface) PermanentPlugSnippet(plug *interfaces.Plug, securitySystem interfaces.SecuritySystem) ([]byte, error) {
+ return nil, nil
+}
+
+func (iface *IioPortsControlInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
+ // Allow what is allowed in the declarations
+ return true
+}
@@ -0,0 +1,128 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2016 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package builtin_test
+
+import (
+ . "gopkg.in/check.v1"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+)
+
+type IioPortsControlInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&IioPortsControlInterfaceSuite{
+ iface: &builtin.IioPortsControlInterface{},
+})
+
+func (s *IioPortsControlInterfaceSuite) SetUpTest(c *C) {
+ // Mock for OS Snap
+ osSnapInfo := snaptest.MockInfo(c, `
+name: ubuntu-core
+type: os
+slots:
+ test-io-ports:
+ interface: io-ports-control
+`, nil)
+ s.slot = &interfaces.Slot{SlotInfo: osSnapInfo.Slots["test-io-ports"]}
+
+ // Snap Consumers
+ consumingSnapInfo := snaptest.MockInfo(c, `
+name: client-snap
+plugs:
+ plug-for-io-ports:
+ interface: io-ports-control
+apps:
+ app-accessing-io-ports:
+ command: foo
+ plugs: [plug-for-io-ports]
+`, nil)
+ s.plug = &interfaces.Plug{PlugInfo: consumingSnapInfo.Plugs["plug-for-io-ports"]}
+}
+
+func (s *IioPortsControlInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "io-ports-control")
+}
+
+func (s *IioPortsControlInterfaceSuite) TestSanitizeSlot(c *C) {
+ err := s.iface.SanitizeSlot(s.slot)
+ c.Assert(err, IsNil)
+ err = s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{
+ Snap: &snap.Info{SuggestedName: "some-snap"},
+ Name: "io-ports-control",
+ Interface: "io-ports-control",
+ }})
+ c.Assert(err, ErrorMatches, "io-ports-control slots only allowed on core snap")
+}
+
+func (s *IioPortsControlInterfaceSuite) TestSanitizePlug(c *C) {
+ err := s.iface.SanitizePlug(s.plug)
+ c.Assert(err, IsNil)
+}
+
+func (s *IioPortsControlInterfaceSuite) TestSanitizeIncorrectInterface(c *C) {
+ c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) },
+ PanicMatches, `slot is not of interface "io-ports-control"`)
+ c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) },
+ PanicMatches, `plug is not of interface "io-ports-control"`)
+}
+
+func (s *IioPortsControlInterfaceSuite) TestUsedSecuritySystems(c *C) {
+ expectedSnippet1 := []byte(`
+# Description: Allow write access to all I/O ports.
+# See 'man 4 mem' for details.
+
+capability sys_rawio, # required by iopl
+
+/dev/ports rw,
+`)
+
+ expectedSnippet2 := []byte(`
+# Description: Allow changes to the I/O port permissions and
+# privilege level of the calling process. In addition to granting
+# unrestricted I/O port access, running at a higher I/O privilege
+# level also allows the process to disable interrupts. This will
+# probably crash the system, and is not recommended.
+ioperm
+iopl
+`)
+
+ expectedSnippet3 := []byte(`KERNEL=="ports", TAG+="snap_client-snap_app-accessing-io-ports"
+`)
+
+ // connected plugs have a non-nil security snippet for apparmor
+ snippet, err := s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityAppArmor)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, DeepEquals, expectedSnippet1, Commentf("\nexpected:\n%s\nfound:\n%s", expectedSnippet1, snippet))
+
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecuritySecComp)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, DeepEquals, expectedSnippet2, Commentf("\nexpected:\n%s\nfound:\n%s", expectedSnippet2, snippet))
+
+ snippet, err = s.iface.ConnectedPlugSnippet(s.plug, s.slot, interfaces.SecurityUDev)
+ c.Assert(err, IsNil)
+ c.Assert(snippet, DeepEquals, expectedSnippet3, Commentf("\nexpected:\n%s\nfound:\n%s", expectedSnippet3, snippet))
+}
Oops, something went wrong.

0 comments on commit aec795f

Please sign in to comment.