interfaces: add random interface #3045

Merged
merged 17 commits into from May 8, 2017
@@ -27,14 +27,15 @@ var allInterfaces = []interfaces.Interface{
&BluezInterface{},
&BoolFileInterface{},
&BrowserSupportInterface{},
- NewClassicSupportInterface(),
&ContentInterface{},
&DbusInterface{},
&DockerInterface{},
&DockerSupportInterface{},
&FramebufferInterface{},
&FwupdInterface{},
&GpioInterface{},
+ &HardwareRandomControlInterface{},
+ &HardwareRandomObserveInterface{},
&HidrawInterface{},
&I2cInterface{},
&IioInterface{},
@@ -61,15 +62,16 @@ var allInterfaces = []interfaces.Interface{
&Unity7Interface{},
&UDisks2Interface{},
&UbuntuDownloadManagerInterface{},
+ &UhidInterface{},
&Unity8Interface{},
&UpowerObserveInterface{},
- &UhidInterface{},
NewAccountControlInterface(),
NewAlsaInterface(),
- NewAvahiObserveInterface(),
NewAutopilotIntrospectionInterface(),
+ NewAvahiObserveInterface(),
NewBluetoothControlInterface(),
NewCameraInterface(),
+ NewClassicSupportInterface(),
NewCoreSupportInterface(),
NewCupsControlInterface(),
NewDcdbasControlInterface(),
@@ -41,6 +41,8 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, DeepContains, &builtin.FramebufferInterface{})
c.Check(all, DeepContains, &builtin.FwupdInterface{})
c.Check(all, DeepContains, &builtin.GpioInterface{})
+ c.Check(all, DeepContains, &builtin.HardwareRandomControlInterface{})
+ c.Check(all, DeepContains, &builtin.HardwareRandomObserveInterface{})
c.Check(all, DeepContains, &builtin.HidrawInterface{})
c.Check(all, DeepContains, &builtin.I2cInterface{})
c.Check(all, DeepContains, &builtin.IioInterface{})
@@ -49,8 +51,8 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, DeepContains, &builtin.LocationControlInterface{})
c.Check(all, DeepContains, &builtin.LocationObserveInterface{})
c.Check(all, DeepContains, &builtin.LxdSupportInterface{})
- c.Check(all, DeepContains, &builtin.MediaHubInterface{})
c.Check(all, DeepContains, &builtin.MaliitInterface{})
+ c.Check(all, DeepContains, &builtin.MediaHubInterface{})
c.Check(all, DeepContains, &builtin.MirInterface{})
c.Check(all, DeepContains, &builtin.MprisInterface{})
c.Check(all, DeepContains, &builtin.PhysicalMemoryControlInterface{})
@@ -61,14 +63,14 @@ func (s *AllSuite) TestInterfaces(c *C) {
c.Check(all, DeepContains, &builtin.TimeControlInterface{})
c.Check(all, DeepContains, &builtin.UDisks2Interface{})
c.Check(all, DeepContains, &builtin.UbuntuDownloadManagerInterface{})
- c.Check(all, DeepContains, &builtin.Unity8Interface{})
- c.Check(all, DeepContains, &builtin.UpowerObserveInterface{})
c.Check(all, DeepContains, &builtin.UhidInterface{})
c.Check(all, DeepContains, &builtin.Unity7Interface{})
+ c.Check(all, DeepContains, &builtin.Unity8Interface{})
+ c.Check(all, DeepContains, &builtin.UpowerObserveInterface{})
c.Check(all, DeepContains, builtin.NewAccountControlInterface())
c.Check(all, DeepContains, builtin.NewAlsaInterface())
- c.Check(all, DeepContains, builtin.NewAvahiObserveInterface())
c.Check(all, DeepContains, builtin.NewAutopilotIntrospectionInterface())
+ c.Check(all, DeepContains, builtin.NewAvahiObserveInterface())
c.Check(all, DeepContains, builtin.NewBluetoothControlInterface())
c.Check(all, DeepContains, builtin.NewCameraInterface())
c.Check(all, DeepContains, builtin.NewCupsControlInterface())
@@ -310,6 +310,16 @@ slots:
- core
deny-auto-connection:
on-classic: false
+ hardware-random-observe:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
+ hardware-random-control:
+ allow-installation:
+ slot-snap-type:
+ - core
+ deny-auto-connection: true
i2c:
allow-installation:
slot-snap-type:
@@ -147,9 +147,9 @@ func (s *baseDeclSuite) TestAutoConnection(c *C) {
"optical-drive": true,
"pulseaudio": true,
"screen-inhibit-control": true,
+ "ubuntu-download-manager": true,
"unity7": true,
"unity8": true,
- "ubuntu-download-manager": true,
"upower-observe": true,
"x11": true,
}
@@ -0,0 +1,93 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 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 (
+ "fmt"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/snap"
+)
+
+const hardwareRandomControlConnectedPlugAppArmor = `
+# Description: allow direct access to the hardware random number generator
+# device. Usually, the default access to /dev/random is sufficient, but this
+# allows applications such as rng-tools to use /dev/hwrng directly or change
+# the hwrng via sysfs. For details, see
+# https://www.kernel.org/doc/Documentation/hw_random.txt
+
+/dev/hwrng rw,
+/run/udev/data/c10:183 r,
+/sys/devices/virtual/misc/ r,
+/sys/devices/virtual/misc/hw_random/rng_{available,current} r,
+
+# Allow changing the hwrng
+/sys/devices/virtual/misc/hw_random/rng_current w,
+`
+
+// The type for physical-memory-control interface
+type HardwareRandomControlInterface struct{}
+
+// Getter for the name of the physical-memory-control interface
+func (iface *HardwareRandomControlInterface) Name() string {
+ return "hardware-random-control"
+}
+
+// Check validity of the defined slot
+func (iface *HardwareRandomControlInterface) 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.Name()))
+ }
+ if slot.Snap.Type != snap.TypeOS {
+ return fmt.Errorf("%s slots are reserved for the operating system snap", iface.Name())
+ }
+ return nil
+}
+
+// Checks and possibly modifies a plug
+func (iface *HardwareRandomControlInterface) SanitizePlug(plug *interfaces.Plug) error {
+ if iface.Name() != plug.Interface {
+ panic(fmt.Sprintf("plug is not of interface %q", iface.Name()))
+ }
+ // Currently nothing is checked on the plug side
+ return nil
+}
+
+func (iface *HardwareRandomControlInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ spec.AddSnippet(hardwareRandomControlConnectedPlugAppArmor)
+ return nil
+}
+
+func (iface *HardwareRandomControlInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ const udevRule = `KERNEL=="hwrng", TAG+="%s"`
+ for appName := range plug.Apps {
+ tag := udevSnapSecurityName(plug.Snap.Name(), appName)
+ spec.AddSnippet(fmt.Sprintf(udevRule, tag))
+ }
+ return nil
+}
+
+func (iface *HardwareRandomControlInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
+ // Allow what is allowed in the declarations
+ return true
+}
@@ -0,0 +1,104 @@
+// -*- 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/apparmor"
+ "github.com/snapcore/snapd/interfaces/builtin"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/snap"
+ "github.com/snapcore/snapd/snap/snaptest"
+ "github.com/snapcore/snapd/testutil"
+)
+
+type HardwareRandomControlInterfaceSuite struct {
+ iface interfaces.Interface
+ slot *interfaces.Slot
+ plug *interfaces.Plug
+}
+
+var _ = Suite(&HardwareRandomControlInterfaceSuite{
+ iface: &builtin.HardwareRandomControlInterface{},
+})
+
+func (s *HardwareRandomControlInterfaceSuite) SetUpTest(c *C) {
+ // Mock for OS Snap
+ osSnapInfo := snaptest.MockInfo(c, `
+name: core
+type: os
+slots:
+ hardware-random-control:
+`, nil)
+ s.slot = &interfaces.Slot{SlotInfo: osSnapInfo.Slots["hardware-random-control"]}
+
+ // Snap Consumers
+ consumingSnapInfo := snaptest.MockInfo(c, `
+name: snap
+apps:
+ app:
+ command: foo
+ plugs: [hardware-random-control]
+`, nil)
+ s.plug = &interfaces.Plug{PlugInfo: consumingSnapInfo.Plugs["hardware-random-control"]}
+}
+
+func (s *HardwareRandomControlInterfaceSuite) TestName(c *C) {
+ c.Assert(s.iface.Name(), Equals, "hardware-random-control")
+}
+
+func (s *HardwareRandomControlInterfaceSuite) 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: "hardware-random-control",
+ Interface: "hardware-random-control",
+ }})
+ c.Assert(err, ErrorMatches, "hardware-random-control slots are reserved for the operating system snap")
+}
+
+func (s *HardwareRandomControlInterfaceSuite) TestSanitizePlug(c *C) {
+ err := s.iface.SanitizePlug(s.plug)
+ c.Assert(err, IsNil)
+}
+
+func (s *HardwareRandomControlInterfaceSuite) TestSanitizeIncorrectInterface(c *C) {
+ c.Assert(func() { s.iface.SanitizeSlot(&interfaces.Slot{SlotInfo: &snap.SlotInfo{Interface: "other"}}) },
+ PanicMatches, `slot is not of interface "hardware-random-control"`)
+ c.Assert(func() { s.iface.SanitizePlug(&interfaces.Plug{PlugInfo: &snap.PlugInfo{Interface: "other"}}) },
+ PanicMatches, `plug is not of interface "hardware-random-control"`)
+}
+
+func (s *HardwareRandomControlInterfaceSuite) TestAppArmorSpec(c *C) {
+ spec := &apparmor.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
+ c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.snap.app"})
+ c.Assert(spec.SnippetForTag("snap.snap.app"), testutil.Contains, "hw_random/rng_current w,")
+}
+
+func (s *HardwareRandomControlInterfaceSuite) TestUDevSpec(c *C) {
+ spec := &udev.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.slot), IsNil)
+ expected := []string{`KERNEL=="hwrng", TAG+="snap_snap_app"`}
+ c.Assert(spec.Snippets(), DeepEquals, expected)
+}
@@ -0,0 +1,87 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2017 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 (
+ "fmt"
+
+ "github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/interfaces/apparmor"
+ "github.com/snapcore/snapd/interfaces/udev"
+ "github.com/snapcore/snapd/snap"
+)
+
+const hardwareRandomObserveConnectedPlugAppArmor = `
+# Description: allow direct read-only access to the hardware random number
+# generator device. In addition allow observing the available and
+# currently-selected hardware random number generator devices.
+
+/dev/hwrng r,
+/run/udev/data/c10:183 r,
+/sys/devices/virtual/misc/ r,
+/sys/devices/virtual/misc/hw_random/rng_{available,current} r,
+`
+
+// The type for physical-memory-control interface
+type HardwareRandomObserveInterface struct{}
+
+// Getter for the name of the physical-memory-control interface
+func (iface *HardwareRandomObserveInterface) Name() string {
+ return "hardware-random-observe"
+}
+
+// Check validity of the defined slot
+func (iface *HardwareRandomObserveInterface) SanitizeSlot(slot *interfaces.Slot) error {
+ if iface.Name() != slot.Interface {
+ panic(fmt.Sprintf("slot is not of interface %q", iface.Name()))
+ }
+ if slot.Snap.Type != snap.TypeOS {
+ return fmt.Errorf("%s slots are reserved for the operating system snap", iface.Name())
+ }
+ return nil
+}
+
+// Checks and possibly modifies a plug
+func (iface *HardwareRandomObserveInterface) SanitizePlug(plug *interfaces.Plug) error {
+ if iface.Name() != plug.Interface {
+ panic(fmt.Sprintf("plug is not of interface %q", iface.Name()))
+ }
+ // Currently nothing is checked on the plug side
+ return nil
+}
+
+func (iface *HardwareRandomObserveInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ spec.AddSnippet(hardwareRandomObserveConnectedPlugAppArmor)
+ return nil
+}
+
+func (iface *HardwareRandomObserveInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.Plug, slot *interfaces.Slot) error {
+ const udevRule = `KERNEL=="hwrng", TAG+="%s"`
+ for appName := range plug.Apps {
+ tag := udevSnapSecurityName(plug.Snap.Name(), appName)
+ spec.AddSnippet(fmt.Sprintf(udevRule, tag))
+ }
+ return nil
+}
+
+func (iface *HardwareRandomObserveInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool {
+ // Allow what is allowed in the declarations
+ return true
+}
Oops, something went wrong.