github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/interfaces/builtin/fwupd.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 "path/filepath" 24 "strings" 25 26 "github.com/snapcore/snapd/dirs" 27 "github.com/snapcore/snapd/interfaces" 28 "github.com/snapcore/snapd/interfaces/apparmor" 29 "github.com/snapcore/snapd/interfaces/dbus" 30 "github.com/snapcore/snapd/interfaces/mount" 31 "github.com/snapcore/snapd/interfaces/seccomp" 32 "github.com/snapcore/snapd/osutil" 33 "github.com/snapcore/snapd/snap" 34 ) 35 36 const fwupdSummary = `allows operating as the fwupd service` 37 38 const fwupdBaseDeclarationSlots = ` 39 fwupd: 40 allow-installation: 41 slot-snap-type: 42 - app 43 - core 44 deny-connection: true 45 deny-auto-connection: true 46 ` 47 48 const fwupdPermanentSlotAppArmor = ` 49 # Description: Allow operating as the fwupd service. This gives privileged 50 # access to the system. 51 52 # Allow read/write access for old efivars sysfs interface 53 capability sys_admin, 54 # Allow libfwup to access efivarfs with immutable flag 55 capability linux_immutable, 56 57 # For udev 58 network netlink raw, 59 60 # File accesses 61 # Allow access for EFI System Resource Table in the UEFI 2.5+ specification 62 /sys/firmware/efi/esrt/entries/ r, 63 /sys/firmware/efi/esrt/entries/** r, 64 65 # Allow fwupd to access system information 66 /sys/devices/virtual/dmi/id/product_name r, 67 /sys/devices/virtual/dmi/id/sys_vendor r, 68 69 # Allow read/write access for efivarfs filesystem 70 /sys/firmware/efi/efivars/ r, 71 /sys/firmware/efi/efivars/** rw, 72 73 # Allow write access for efi firmware updater 74 /boot/efi/{,**/} r, 75 # allow access to fwupd* and fw/ under boot/ for core systems 76 /boot/efi/EFI/boot/fwupd*.efi* rw, 77 /boot/efi/EFI/boot/fw/** rw, 78 # allow access to fwupd* and fw/ under ubuntu/ for classic systems 79 /boot/efi/EFI/ubuntu/fwupd*.efi* rw, 80 /boot/efi/EFI/ubuntu/fw/** rw, 81 82 # Allow access from efivar library 83 owner @{PROC}/@{pid}/mounts r, 84 /sys/devices/{pci*,platform}/**/block/**/partition r, 85 # Introspect the block devices to get partition guid and size information 86 /run/udev/data/b[0-9]*:[0-9]* r, 87 88 # Allow access UEFI firmware platform size 89 /sys/firmware/efi/ r, 90 /sys/firmware/efi/fw_platform_size r, 91 92 # DBus accesses 93 #include <abstractions/dbus-strict> 94 dbus (send) 95 bus=system 96 path=/org/freedesktop/DBus 97 interface=org.freedesktop.DBus 98 member={Request,Release}Name 99 peer=(name=org.freedesktop.DBus), 100 101 dbus (send) 102 bus=system 103 path=/org/freedesktop/DBus 104 interface=org.freedesktop.DBus 105 member=GetConnectionUnixUser 106 peer=(label=unconfined), 107 108 # Allow binding the service to the requested connection name 109 dbus (bind) 110 bus=system 111 name="org.freedesktop.fwupd", 112 ` 113 114 const fwupdConnectedPlugAppArmor = ` 115 # Description: Allow using fwupd service. This gives # privileged access to the 116 # fwupd service. 117 118 #Can access the network 119 #include <abstractions/nameservice> 120 #include <abstractions/ssl_certs> 121 /run/systemd/resolve/stub-resolv.conf r, 122 123 # DBus accesses 124 #include <abstractions/dbus-strict> 125 126 # systemd-resolved (not yet included in nameservice abstraction) 127 # 128 # Allow access to the safe members of the systemd-resolved D-Bus API: 129 # 130 # https://www.freedesktop.org/wiki/Software/systemd/resolved/ 131 # 132 # This API may be used directly over the D-Bus system bus or it may be used 133 # indirectly via the nss-resolve plugin: 134 # 135 # https://www.freedesktop.org/software/systemd/man/nss-resolve.html 136 # 137 dbus send 138 bus=system 139 path="/org/freedesktop/resolve1" 140 interface="org.freedesktop.resolve1.Manager" 141 member="Resolve{Address,Hostname,Record,Service}" 142 peer=(name="org.freedesktop.resolve1"), 143 144 # Allow access to fwupd service 145 dbus (receive, send) 146 bus=system 147 path=/ 148 interface=org.freedesktop.fwupd 149 peer=(label=###SLOT_SECURITY_TAGS###), 150 151 dbus (receive, send) 152 bus=system 153 path=/ 154 interface=org.freedesktop.DBus.Properties 155 peer=(label=###SLOT_SECURITY_TAGS###), 156 157 # Allow clients to introspect the service on non-classic (due to the path, 158 # allowing on classic would reveal too much for unconfined) 159 dbus (send) 160 bus=system 161 path=/ 162 interface=org.freedesktop.DBus.Introspectable 163 member=Introspect 164 peer=(label=###SLOT_SECURITY_TAGS###), 165 ` 166 167 const fwupdConnectedSlotAppArmor = ` 168 # Description: Allow firmware update using fwupd service. This gives privileged 169 # access to the fwupd service. 170 171 # Allow traffic to/from org.freedesktop.DBus for fwupd service 172 dbus (receive, send) 173 bus=system 174 path=/ 175 interface=org.freedesktop.DBus.** 176 peer=(label=###PLUG_SECURITY_TAGS###), 177 178 dbus (receive, send) 179 bus=system 180 path=/org/freedesktop/fwupd{,/**} 181 interface=org.freedesktop.DBus.** 182 peer=(label=###PLUG_SECURITY_TAGS###), 183 184 # Allow traffic to/from fwupd interface with any method 185 dbus (receive, send) 186 bus=system 187 path=/ 188 interface=org.freedesktop.fwupd 189 peer=(label=###PLUG_SECURITY_TAGS###), 190 191 dbus (receive, send) 192 bus=system 193 path=/org/freedesktop/fwupd{,/**} 194 interface=org.freedesktop.fwupd 195 peer=(label=###PLUG_SECURITY_TAGS###), 196 ` 197 198 const fwupdPermanentSlotDBus = ` 199 <policy user="root"> 200 <allow own="org.freedesktop.fwupd"/> 201 <allow send_destination="org.freedesktop.fwupd" send_interface="org.freedesktop.fwupd"/> 202 <allow send_destination="org.freedesktop.fwupd" send_interface="org.freedesktop.DBus.Properties"/> 203 <allow send_destination="org.freedesktop.fwupd" send_interface="org.freedesktop.DBus.Introspectable"/> 204 <allow send_destination="org.freedesktop.fwupd" send_interface="org.freedesktop.DBus.Peer"/> 205 </policy> 206 <policy context="default"> 207 <deny own="org.freedesktop.fwupd"/> 208 <deny send_destination="org.freedesktop.fwupd" send_interface="org.freedesktop.fwupd"/> 209 </policy> 210 ` 211 212 const fwupdPermanentSlotSecComp = ` 213 # Description: Allow operating as the fwupd service. This gives privileged 214 # access to the system. 215 # Can communicate with DBus system service 216 bind 217 # for udev 218 socket AF_NETLINK - NETLINK_KOBJECT_UEVENT 219 ` 220 const fwupdConnectedPlugSecComp = ` 221 # Description: Allow using fwupd service. Reserved because this gives 222 # privileged access to the fwupd service. 223 bind 224 ` 225 226 // fwupdInterface type 227 type fwupdInterface struct{} 228 229 // Name of the fwupdInterface 230 func (iface *fwupdInterface) Name() string { 231 return "fwupd" 232 } 233 234 func (iface *fwupdInterface) StaticInfo() interfaces.StaticInfo { 235 return interfaces.StaticInfo{ 236 Summary: fwupdSummary, 237 ImplicitOnClassic: true, 238 BaseDeclarationSlots: fwupdBaseDeclarationSlots, 239 } 240 } 241 242 func (iface *fwupdInterface) DBusPermanentSlot(spec *dbus.Specification, slot *snap.SlotInfo) error { 243 if !implicitSystemPermanentSlot(slot) { 244 spec.AddSnippet(fwupdPermanentSlotDBus) 245 } 246 return nil 247 } 248 249 func (iface *fwupdInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 250 old := "###SLOT_SECURITY_TAGS###" 251 var new string 252 if implicitSystemConnectedSlot(slot) { 253 new = "unconfined" 254 } else { 255 new = slotAppLabelExpr(slot) 256 } 257 snippet := strings.Replace(fwupdConnectedPlugAppArmor, old, new, -1) 258 spec.AddSnippet(snippet) 259 return nil 260 } 261 262 func (iface *fwupdInterface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error { 263 // Only apply slot snippet when running as application snap on 264 // classic, slot side can be system or application 265 if !implicitSystemPermanentSlot(slot) { 266 spec.AddSnippet(fwupdPermanentSlotAppArmor) 267 268 // Allow mounting boot partition to snap-update-ns 269 emit := spec.AddUpdateNSf 270 target := "/boot" 271 source := "/var/lib/snapd/hostfs" + target 272 emit(" # Read-write access to %s\n", target) 273 emit(" mount options=(rbind) %s/ -> %s/,\n", source, target) 274 emit(" umount %s/,\n\n", target) 275 } 276 return nil 277 } 278 279 func (iface *fwupdInterface) MountPermanentSlot(spec *mount.Specification, slot *snap.SlotInfo) error { 280 if !implicitSystemPermanentSlot(slot) { 281 dir := filepath.Join(dirs.GlobalRootDir, "/boot") 282 if osutil.IsDirectory(dir) { 283 spec.AddMountEntry(osutil.MountEntry{ 284 Name: "/var/lib/snapd/hostfs" + dir, 285 Dir: dirs.StripRootDir(dir), 286 Options: []string{"rbind", "rw"}, 287 }) 288 } 289 } 290 return nil 291 } 292 293 func (iface *fwupdInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 294 if !implicitSystemConnectedSlot(slot) { 295 old := "###PLUG_SECURITY_TAGS###" 296 new := plugAppLabelExpr(plug) 297 snippet := strings.Replace(fwupdConnectedSlotAppArmor, old, new, -1) 298 spec.AddSnippet(snippet) 299 } 300 return nil 301 } 302 303 func (iface *fwupdInterface) SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error { 304 spec.AddSnippet(fwupdConnectedPlugSecComp) 305 return nil 306 } 307 308 func (iface *fwupdInterface) SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error { 309 if !implicitSystemPermanentSlot(slot) { 310 spec.AddSnippet(fwupdPermanentSlotSecComp) 311 } 312 return nil 313 } 314 315 func (iface *fwupdInterface) AutoConnect(*snap.PlugInfo, *snap.SlotInfo) bool { 316 // allow what declarations allowed 317 return true 318 } 319 320 func init() { 321 registerIface(&fwupdInterface{}) 322 }