gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/system_observe.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 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  
    25  	"gitee.com/mysnapcore/mysnapd/dirs"
    26  	"gitee.com/mysnapcore/mysnapd/interfaces"
    27  	"gitee.com/mysnapcore/mysnapd/interfaces/apparmor"
    28  	"gitee.com/mysnapcore/mysnapd/interfaces/mount"
    29  	"gitee.com/mysnapcore/mysnapd/logger"
    30  	"gitee.com/mysnapcore/mysnapd/osutil"
    31  	"gitee.com/mysnapcore/mysnapd/snap"
    32  )
    33  
    34  const systemObserveSummary = `allows observing all processes and drivers`
    35  
    36  const systemObserveBaseDeclarationSlots = `
    37    system-observe:
    38      allow-installation:
    39        slot-snap-type:
    40          - core
    41      deny-auto-connection: true
    42  `
    43  
    44  const systemObserveConnectedPlugAppArmor = `
    45  # Description: Can query system status information. This is restricted because
    46  # it gives privileged read access to all processes on the system and should
    47  # only be used with trusted apps.
    48  
    49  # Needed by 'ps'
    50  @{PROC}/tty/drivers r,
    51  
    52  # This ptrace is an information leak. Intentionlly omit 'ptrace (trace)' here
    53  # since since ps doesn't actually need to trace other processes. Note this
    54  # allows a number of accesses (assuming the associated /proc file is allowed),
    55  # such as various memory address locations and esp/eip via /proc/*/stat,
    56  # /proc/*/mem, /proc/*/personality, /proc/*/stack, /proc/*/syscall,
    57  # /proc/*/timerslack_ns and /proc/*/wchan (see man proc).
    58  #
    59  # Some files like /proc/kallsyms (but anything using %pK format specifier) need
    60  # 'capability syslog' when /proc/sys/kernel/kptr_restrict=1, but we
    61  # intentionally do not allow since it could be used to defeat KASLR.
    62  ptrace (read),
    63  
    64  # Other miscellaneous accesses for observing the system
    65  @{PROC}/cgroups r,
    66  @{PROC}/locks r,
    67  @{PROC}/modules r,
    68  @{PROC}/stat r,
    69  @{PROC}/vmstat r,
    70  @{PROC}/zoneinfo r,
    71  @{PROC}/diskstats r,
    72  @{PROC}/kallsyms r,
    73  @{PROC}/partitions r,
    74  @{PROC}/pressure/cpu r,
    75  @{PROC}/pressure/io r,
    76  @{PROC}/pressure/memory r,
    77  @{PROC}/sys/kernel/panic r,
    78  @{PROC}/sys/kernel/panic_on_oops r,
    79  @{PROC}/sys/kernel/sched_autogroup_enabled r,
    80  @{PROC}/sys/vm/max_map_count r,
    81  @{PROC}/sys/vm/panic_on_oom r,
    82  @{PROC}/sys/vm/swappiness r,
    83  
    84  # These are not process-specific (/proc/*/... and /proc/*/task/*/...)
    85  @{PROC}/*/{,task/,task/*/} r,
    86  @{PROC}/*/{,task/*/}autogroup r,
    87  @{PROC}/*/{,task/*/}auxv r,
    88  @{PROC}/*/{,task/*/}cgroup r,
    89  @{PROC}/*/{,task/*/}cmdline r,
    90  @{PROC}/*/{,task/*/}comm r,
    91  @{PROC}/*/{,task/*/}exe r,
    92  @{PROC}/*/{,task/*/}fdinfo/* r,
    93  @{PROC}/*/{,task/*/}io r,
    94  @{PROC}/*/{,task/*/}oom_score r,
    95  # allow reading of smaps_rollup, which is a summary of the memory use of a process,
    96  # but not smaps which contains a detailed mappings breakdown like
    97  # /proc/self/maps, which we do not allow access to for other processes
    98  @{PROC}/*/{,task/*/}smaps_rollup r,
    99  @{PROC}/*/{,task/*/}stat r,
   100  @{PROC}/*/{,task/*/}statm r,
   101  @{PROC}/*/{,task/*/}status r,
   102  @{PROC}/*/{,task/*/}wchan r,
   103  
   104  # Allow reading processes security label
   105  @{PROC}/*/{,task/*/}attr/{,apparmor/}current r,
   106  
   107  # Allow discovering the os-release of the host
   108  /var/lib/snapd/hostfs/etc/os-release rk,
   109  /var/lib/snapd/hostfs/usr/lib/os-release rk,
   110  
   111  # Allow discovering the Kernel build config
   112  @{PROC}/config.gz r,
   113  /boot/config* r,
   114  
   115  # Allow discovering system-wide CFS Bandwidth Control information
   116  # https://www.kernel.org/doc/html/latest/scheduler/sched-bwc.html
   117  /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us r,
   118  /sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us r,
   119  /sys/fs/cgroup/cpu,cpuacct/cpu.shares r,
   120  /sys/fs/cgroup/cpu,cpuacct/cpu.stat r,
   121  /sys/fs/cgroup/memory/memory.stat r,
   122  
   123  #include <abstractions/dbus-strict>
   124  
   125  # do not use peer=(label=unconfined) here since this is DBus activated
   126  dbus (send)
   127      bus=system
   128      path=/org/freedesktop/hostname1
   129      interface=org.freedesktop.DBus.Properties
   130      member=Get{,All},
   131  
   132  # Allow clients to introspect hostname1
   133  # do not use peer=(label=unconfined) here since this is DBus activated
   134  dbus (send)
   135      bus=system
   136      path=/org/freedesktop/hostname1
   137      interface=org.freedesktop.DBus.Introspectable
   138      member=Introspect,
   139  
   140  # Allow clients to enumerate DBus connection names on common buses
   141  dbus (send)
   142      bus={session,system}
   143      path=/org/freedesktop/DBus
   144      interface=org.freedesktop.DBus
   145      member={ListNames,ListActivatableNames}
   146      peer=(label=unconfined),
   147  
   148  # Allow clients to obtain the DBus machine ID on common buses. We do not
   149  # mediate the path since any peer can be used.
   150  dbus (send)
   151      bus={session,system}
   152      interface=org.freedesktop.DBus.Peer
   153      member=GetMachineId
   154      peer=(label=unconfined),
   155  
   156  # Allow reading if protected hardlinks are enabled, but don't allow enabling or
   157  # disabling them
   158  @{PROC}/sys/fs/protected_hardlinks r,
   159  @{PROC}/sys/fs/protected_symlinks r,
   160  @{PROC}/sys/fs/protected_fifos r,
   161  @{PROC}/sys/fs/protected_regular r,
   162  `
   163  
   164  const systemObserveConnectedPlugSecComp = `
   165  # Description: Can query system status information. This is restricted because
   166  # it gives privileged read access to all processes on the system and should
   167  # only be used with trusted apps.
   168  
   169  # ptrace can be used to break out of the seccomp sandbox, but ps requests
   170  # 'ptrace (trace)' from apparmor. 'ps' does not need the ptrace syscall though,
   171  # so we deny the ptrace here to make sure we are always safe.
   172  # Note: may uncomment once ubuntu-core-launcher understands @deny rules and
   173  # if/when we conditionally deny this in the future.
   174  #@deny ptrace
   175  `
   176  
   177  type systemObserveInterface struct {
   178  	commonInterface
   179  }
   180  
   181  func (iface *systemObserveInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
   182  	spec.AddSnippet(systemObserveConnectedPlugAppArmor)
   183  	spec.SetSuppressPtraceTrace()
   184  	// Allow mounting boot partition to snap-update-ns
   185  	emit := spec.AddUpdateNSf
   186  	target := "/boot"
   187  	source := "/var/lib/snapd/hostfs" + target
   188  	emit("  # Read-only access to %s", target)
   189  	// When setting up a read-only bind mount, snap-update-ns first creates a
   190  	// plain read/write bind mount, and then remounts it to readonly.
   191  	emit("  mount options=(bind,rw) %s/ -> %s/,", source, target)
   192  	emit("  mount options=(bind,remount,ro) -> %s/,", target)
   193  	emit("  umount %s/,\n", target)
   194  	return nil
   195  }
   196  
   197  func (iface *systemObserveInterface) MountPermanentPlug(spec *mount.Specification, plug *snap.PlugInfo) error {
   198  	dir := filepath.Join(dirs.GlobalRootDir, "/boot")
   199  	if matches, _ := filepath.Glob(filepath.Join(dir, "config*")); len(matches) > 0 {
   200  		spec.AddMountEntry(osutil.MountEntry{
   201  			Name:    "/var/lib/snapd/hostfs" + dir,
   202  			Dir:     "/boot",
   203  			Options: []string{"bind", "ro"},
   204  		})
   205  	} else {
   206  		// TODO: if /boot/config does not exist, we should check whether the
   207  		// kernel is being delivered as a snap (this is the case in Ubuntu
   208  		// Core) and, if found, we should bind-mount the config file onto the
   209  		// expected location.
   210  		logger.Debugf("system-observe: /boot/config* not found, skipping mount of /boot/")
   211  	}
   212  	return nil
   213  }
   214  
   215  func init() {
   216  	registerIface(&systemObserveInterface{
   217  		commonInterface: commonInterface{
   218  			name:                 "system-observe",
   219  			summary:              systemObserveSummary,
   220  			implicitOnCore:       true,
   221  			implicitOnClassic:    true,
   222  			baseDeclarationSlots: systemObserveBaseDeclarationSlots,
   223  			connectedPlugSecComp: systemObserveConnectedPlugSecComp,
   224  		},
   225  	})
   226  }