github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/bluez.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 "strings" 24 25 "github.com/snapcore/snapd/interfaces" 26 "github.com/snapcore/snapd/interfaces/apparmor" 27 "github.com/snapcore/snapd/interfaces/dbus" 28 "github.com/snapcore/snapd/interfaces/seccomp" 29 "github.com/snapcore/snapd/interfaces/udev" 30 "github.com/snapcore/snapd/release" 31 "github.com/snapcore/snapd/snap" 32 ) 33 34 const bluezSummary = `allows operating as the bluez service` 35 36 const bluezBaseDeclarationSlots = ` 37 bluez: 38 allow-installation: 39 slot-snap-type: 40 - app 41 - core 42 deny-auto-connection: true 43 deny-connection: 44 on-classic: false 45 ` 46 47 const bluezPermanentSlotAppArmor = ` 48 # Description: Allow operating as the bluez service. This gives privileged 49 # access to the system. 50 51 network bluetooth, 52 53 capability net_admin, 54 capability net_bind_service, 55 56 # libudev 57 network netlink raw, 58 59 # File accesses 60 /sys/bus/usb/drivers/btusb/ r, 61 /sys/bus/usb/drivers/btusb/** r, 62 /sys/class/bluetooth/ r, 63 /sys/devices/**/bluetooth/ rw, 64 /sys/devices/**/bluetooth/** rw, 65 /sys/devices/**/id/chassis_type r, 66 67 # TODO: use snappy hardware assignment for this once LP: #1498917 is fixed 68 /dev/rfkill rw, 69 70 # DBus accesses 71 #include <abstractions/dbus-strict> 72 dbus (send) 73 bus=system 74 path=/org/freedesktop/DBus 75 interface=org.freedesktop.DBus 76 member={Request,Release}Name 77 peer=(name=org.freedesktop.DBus, label=unconfined), 78 79 dbus (send) 80 bus=system 81 path=/org/freedesktop/* 82 interface=org.freedesktop.DBus.Properties 83 peer=(label=unconfined), 84 85 # Allow binding the service to the requested connection name 86 dbus (bind) 87 bus=system 88 name="org.bluez", 89 90 # Allow binding the service to the requested connection name 91 dbus (bind) 92 bus=system 93 name="org.bluez.obex", 94 95 # Allow binding the service to the requested connection name 96 dbus (bind) 97 bus=system 98 name="org.bluez.mesh", 99 100 # Allow traffic to/from our interface with any method for unconfined clients 101 # to talk to our bluez services. For the org.bluez interface we don't specify 102 # an Object Path since according to the bluez specification these can be 103 # anything (https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc). 104 dbus (receive, send) 105 bus=system 106 interface=org.bluez.* 107 peer=(label=unconfined), 108 dbus (receive, send) 109 bus=system 110 path=/org/bluez{,/**} 111 interface=org.freedesktop.DBus.* 112 peer=(label=unconfined), 113 114 # Allow traffic to/from org.freedesktop.DBus for bluez service. This rule is 115 # not snap-specific and grants privileged access to the org.freedesktop.DBus 116 # on the system bus. 117 dbus (receive, send) 118 bus=system 119 path=/ 120 interface=org.freedesktop.DBus.* 121 peer=(label=unconfined), 122 123 # Allow access to hostname system service 124 dbus (receive, send) 125 bus=system 126 path=/org/freedesktop/hostname1 127 interface=org.freedesktop.DBus.Properties 128 peer=(label=unconfined), 129 130 # do not use peer=(label=unconfined) here since this is DBus activated 131 dbus (send) 132 bus=system 133 path=/org/freedesktop/hostname1 134 interface=org.freedesktop.DBus.Properties 135 member="Get{,All}", 136 dbus (send) 137 bus=system 138 path=/org/freedesktop/hostname1 139 interface=org.freedesktop.DBus.Introspectable 140 member=Introspect, 141 ` 142 143 const bluezConnectedSlotAppArmor = ` 144 # Allow connected clients to interact with the service 145 146 # Allow all access to bluez service 147 dbus (receive, send) 148 bus=system 149 peer=(label=###PLUG_SECURITY_TAGS###), 150 ` 151 152 const bluezConnectedPlugAppArmor = ` 153 # Description: Allow using bluez service. This gives privileged access to the 154 # bluez service. 155 156 #include <abstractions/dbus-strict> 157 158 # Allow all access to bluez service 159 dbus (receive, send) 160 bus=system 161 peer=(label=###SLOT_SECURITY_TAGS###), 162 163 dbus (send) 164 bus=system 165 peer=(name=org.bluez, label=unconfined), 166 167 dbus (send) 168 bus=system 169 peer=(name=org.bluez.obex, label=unconfined), 170 171 dbus (send) 172 bus=system 173 peer=(name=org.bluez.mesh, label=unconfined), 174 175 dbus (receive) 176 bus=system 177 path=/ 178 interface=org.freedesktop.DBus.ObjectManager 179 peer=(label=unconfined), 180 181 dbus (receive) 182 bus=system 183 path=/org/bluez{,/**} 184 interface=org.freedesktop.DBus.* 185 peer=(label=unconfined), 186 187 # Allow access to bluetooth audio streams 188 network bluetooth, 189 ` 190 191 const bluezPermanentSlotSecComp = ` 192 # Description: Allow operating as the bluez service. This gives privileged 193 # access to the system. 194 accept 195 accept4 196 bind 197 listen 198 # libudev 199 socket AF_NETLINK - NETLINK_KOBJECT_UEVENT 200 ` 201 202 const bluezPermanentSlotDBus = ` 203 <policy user="root"> 204 <allow own="org.bluez"/> 205 <allow own="org.bluez.obex"/> 206 <allow own="org.bluez.mesh"/> 207 <allow send_destination="org.bluez"/> 208 <allow send_destination="org.bluez.obex"/> 209 <allow send_destination="org.bluez.mesh"/> 210 <allow send_interface="org.bluez.Agent1"/> 211 <allow send_interface="org.bluez.MediaEndpoint1"/> 212 <allow send_interface="org.bluez.MediaPlayer1"/> 213 <allow send_interface="org.bluez.ThermometerWatcher1"/> 214 <allow send_interface="org.bluez.AlertAgent1"/> 215 <allow send_interface="org.bluez.Profile1"/> 216 <allow send_interface="org.bluez.HeartRateWatcher1"/> 217 <allow send_interface="org.bluez.CyclingSpeedWatcher1"/> 218 <allow send_interface="org.bluez.GattCharacteristic1"/> 219 <allow send_interface="org.bluez.GattDescriptor1"/> 220 <allow send_interface="org.bluez.mesh.Element1"/> 221 <allow send_interface="org.bluez.mesh.Application1"/> 222 <allow send_interface="org.bluez.mesh.ProvisionAgent1"/> 223 <allow send_interface="org.bluez.mesh.Provisioner1"/> 224 <allow send_interface="org.bluez.mesh.Attention1"/> 225 <allow send_interface="org.bluez.mesh.Network1"/> 226 <allow send_interface="org.bluez.mesh.Node1"/> 227 <allow send_interface="org.bluez.mesh.Management1"/> 228 <allow send_interface="org.freedesktop.DBus.ObjectManager"/> 229 <allow send_interface="org.freedesktop.DBus.Properties"/> 230 </policy> 231 <policy context="default"> 232 <deny send_destination="org.bluez"/> 233 </policy> 234 ` 235 236 type bluezInterface struct{} 237 238 func (iface *bluezInterface) Name() string { 239 return "bluez" 240 } 241 242 func (iface *bluezInterface) StaticInfo() interfaces.StaticInfo { 243 return interfaces.StaticInfo{ 244 Summary: bluezSummary, 245 ImplicitOnClassic: true, 246 BaseDeclarationSlots: bluezBaseDeclarationSlots, 247 } 248 } 249 250 func (iface *bluezInterface) DBusPermanentSlot(spec *dbus.Specification, slot *snap.SlotInfo) error { 251 if !release.OnClassic { 252 spec.AddSnippet(bluezPermanentSlotDBus) 253 } 254 return nil 255 } 256 257 func (iface *bluezInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 258 old := "###SLOT_SECURITY_TAGS###" 259 var new string 260 if release.OnClassic { 261 new = "unconfined" 262 } else { 263 new = slotAppLabelExpr(slot) 264 } 265 snippet := strings.Replace(bluezConnectedPlugAppArmor, old, new, -1) 266 spec.AddSnippet(snippet) 267 return nil 268 } 269 270 func (iface *bluezInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 271 if !release.OnClassic { 272 old := "###PLUG_SECURITY_TAGS###" 273 new := plugAppLabelExpr(plug) 274 snippet := strings.Replace(bluezConnectedSlotAppArmor, old, new, -1) 275 spec.AddSnippet(snippet) 276 } 277 return nil 278 } 279 280 func (iface *bluezInterface) UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 281 spec.TagDevice(`KERNEL=="rfkill"`) 282 return nil 283 } 284 285 func (iface *bluezInterface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error { 286 if !release.OnClassic { 287 spec.AddSnippet(bluezPermanentSlotAppArmor) 288 } 289 return nil 290 } 291 292 func (iface *bluezInterface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error { 293 if !release.OnClassic { 294 spec.AddSnippet(bluezPermanentSlotSecComp) 295 } 296 return nil 297 } 298 299 func (iface *bluezInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 300 // allow what declarations allowed 301 return true 302 } 303 304 func init() { 305 registerIface(&bluezInterface{}) 306 }