Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
Already on GitHub? Sign in to your account
interfaces/builtin: add kvm interface #3609
Merged
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
205289e
Introduce the kvm interface
Saviq 75a8dc1
Fix copyright year
Saviq b84efaf
Fix man reference
Saviq 6af77f9
Fixes based on review comments
Saviq 392d3c0
Rename MetaData to StaticInfo
Saviq eb6a2b3
Adapt to new test interfaces
Saviq d0d3298
Merge branch 'master' of github.com:snapcore/snapd into kvm-interface
zyga
Jump to file or symbol
Failed to load files and symbols.
| @@ -0,0 +1,88 @@ | ||
| +// -*- 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" | ||
| +) | ||
| + | ||
| +const kvmSummary = `allows access to the kvm device` | ||
| + | ||
| +const kvmBaseDeclarationSlots = ` | ||
| + kvm: | ||
| + allow-installation: | ||
| + slot-snap-type: | ||
| + - core | ||
| + deny-auto-connection: true | ||
| +` | ||
| + | ||
| +const kvmConnectedPlugAppArmor = ` | ||
| +# Description: Allow write access to kvm. | ||
| +# See 'man kvm' for details. | ||
| + | ||
| +/dev/kvm rw, | ||
| +` | ||
| + | ||
| +// The type for kvm interface | ||
| +type kvmInterface struct{} | ||
| + | ||
| +func (iface *kvmInterface) Name() string { | ||
| + return "kvm" | ||
| +} | ||
| + | ||
| +func (iface *kvmInterface) StaticInfo() interfaces.StaticInfo { | ||
| + return interfaces.StaticInfo{ | ||
| + Summary: kvmSummary, | ||
| + ImplicitOnClassic: true, | ||
| + ImplicitOnCore: true, | ||
| + BaseDeclarationSlots: kvmBaseDeclarationSlots, | ||
| + } | ||
| +} | ||
| + | ||
| +func (iface *kvmInterface) SanitizeSlot(slot *interfaces.Slot) error { | ||
| + return sanitizeSlotReservedForOS(iface, slot) | ||
| +} | ||
| + | ||
| +func (iface *kvmInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error { | ||
| + spec.AddSnippet(kvmConnectedPlugAppArmor) | ||
| + return nil | ||
| +} | ||
| + | ||
| +func (iface *kvmInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error { | ||
| + const udevRule = `KERNEL=="kvm", TAG+="%s"` | ||
| + for appName := range plug.Apps { | ||
| + tag := udevSnapSecurityName(plug.Snap.Name(), appName) | ||
| + spec.AddSnippet(fmt.Sprintf(udevRule, tag)) | ||
| + } | ||
| + return nil | ||
| +} | ||
| + | ||
| +func (iface *kvmInterface) AutoConnect(*interfaces.Plug, *interfaces.Slot) bool { | ||
| + // Allow what is allowed in the declarations | ||
| + return true | ||
| +} | ||
| + | ||
| +func init() { | ||
| + registerIface(&kvmInterface{}) | ||
| +} |
| @@ -0,0 +1,98 @@ | ||
| +// -*- 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_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 kvmInterfaceSuite struct { | ||
| + iface interfaces.Interface | ||
| + slot *interfaces.Slot | ||
| + plug *interfaces.Plug | ||
| +} | ||
| + | ||
| +var _ = Suite(&kvmInterfaceSuite{ | ||
| + iface: builtin.MustInterface("kvm"), | ||
| +}) | ||
| + | ||
| +func (s *kvmInterfaceSuite) SetUpTest(c *C) { | ||
| + info := snaptest.MockInfo(c, ` | ||
| +name: core | ||
| +type: os | ||
| +slots: | ||
| + kvm: | ||
| + interface: kvm | ||
| +`, nil) | ||
| + s.slot = &interfaces.Slot{SlotInfo: info.Slots["kvm"]} | ||
| + | ||
| + info = snaptest.MockInfo(c, ` | ||
| +name: consumer | ||
| +apps: | ||
| + app: | ||
| + plugs: [kvm] | ||
| +`, nil) | ||
| + s.plug = &interfaces.Plug{PlugInfo: info.Plugs["kvm"]} | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestName(c *C) { | ||
| + c.Assert(s.iface.Name(), Equals, "kvm") | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestSanitizeSlot(c *C) { | ||
| + c.Assert(s.slot.Sanitize(s.iface), IsNil) | ||
| + slot := &interfaces.Slot{SlotInfo: &snap.SlotInfo{ | ||
| + Snap: &snap.Info{SuggestedName: "some-snap"}, | ||
| + Name: "kvm", | ||
| + Interface: "kvm", | ||
| + }} | ||
| + c.Assert(slot.Sanitize(s.iface), ErrorMatches, | ||
| + "kvm slots are reserved for the core snap") | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestSanitizePlug(c *C) { | ||
| + c.Assert(s.plug.Sanitize(s.iface), IsNil) | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestUDevSpec(c *C) { | ||
| + spec := &udev.Specification{} | ||
| + c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.slot, nil), IsNil) | ||
| + c.Assert(spec.Snippets(), HasLen, 1) | ||
| + c.Assert(spec.Snippets()[0], Equals, `KERNEL=="kvm", TAG+="snap_consumer_app"`) | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestAppArmorSpec(c *C) { | ||
| + spec := &apparmor.Specification{} | ||
| + c.Assert(spec.AddConnectedPlug(s.iface, s.plug, nil, s.slot, nil), IsNil) | ||
| + c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) | ||
| + c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "/dev/kvm rw,") | ||
| +} | ||
| + | ||
| +func (s *kvmInterfaceSuite) TestInterfaces(c *C) { | ||
| + c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface) | ||
| +} |