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  }