interfaces,interfaces/udev: add udev security backend #768

Merged
merged 16 commits into from Apr 4, 2016
@@ -1,33 +0,0 @@
-// -*- 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 interfaces
-
-import (
- "github.com/ubuntu-core/snappy/testutil"
-)
-
-// MockActiveSnapMetaData replaces the function used to determine version and origin of a given snap.
-func MockActiveSnapMetaData(test *testutil.BaseTest, fn func(string) (string, string, []string, error)) {
- orig := ActiveSnapMetaData
- ActiveSnapMetaData = fn
- test.AddCleanup(func() {
- ActiveSnapMetaData = orig
- })
-}
View
@@ -25,19 +25,6 @@ import (
"github.com/ubuntu-core/snappy/snap"
)
-// DEPRECATED: Remove after backends are converted to SecurityBackend.
-func WrapperNameForApp(snapName, appName string) string {
- if appName == snapName {
- return snapName
- }
- return fmt.Sprintf("%s.%s", snapName, appName)
-}
-
-// DEPRECATED: Remove after backends are converted to SecurityBackend.
-func SecurityTagForApp(snapName, appName string) string {
- return fmt.Sprintf("%s.snap", WrapperNameForApp(snapName, appName))
-}
-
// SecurityTag returns application-specific security tag.
//
// Security tags are used by various security subsystems as "profile names" and
@@ -30,18 +30,6 @@ type NamingSuite struct{}
var _ = Suite(&NamingSuite{})
-// Tests for WrapperNameForApp()
-
-func (s *NamingSuite) TestWrapperNameForApp(c *C) {
- c.Assert(WrapperNameForApp("snap", "app"), Equals, "snap.app")
- c.Assert(WrapperNameForApp("foo", "foo"), Equals, "foo")
-}
-
-func (s *NamingSuite) TestSecurityTagForApp(c *C) {
- c.Assert(SecurityTagForApp("snap", "app"), Equals, "snap.app.snap")
- c.Assert(SecurityTagForApp("foo", "foo"), Equals, "foo.snap")
-}
-
func (s *NamingSuite) TestSecurityTag(c *C) {
appInfo := &snap.AppInfo{Snap: &snap.Info{Name: "http"}, Name: "GET"}
c.Check(SecurityTag(appInfo), Equals, "snap.http.GET")
View
@@ -20,7 +20,6 @@
package interfaces
import (
- "bytes"
"fmt"
"sort"
"sync"
@@ -34,11 +33,10 @@ type Repository struct {
m sync.Mutex
ifaces map[string]Interface
// Indexed by [snapName][plugName]
- plugs map[string]map[string]*Plug
- slots map[string]map[string]*Slot
- slotPlugs map[*Slot]map[*Plug]bool
- plugSlots map[*Plug]map[*Slot]bool
- securityHelpers []securityHelper
+ plugs map[string]map[string]*Plug
+ slots map[string]map[string]*Slot
+ slotPlugs map[*Slot]map[*Plug]bool
+ plugSlots map[*Plug]map[*Slot]bool
}
// NewRepository creates an empty plug repository.
@@ -49,9 +47,6 @@ func NewRepository() *Repository {
slots: make(map[string]map[string]*Slot),
slotPlugs: make(map[*Slot]map[*Plug]bool),
plugSlots: make(map[*Plug]map[*Slot]bool),
- securityHelpers: []securityHelper{
- &uDev{},
- },
}
}
@@ -521,60 +516,3 @@ func (r *Repository) securitySnippetsForSnap(snapName string, securitySystem Sec
}
return snippets, nil
}
-
-// SecurityFilesForSnap returns the paths and contents of security files for a given snap.
-func (r *Repository) SecurityFilesForSnap(snapName string) (map[string][]byte, error) {
- r.m.Lock()
- defer r.m.Unlock()
-
- buffers := make(map[string]*bytes.Buffer)
- for _, helper := range r.securityHelpers {
- if err := r.collectFilesFromSecurityHelper(snapName, helper, buffers); err != nil {
- return nil, err
- }
- }
- blobs := make(map[string][]byte)
- for name, buffer := range buffers {
- blobs[name] = buffer.Bytes()
- }
- return blobs, nil
-}
-
-func (r *Repository) collectFilesFromSecurityHelper(snapName string, helper securityHelper, buffers map[string]*bytes.Buffer) error {
- securitySystem := helper.securitySystem()
- snapVersion, snapOrigin, snapApps, err := ActiveSnapMetaData(snapName)
- if err != nil {
- return fmt.Errorf("cannot determine meta-data for snap %s: %v", snapName, err)
- }
- appSnippets, err := r.securitySnippetsForSnap(snapName, securitySystem)
- if err != nil {
- return fmt.Errorf("cannot determine %s security snippets for snap %s: %v", securitySystem, snapName, err)
- }
- for _, appName := range snapApps {
- // NOTE: this explicitly iterates over all apps, even if they have no granted skills.
- // This way after revoking a skill permission are updated to reflect that.
- snippets := appSnippets[appName]
- writer := &bytes.Buffer{}
- path := helper.pathForApp(snapName, snapVersion, snapOrigin, appName)
- doWrite := func(blob []byte) error {
- _, err = writer.Write(blob)
- if err != nil {
- return fmt.Errorf("cannot write %s file for snap %s (app %s): %v", securitySystem, snapName, appName, err)
- }
- return nil
- }
- if err := doWrite(helper.headerForApp(snapName, snapVersion, snapOrigin, appName)); err != nil {
- return err
- }
- for _, snippet := range snippets {
- if err := doWrite(snippet); err != nil {
- return err
- }
- }
- if err := doWrite(helper.footerForApp(snapName, snapVersion, snapOrigin, appName)); err != nil {
- return err
- }
- buffers[path] = writer
- }
- return nil
-}
View
@@ -1,68 +0,0 @@
-// -*- 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 interfaces
-
-import (
- "fmt"
-)
-
-// securityHelper is an interface for common aspects of generating security files.
-type securityHelper interface {
- securitySystem() SecuritySystem
- pathForApp(snapName, snapVersion, snapOrigin, appName string) string
- headerForApp(snapName, snapVersion, snapOrigin, appName string) []byte
- footerForApp(snapName, snapVersion, snapOrigin, appName string) []byte
-}
-
-// uDev is a security subsystem that writes additional udev rules (one per snap).
-//
-// Each rule looks like this:
-//
-// KERNEL=="hiddev0", TAG:="snappy-assign", ENV{SNAPPY_APP}:="http.GET.snap"
-//
-// NOTE: This interacts with ubuntu-core-launcher.
-//
-// This tag is picked up by /lib/udev/rules.d/80-snappy-assign.rules which in
-// turn runs /lib/udev/snappy-app-dev script, which re-configures the device
-// cgroup at /sys/fs/cgroup/devices/snappy.$SNAPPY_APP for the acl
-// "c $major:$minor rwm" for character devices and "b $major:$minor rwm" for
-// block devices.
-//
-// $SNAPPY_APP is always computed with SecurityTagForApp()
-//
-// The control group is created by ubuntu-app-launcher.
-type uDev struct{}
-
-func (udev *uDev) securitySystem() SecuritySystem {
- return SecurityUDev
-}
-
-func (udev *uDev) pathForApp(snapName, snapVersion, snapOrigin, appName string) string {
- // NOTE: we ignore appName so effectively udev rules apply to entire snap.
- return fmt.Sprintf("/etc/udev/rules.d/70-%s.rules", SecurityTagForApp(snapName, appName))
-}
-
-func (udev *uDev) headerForApp(snapName, snapVersion, snapOrigin, appName string) []byte {
- return nil // udev doesn't require a header
-}
-
-func (udev *uDev) footerForApp(snapName, snapVersion, snapOrigin, appName string) []byte {
- return nil // udev doesn't require a footer
-}
@@ -1,120 +0,0 @@
-// -*- Mote: 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 interfaces_test
-
-import (
- . "gopkg.in/check.v1"
-
- . "github.com/ubuntu-core/snappy/interfaces"
- "github.com/ubuntu-core/snappy/snap"
- "github.com/ubuntu-core/snappy/testutil"
-)
-
-type SecuritySuite struct {
- testutil.BaseTest
- repo *Repository
- plug *Plug
- slot *Slot
-}
-
-var _ = Suite(&SecuritySuite{})
-
-func (s *SecuritySuite) SetUpTest(c *C) {
- s.BaseTest.SetUpTest(c)
- s.repo = NewRepository()
- // NOTE: the names producer/consumer are confusing. They will be fixed shortly.
- producer, err := snap.InfoFromSnapYaml([]byte(`
-name: producer
-apps:
- hook:
-plugs:
- plug: interface
-`))
- c.Assert(err, IsNil)
- consumer, err := snap.InfoFromSnapYaml([]byte(`
-name: consumer
-apps:
- app:
-slots:
- slot:
- interface: interface
- label: label
- attr: value
-`))
- c.Assert(err, IsNil)
- s.plug = &Plug{PlugInfo: producer.Plugs["plug"]}
- s.slot = &Slot{SlotInfo: consumer.Slots["slot"]}
- // TODO: make this obsolete thanks to unified and rich snap.Info
- MockActiveSnapMetaData(&s.BaseTest, func(snapName string) (string, string, []string, error) {
- switch snapName {
- case "producer":
- return "version", "origin", []string{"hook"}, nil
- case "consumer":
- return "version", "origin", []string{"app"}, nil
- default:
- panic("unexpected snap name")
- }
- })
-}
-
-func (s *SecuritySuite) prepareFixtureWithInterface(c *C, i Interface) {
- err := s.repo.AddInterface(i)
- c.Assert(err, IsNil)
- err = s.repo.AddPlug(s.plug)
- c.Assert(err, IsNil)
- err = s.repo.AddSlot(s.slot)
- c.Assert(err, IsNil)
- err = s.repo.Connect(s.plug.Snap.Name, s.plug.Name, s.slot.Snap.Name, s.slot.Name)
- c.Assert(err, IsNil)
-}
-
-// Tests for uDev
-
-func (s *SecuritySuite) TestUdevPlugPermissions(c *C) {
- s.prepareFixtureWithInterface(c, &TestInterface{
- InterfaceName: "interface",
- PlugSnippetCallback: func(plug *Plug, slot *Slot, securitySystem SecuritySystem) ([]byte, error) {
- if securitySystem == SecurityUDev {
- return []byte("...\n"), nil
- }
- return nil, nil
- },
- })
- // Ensure that plug-side security profile looks correct.
- blobs, err := s.repo.SecurityFilesForSnap(s.plug.Snap.Name)
- c.Assert(err, IsNil)
- c.Check(blobs["/etc/udev/rules.d/70-producer.hook.snap.rules"], DeepEquals, []byte("...\n"))
-}
-
-func (s *SecuritySuite) TestUdevSlotPermissions(c *C) {
- s.prepareFixtureWithInterface(c, &TestInterface{
- InterfaceName: "interface",
- SlotSnippetCallback: func(plug *Plug, slot *Slot, securitySystem SecuritySystem) ([]byte, error) {
- if securitySystem == SecurityUDev {
- return []byte("...\n"), nil
- }
- return nil, nil
- },
- })
- // Ensure that slot-side security profile looks correct.
- blobs, err := s.repo.SecurityFilesForSnap(s.slot.Snap.Name)
- c.Assert(err, IsNil)
- c.Check(blobs["/etc/udev/rules.d/70-consumer.app.snap.rules"], DeepEquals, []byte("...\n"))
-}
Oops, something went wrong.