Skip to content

Commit

Permalink
Merge pull request #2424 from tonyespy/add-dev-mem-interfaces
Browse files Browse the repository at this point in the history
interfaces/builtin: add physical-memory-* and io-ports-control
  • Loading branch information
mvo5 committed Jan 11, 2017
2 parents 4776648 + b51c3ec commit aec795f
Show file tree
Hide file tree
Showing 10 changed files with 728 additions and 0 deletions.
3 changes: 3 additions & 0 deletions interfaces/builtin/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var allInterfaces = []interfaces.Interface{
&HidrawInterface{},
&I2cInterface{},
&IioInterface{},
&IioPortsControlInterface{},
&LocationControlInterface{},
&LocationObserveInterface{},
&LxdInterface{},
Expand All @@ -45,6 +46,8 @@ var allInterfaces = []interfaces.Interface{
&MprisInterface{},
&NetworkManagerInterface{},
&OfonoInterface{},
&PhysicalMemoryControlInterface{},
&PhysicalMemoryObserveInterface{},
&PppInterface{},
&PulseAudioInterface{},
&SerialPortInterface{},
Expand Down
3 changes: 3 additions & 0 deletions interfaces/builtin/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{})
Expand Down
15 changes: 15 additions & 0 deletions interfaces/builtin/basedeclaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
124 changes: 124 additions & 0 deletions interfaces/builtin/io_ports_control.go
Original file line number Diff line number Diff line change
@@ -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
}
128 changes: 128 additions & 0 deletions interfaces/builtin/io_ports_control_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
Loading

0 comments on commit aec795f

Please sign in to comment.