DevelopingFrameworkPolicy

This page only applies to Ubuntu Core 15.04. For series 16, see https://github.com/snapcore/snapd/wiki/Security

Security policy for framework services and binaries

See https://developer.ubuntu.com/en/snappy/guides/security-policy/ for information on security policy in snaps.

package.yaml

Framework services and binaries often need additional privileges if they are going to be of use to other snaps. These services and binaries will typically use security-policy in their yaml to specify the files that contain the raw security policy.

For example,

name: foo
version: 0.1
vendor: "Some Person <some.person@example.com>"
type: framework
...
services:
  - name: bar
    start: bin/bar
    bus-name: com.example.foo
    security-policy:
      apparmor: meta/bar.apparmor
      seccomp: meta/bar.seccomp

'bus-name' gives the DBus connection name for the bar service while 'apparmor' and 'seccomp' specify the hand-crafted apparmor and seccomp policy files, respectively.

AppArmor

Snappy provides several AppArmor variables that make maintenance easier and best practice dictates that handcrafted policy start with boilerplate policy. A portion of the AppArmor boilerplate is excerpted here:

#
# AppArmor confinement for foo_bar
#

#include <tunables/global>

# Specified profile variables
###VAR###

###PROFILEATTACH### (attach_disconnected) {
  #include <abstractions/base>
  #include <abstractions/openssl>

  ...

  #
  # DBus rules: only needed for DBus services (ie, when specifying 'bus-name'
  # in the yaml)
  #

  #include <abstractions/dbus-strict>
  # Allow requesting a connection name and also releasing it
  dbus (send)
     bus=system
     path=/org/freedesktop/DBus
     interface=org.freedesktop.DBus
     member={Request,Release}Name
     peer=(name=org.freedesktop.DBus),

  # Allow binding the service to the requested connection name. Adjust
  # accordingly based on 'bus-name' from yaml
  dbus (bind)
    bus=system
    name="com.example.foo",

  # Allow receiving traffic to our path and interface with any method. Adjust
  # accordingly based on 'bus-name' from yaml
  dbus (receive)
    bus=system
    path=/com/example/foo/**
    interface=com.example.foo.*,

  #
  # end DBus rules
  #

  # Read-only for the install directory
  @{CLICK_DIR}/@{APP_PKGNAME}/                   r,
  @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/    r,
  @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/**  mrklix,

  # Read-only home area for other versions
  owner @{HOMEDIRS}/*/apps/@{APP_PKGNAME}/                  r,
  owner @{HOMEDIRS}/*/apps/@{APP_PKGNAME}/@{APP_VERSION}/   r,
  owner @{HOMEDIRS}/*/apps/@{APP_PKGNAME}/@{APP_VERSION}/** mrkix,

  # Writable home area for this version.
  owner @{HOMEDIRS}/*/apps/@{APP_PKGNAME}/@{APP_VERSION}/   w,
  owner @{HOMEDIRS}/*/apps/@{APP_PKGNAME}/@{APP_VERSION}/** wl,

  # Read-only system area for other versions
  /var/lib/apps/@{APP_PKGNAME}/   r,
  /var/lib/apps/@{APP_PKGNAME}/** mrkix,

  # Writable system area only for this version
  /var/lib/apps/@{APP_PKGNAME}/@{APP_VERSION}/   w,
  /var/lib/apps/@{APP_PKGNAME}/@{APP_VERSION}/** wl,

  # The ubuntu-core-launcher creates an app-specific private restricted /tmp
  # and will fail to launch the app if something goes wrong. As such, we can
  # simply allow full access to /tmp.
  /tmp/   r,
  /tmp/** mrwlkix,

  # Miscellaneous accesses
  ...

  #
  # Framework service/binary specific rules below here
  #
}

Notice the following to ease maintenance:

  • ###VAR###: this is expanded on framework install to framework-specific AppArmor variables

  • ###PROFILEATTACH###: this is expanded on framework install to framework-specific value to match the APP_ID

  • @{CLICK_DIR}: this is set for snappy-specfic directories

  • @{APP_PKGNAME}: this is set to the top-level name from the package.yaml. Eg, 'foo'

  • @{APP_VERSION}: this is set to the version from the package.yaml. Eg, '0.1'

  • @{APP_APPNAME} (not shown in the above boilerplate): this is set to the name of the service/binary. Eg 'bar'

With the above example yaml, save the above as 'meta/bar.apparmor' and adjust as needed.

Seccomp

Seccomp is much simpler than AppArmor when expressing policy-- it is a simple list of allowed syscalls. Easiest is to start with the seccomp portion of the boilerplate policy.

If you want to start with an existing template, you can simply do:

$ sed 's/^deny/# EXPLICITLY DENY/' /usr/share/seccomp/templates/ubuntu-core/15.04/default > meta/bar.seccomp

and adjust as needed.

Development tips

When fine-tuning AppArmor policy, it is often easiest to install the snap then modify the AppArmor policy in place on the target system, then copying it back. Eg, these steps might be:

  1. snappy build .
  2. copy ./foo_0.1.snap to your target device

  3. login to target device and install the snap
  4. test, monitoring /var/log/syslog for denials
    • 15.04, modify profile in /var/lib/apparmor/profiles/..., then do: sudo apparmor_parser -r /var/lib/apparmor/profiles/...

    • 16.04, modify profile in /var/lib/snappy/apparmor/profiles/..., then do: sudo apparmor_parser -r /var/lib/snappy/apparmor/profiles/...

  5. 'sudo systemctl stop <unit>', 'sudo systemctl start <unit>', etc

  6. repeat until satisfied
  7. finally, copy any changes you to /var/lib/snappy/apparmor/profiles (/var/lib/apparmor/profiles/... on 15.04) on your target machine to your packaging directory (eg, meta/bar.apparmor). If you simply copy the file over, be sure to put ###VAR### and ###PROFILEATTACH### back into your packaging file.

The same is true for seccomp-- the profile is located in /var/lib/snappy/seccomp/profiles/.... Unlike AppArmor, you do not have to load the policy in a separate step (this is handled by the launcher); just modify the file in place and retest

In addition to the above, here are two useful techniques when debugging/developing policy:

  1. specify @unrestricted in the seccomp policy and this will allow all syscalls

  2. replace your restrictive AppArmor policy with the framework-template unconfined policy (which is the same as the policy in the unconfined 'security-template').

Also see:

framework-policy for apps to use the framework

See https://developer.ubuntu.com/en/snappy/guides/frameworks/ for high-level information on frameworks and framework-policy. Often a framework need not ship any framework-policy templates and instead only ship a framework-policy cap or two for apps to be able to use with this framework. Eg, with the above yaml and AppArmor policy for the DBus service bar, then meta/framework-policy/apparmor/policygroups/client might contain:

# Description: allow using foo_bar DBus service
# Usage: common

#include <abstractions/dbus-strict>
dbus (send)
  bus=system
  path=/com/example/foo/**
  interface=com.example.foo.*
  member=Method
  peer=(label=foo_bar_*),

and meta/framework-policy/seccomp/policygroups/client might contain:

# Description: allow using foo_bar DBus service
# Usage: common

# for connecting to DBus
connect
getsockname
recvmsg
send
sendto
sendmsg
socket

Conveniently, other framework services may specify framework-policy in security policy. So if the foo framework is adjusted to ship the 'baz' binary, and 'baz' needs to use the 'client' cap from foo's framework-policy, then the package.yaml might be updated to contain:

name: foo
version: 0.1
vendor: "Some Person <some.person@example.com>"
type: framework
...
services:
  - name: bar
    start: bin/bar
    bus-name: com.example.foo
    security-policy:
      apparmor: meta/bar.apparmor
      seccomp: meta/bar.seccomp
binaries:
  - name: baz
    exec: bin/baz
    caps:
      - foo_client

Also notice the 'Usage: common' metadata in the framework policy. You may specify either common or restricted. common means that the framework functionality exposed via this policy is considered safe for any app to use. restricted means that apps are not generally allowed to specify this policy group in their caps or security-template and if they do, then the app will need to be manually reviewed when uploaded to the store. restricted framework-policy might be useful for the framework's own services/binaries.

SecurityTeam/Specifications/SnappyConfinement/DevelopingFrameworkPolicy (last edited 2016-11-17 16:30:14 by jdstrand)