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