github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/interfaces/builtin/hidraw.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 hidrawSummary = `allows access to specific hidraw device` 35 36 const hidrawBaseDeclarationSlots = ` 37 hidraw: 38 allow-installation: 39 slot-snap-type: 40 - core 41 - gadget 42 deny-auto-connection: true 43 ` 44 45 // hidrawInterface is the type for hidraw interfaces. 46 type hidrawInterface struct{} 47 48 // Name of the hidraw interface. 49 func (iface *hidrawInterface) Name() string { 50 return "hidraw" 51 } 52 53 func (iface *hidrawInterface) StaticInfo() interfaces.StaticInfo { 54 return interfaces.StaticInfo{ 55 Summary: hidrawSummary, 56 BaseDeclarationSlots: hidrawBaseDeclarationSlots, 57 } 58 } 59 60 func (iface *hidrawInterface) String() string { 61 return iface.Name() 62 } 63 64 // Pattern to match allowed hidraw device nodes, path attributes will be 65 // compared to this for validity when not using udev identification 66 var hidrawDeviceNodePattern = regexp.MustCompile("^/dev/hidraw[0-9]{1,3}$") 67 68 // Pattern that is considered valid for the udev symlink to the hidraw device, 69 // path attributes will be compared to this for validity when usb vid and pid 70 // are also specified 71 var hidrawUDevSymlinkPattern = regexp.MustCompile("^/dev/hidraw-[a-z0-9]+$") 72 73 // BeforePrepareSlot checks validity of the defined slot 74 func (iface *hidrawInterface) BeforePrepareSlot(slot *snap.SlotInfo) error { 75 // Check slot has a path attribute identify hidraw device 76 path, ok := slot.Attrs["path"].(string) 77 if !ok || path == "" { 78 return fmt.Errorf("hidraw slots must have a path attribute") 79 } 80 81 // XXX: this interface feeds the cleaned path into the regex and is 82 // left unchanged here for historical reasons. New interfaces (eg, 83 // like raw-volume) should instead use verifySlotPathAttribute() which 84 // performs additional verification. 85 path = filepath.Clean(path) 86 87 if iface.hasUsbAttrs(slot) { 88 // Must be path attribute where symlink will be placed and usb vendor and product identifiers 89 // Check the path attribute is in the allowable pattern 90 if !hidrawUDevSymlinkPattern.MatchString(path) { 91 return fmt.Errorf("hidraw path attribute specifies invalid symlink location") 92 } 93 94 usbVendor, vOk := slot.Attrs["usb-vendor"].(int64) 95 if !vOk { 96 return fmt.Errorf("hidraw slot failed to find usb-vendor attribute") 97 } 98 if (usbVendor < 0x1) || (usbVendor > 0xFFFF) { 99 return fmt.Errorf("hidraw usb-vendor attribute not valid: %d", usbVendor) 100 } 101 102 usbProduct, pOk := slot.Attrs["usb-product"].(int64) 103 if !pOk { 104 return fmt.Errorf("hidraw slot failed to find usb-product attribute") 105 } 106 if (usbProduct < 0x0) || (usbProduct > 0xFFFF) { 107 return fmt.Errorf("hidraw usb-product attribute not valid: %d", usbProduct) 108 } 109 } else { 110 // Just a path attribute - must be a valid usb device node 111 // Check the path attribute is in the allowable pattern 112 if !hidrawDeviceNodePattern.MatchString(path) { 113 return fmt.Errorf("hidraw path attribute must be a valid device node") 114 } 115 } 116 return nil 117 } 118 119 func (iface *hidrawInterface) UDevPermanentSlot(spec *udev.Specification, slot *snap.SlotInfo) error { 120 usbVendor, ok := slot.Attrs["usb-vendor"].(int64) 121 if !ok { 122 return nil 123 } 124 usbProduct, ok := slot.Attrs["usb-product"].(int64) 125 if !ok { 126 return nil 127 } 128 path, ok := slot.Attrs["path"].(string) 129 if !ok || path == "" { 130 return nil 131 } 132 spec.AddSnippet(fmt.Sprintf(`# hidraw 133 IMPORT{builtin}="usb_id" 134 SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="%04x", ATTRS{idProduct}=="%04x", SYMLINK+="%s"`, 135 usbVendor, usbProduct, strings.TrimPrefix(path, "/dev/"))) 136 return nil 137 } 138 139 func (iface *hidrawInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 140 if iface.hasUsbAttrs(slot) { 141 // This apparmor rule must match hidrawDeviceNodePattern 142 // UDev tagging and device cgroups will restrict down to the specific device 143 spec.AddSnippet("/dev/hidraw[0-9]{,[0-9],[0-9][0-9]} rw,") 144 return nil 145 } 146 147 // Path to fixed device node 148 var path string 149 if err := slot.Attr("path", &path); err != nil { 150 return err 151 } 152 cleanedPath := filepath.Clean(path) 153 spec.AddSnippet(fmt.Sprintf("%s rw,", cleanedPath)) 154 return nil 155 156 } 157 158 func (iface *hidrawInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 159 hasOnlyPath := true 160 if iface.hasUsbAttrs(slot) { 161 hasOnlyPath = false 162 } 163 164 var usbVendor int64 165 var usbProduct int64 166 var path string 167 168 err := slot.Attr("usb-vendor", &usbVendor) 169 if err != nil && !hasOnlyPath { 170 return nil 171 } 172 err = slot.Attr("usb-product", &usbProduct) 173 if err != nil && !hasOnlyPath { 174 return nil 175 } 176 177 err = slot.Attr("path", &path) 178 if err != nil && hasOnlyPath { 179 return nil 180 } 181 182 if hasOnlyPath { 183 spec.TagDevice(fmt.Sprintf(`SUBSYSTEM=="hidraw", KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/"))) 184 } else { 185 spec.TagDevice(fmt.Sprintf(`IMPORT{builtin}="usb_id" 186 SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="%04x", ATTRS{idProduct}=="%04x"`, usbVendor, usbProduct)) 187 } 188 return nil 189 } 190 191 func (iface *hidrawInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 192 // allow what declarations allowed 193 return true 194 } 195 196 func (iface *hidrawInterface) hasUsbAttrs(attrs interfaces.Attrer) bool { 197 var v int64 198 if err := attrs.Attr("usb-vendor", &v); err == nil { 199 return true 200 } 201 if err := attrs.Attr("usb-product", &v); err == nil { 202 return true 203 } 204 return false 205 } 206 207 func init() { 208 registerIface(&hidrawInterface{}) 209 }