github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/uio.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019 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 "regexp" 25 "strings" 26 27 "github.com/snapcore/snapd/interfaces" 28 "github.com/snapcore/snapd/interfaces/apparmor" 29 "github.com/snapcore/snapd/interfaces/udev" 30 "github.com/snapcore/snapd/snap" 31 ) 32 33 // https://www.kernel.org/doc/html/latest/driver-api/uio-howto.html 34 const uioSummary = `allows access to specific uio device` 35 36 const uioBaseDeclarationSlots = ` 37 uio: 38 allow-installation: 39 slot-snap-type: 40 - core 41 - gadget 42 deny-auto-connection: true 43 ` 44 45 type uioInterface struct{} 46 47 func (iface *uioInterface) Name() string { 48 return "uio" 49 } 50 51 func (iface *uioInterface) StaticInfo() interfaces.StaticInfo { 52 return interfaces.StaticInfo{ 53 Summary: uioSummary, 54 BaseDeclarationSlots: uioBaseDeclarationSlots, 55 } 56 } 57 58 var uioPattern = regexp.MustCompile(`^/dev/uio[0-9]+$`) 59 60 const invalidUioDeviceNodeSlotPathErrFmt = "slot %q path attribute must be a valid UIO device node" 61 62 func (iface *uioInterface) path(slotRef *interfaces.SlotRef, attrs interfaces.Attrer) (string, error) { 63 return verifySlotPathAttribute(slotRef, attrs, uioPattern, invalidUioDeviceNodeSlotPathErrFmt) 64 } 65 66 func (iface *uioInterface) BeforePrepareSlot(slot *snap.SlotInfo) error { 67 _, err := verifySlotPathAttribute(&interfaces.SlotRef{Snap: slot.Snap.InstanceName(), Name: slot.Name}, slot, uioPattern, invalidUioDeviceNodeSlotPathErrFmt) 68 return err 69 } 70 71 func (iface *uioInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 72 path, err := iface.path(slot.Ref(), slot) 73 if err != nil { 74 return nil 75 } 76 spec.AddSnippet(fmt.Sprintf("%s rw,", path)) 77 // Assuming sysfs_base is /sys/class/uio/uio[0-9]+ where the leaf directory 78 // name matches /dev/uio[0-9]+ device name, the following files exists or 79 // may exist: 80 // - $sysfs_base/{name,version,event} 81 // - $sysfs_base/maps/map[0-9]+/{addr,name,offset,size} 82 // - $sysfs_base/portio/port[0-9]+/{name,start,size,porttype} 83 // The expression below matches them all as they all may be required for 84 // userspace drivers to operate. 85 // 86 // While it is more accurate to use: 87 // 88 // "/sys/devices/platform/**/uio/%s/** r,", strings.TrimPrefix(path, "/dev/") 89 // 90 // multiple interface connections will result in overlapping deep 91 // globs of the form: 92 // 93 // /sys/devices/platform/**/uio/uio1/** r, 94 // /sys/devices/platform/**/uio/uio2/** r, 95 // /sys/devices/platform/**/uio/uioN/** r, 96 // 97 // which are computationally difficult to de-duplicate provided 98 // large enough N. Instead, grant read only access to all uio 99 // sysfs files and control writable access to the specific 100 // device node in /dev. Use AddDeduplicatedSnippet() for clarity 101 // in the resulting rules. 102 spec.AddDeduplicatedSnippet("/sys/devices/platform/**/uio/uio[0-9]** r, # common rule for all uio connections") 103 return nil 104 } 105 106 func (iface *uioInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 107 path, err := iface.path(slot.Ref(), slot) 108 if err != nil { 109 return nil 110 } 111 spec.TagDevice(fmt.Sprintf(`SUBSYSTEM=="uio", KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/"))) 112 return nil 113 } 114 115 func (iface *uioInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 116 // Allow what is allowed in the declarations 117 return true 118 } 119 120 func init() { 121 registerIface(&uioInterface{}) 122 }