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