1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2016-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"
"path/filepath"
"regexp"
"strings"
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/udev"
"github.com/snapcore/snapd/snap"
)
const iioSummary = `allows access to a specific IIO device`
const iioBaseDeclarationSlots = `
iio:
allow-installation:
slot-snap-type:
- gadget
- core
deny-auto-connection: true
`
const iioConnectedPlugAppArmor = `
# Description: Give access to a specific IIO device on the system.
###IIO_DEVICE_PATH### rw,
/sys/bus/iio/devices/###IIO_DEVICE_NAME###/ r,
/sys/bus/iio/devices/###IIO_DEVICE_NAME###/** rwk,
`
// The type for iio interface
type iioInterface struct{}
// Getter for the name of the iio interface
func (iface *iioInterface) Name() string {
return "iio"
}
func (iface *iioInterface) StaticInfo() interfaces.StaticInfo {
return interfaces.StaticInfo{
Summary: iioSummary,
BaseDeclarationSlots: iioBaseDeclarationSlots,
}
}
func (iface *iioInterface) String() string {
return iface.Name()
}
// Pattern to match allowed iio device nodes. It is going to be used to check the
// validity of the path attributes in case the udev is not used for
// identification
var iioControlDeviceNodePattern = regexp.MustCompile("^/dev/iio:device[0-9]+$")
// Check validity of the defined slot
func (iface *iioInterface) BeforePrepareSlot(slot *snap.SlotInfo) error {
// Validate the path
path, ok := slot.Attrs["path"].(string)
if !ok || path == "" {
return fmt.Errorf("%s slot must have a path attribute", iface.Name())
}
// XXX: this interface feeds the cleaned path into the regex and is
// left unchanged here for historical reasons. New interfaces (eg,
// like raw-volume) should instead use verifySlotPathAttribute() which
// performs additional verification.
path = filepath.Clean(path)
if !iioControlDeviceNodePattern.MatchString(path) {
return fmt.Errorf("%s path attribute must be a valid device node", iface.Name())
}
return nil
}
func (iface *iioInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
var path string
if err := slot.Attr("path", &path); err != nil {
return nil
}
cleanedPath := filepath.Clean(path)
snippet := strings.Replace(iioConnectedPlugAppArmor, "###IIO_DEVICE_PATH###", cleanedPath, -1)
// The path is already verified against a regular expression
// in BeforePrepareSlot so we can rely on its structure here and
// safely strip the '/dev/' prefix to get the actual name of
// the IIO device.
deviceName := strings.TrimPrefix(path, "/dev/")
snippet = strings.Replace(snippet, "###IIO_DEVICE_NAME###", deviceName, -1)
// Add a snippet for various device specific rules, except for sysfs write
// access that are specialized below.
spec.AddSnippet(snippet)
// Because all deviceName values have the prefix of "iio:device" enforced
// by the sanitization logic above, we can trim that prefix and provide a
// shorter expansion expression.
deviceNum := strings.TrimPrefix(deviceName, "iio:device")
// Use parametric snippets to avoid no-expr-simplify side-effects.
spec.AddParametricSnippet([]string{
"/sys/devices/**/iio:device" /* ###PARAM### */, "/** rwk, # Add any condensed parametric rules",
}, deviceNum)
// For consistency, not an efficiency problem.
spec.AddParametricSnippet([]string{
"/sys/devices/**/iio:device" /* ###PARAM### */, "/ r, # Add any condensed parametric rules",
}, deviceNum)
return nil
}
func (iface *iioInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
var path string
if err := slot.Attr("path", &path); err != nil {
return nil
}
spec.TagDevice(fmt.Sprintf(`KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/")))
return nil
}
func (iface *iioInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool {
// Allow what is allowed in the declarations
return true
}
func init() {
registerIface(&iioInterface{})
}
|