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