Where eagles snap – A closer look

by Igor Ljubuncic on 31 January 2019

A couple of weeks ago, we talked about snap security, taking a journey through the eyes of a developer and handing over to a user who wants to install applications from the Snap Store. We discussed concepts like application confinement, interfaces, store review, and automatic updates. Today, we will look under the hood, and examine the underlying security mechanisms, and then talk some more about Ubuntu Core.

Ubuntu hardening mechanisms

Ubuntu uses several security hardening mechanisms, including: Discretionary Access Controls (DAC), Mandatory Access Control (MAC) via AppArmor, Seccomp kernel system call filtering (limits the system calls a process may use), cgroups device access controls for hardware assignment, and pseudoterminal (PTY) functionality for login sessions via a new devpts instance per command to prevent snooping and input injection via /dev/pts. Ubuntu also uses YAMA Linux Security Module in Canonical-supported kernels, and provides ptrace scoping, symlink restrictions and hardlink restrictions.

DHCP

The DHCP client runs under a restrictive AppArmor profile.

User logins

The administrative user (root) has a disabled password. All system users have disabled logins.

Remote connectivity

When installed on desktop and server, OpenSSH listens by default but it is configured with PermitRootLogin prohibit-password to disable root logins when a password is set. For Ubuntu on cloud, this is the default configuration.

Ubuntu Core Filesystem Hierarchy Standard (FHS)

The name of this subsection can be a little confusing, because the FHS applies to snaps used both on classic Ubuntu as well Ubuntu Core. The snap installation directory is read-only, with specific writable data areas. These areas correspond to environment variables that are set during runtime. Specifically:

  • read-only access to $SNAP (versioned install path)
  • write access to $SNAP_DATA (versioned path in /var)
  • write access to $SNAP_USER_DATA (versioned path in /home)
  • write access to $SNAP_COMMON (snap-specific path in /var)
  • write access to $SNAP_USER_COMMON (snap-specific path in /home)
  • write access to $XDG_RUNTIME_DIR (snap-specific path in /run/user/”uid”)
  • write access to shared memory files (/dev/shm/snap.SNAP_NAME.*)
  • read-only access to install path and data directories of previous versions
  • access to a subset of executables in /bin, /sbin, /usr/bin and /usr/sbin
  • allow processes from the same snap to communicate with each other via abstract and anonymous sockets
  • allow processes from the same snap to signal each other via signals

Application confinement

Furthermore, there are several confinement mechanisms enabled in Ubuntu (snaps):

  • Security policy ID – Applications are tracked by the system using the concept of identifiers. This identifier is a composition of elements from the snap’s packaging. Specifically, it consists of the package name and the command name. The security policy ID takes the form of snap.”name”.”command”.
  • Snap trust model – Snaps are not allowed to use crond scheduling service, change to another user, have unapproved access to hardware, add rsyslog rules, add users, ship setuid/setgid programs, change security policy, modify the system, modify kernel runtime variables, or access sensitive kernel syscalls. By default, snaps are not allowed to manipulate network interfaces, routing, QoS, network namespaces, manipulate the firewall, monitor the network, and do not run with CAP_NET_ADMIN. Snaps may request ‘network-control’, ‘firewall-control’ or ‘network-observe’ in their plugs to perform the above, but these are subject to store upload policies.
  • Application launching – When a snap starts, the snap run command will determine how to start the program and configure its runtime environment variables. It will execute snap-confine, which will then: configure work and temporary directories for the snap, setup device access to hardware, setup a Linux kernel system call filter via seccomp, and launch the command under an AppArmor profile.
  • Self-checks – On boot and during installations, the snapd service will perform integrity checks on snaps. If any problems are detected, the snaps will be disabled until refreshed from the store with an updated version.

Ubuntu Core

Ubuntu Core is a lightweight, robust, transactional version of Ubuntu for IoT devices and large, scale-out container deployments. It comes with additional security hardening and restrictions compared to the snap security on classic desktop distributions.

Please note that the list below is not comprehensive, and does not cover all the security features available in Ubuntu Core, but it outlines some of the major differences, as well as security mechanisms in it.

Architecture

There are a few important differences in how Ubuntu Core is designed:

  • Ubuntu Core is application-centric instead of distribution archive-centric.
  • Ubuntu Core replaces apt with the snap command – applications are packaged and delivered entirely as snaps.
  • The base system is a minimal system that consists of three parts: the operating system, the kernel, and gadget, which are all delivered using the snap packaging format. The OS snap is constructed from DEB packages from the Ubuntu archive. The gadget snap provides several snaps during the provisioning steps, and they will be preinstalled for the user.
  • There is a clean separation between the base system (base snaps) and the applications installed from the store (application snaps), as well as a clean separation between installed applications.
  • The root filesystem is read-only.

Boot mechanisms

Ubuntu Core uses the same boot process as classic Ubuntu. However, unlike classic Ubuntu, all applications on Ubuntu Core run under an application sandbox, and they are not permitted to modify the firmware, bootloader, kernel, modules, initrd, and init, and they are not allowed to interact with the base system except in very controlled ways.

System mechanisms

The Ubuntu Core base system contains only the following components: kernel, the init process, snapd service, and several standard Linux/UNIX tools and libraries to make application development easier.

Ubuntu Core only exposes a very small subset of the systemd specification in the snap packaging. On system install, the systemd unit file is auto-generated based on these packaging options. This prevents snaps from interacting with systemd and the system in uncontrolled ways.

User logins

As part of provisioning, one user account is setup using the Ubuntu SSO as the name of the user. By default this user has console access disabled and SSH access allowed via the SSH key stored in Launchpad for the user. This user is in the sudo group and thus capable of running commands as root. Multi-user support is limited on Ubuntu Core, but alternate user accounts can be set up using standard tools.

Security trust model

As we briefly mentioned earlier, Ubuntu Core differs from classic Ubuntu in how software is distributed, including core operating system snap, pre-installed snaps and snaps installed via the store.

Untrusted by the operating system

Application snaps are considered untrusted. We touched on this in the first article on security, whereby we mentioned that untrusted applications:

  • can freely access their own data.
  • cannot access other applications’ data.
  • cannot access non-application-specific user data.
  • cannot access privileged portions of the OS.
  • cannot access privileged system APIs.
  • may access sensitive APIs with user permission provided the API asks for permission at time of access or the permission is granted to the application outside of snap installation.

Security in action

To understand how the snap packaging, security policy and runtime restrictions all work together, let’s examine a use case. Below, we have a sample snapcraft.yaml file for a foo application. This content will be transformed into a snap and uploaded to the store. In this example, the snap is assigned revision 7 by the store.

name: foo
version: 1.0
description: foo does stuff
apps:
bar:
command: bin/bar-service
daemon: simple
plugs:
- qux
- network
ctl:
command: bin/control

What do we have here? We have a snap named foo, version 1.0. It has two commands in it, one called bar and one called ctl. Bar is a background service (daemon), and it requests access to qux and network interfaces. Ctl runs the bin/control executable.To make the example more complete, there is also an existing snap named baz.

name: baz
apps:
norf
daemon: dbus
slots:
- qux

The snap named baz has an application named norf. It is a D-BUS message bus type background service, and it provides a slot named qux, to snaps that request access (plug) for qux.

When foo runs, the following happens:

  • Security policy ID for bar is snap.foo.bar. It has the default security policy with the network interface auto-connected. The qux interface is not auto-connected, but it can be manually connected during runtime.
  • Security policy ID for ctl is snap.foo.ctl. It has the default security policy only.
  • For both of the above commands, the runtime environment variables are set to SNAP_REVISION=7, SNAP=/snap/foo/7, SNAP_DATA=/var/snap/foo/7, and SNAP_USER_DATA=$HOME/snap/foo/7.
  • The foo snap plugs into the qux interface. The baz norf service implements the qux slot. There is no automatic connection – it is done manually via snap connect foo:qux baz:qux. The security policies are configured to allow (by seccomp filter) bar to connect() to norf D-Bus service at org.qux (by AppArmor policy).

Conclusion

Snap security comprises several layers, and users often only see the top one, working and interacting with snaps. But there is a lot happening under the surface, starting with robust operating system fundamentals, and continuing with hardening policies and a strong trust model. Hopefully, this article has shed some light of the things happening behind the scenes, which should give you a better understanding and more confidence into the snap security model.

Furthermore, Ubuntu Core introduces additional measures, specifically tailored for IoT devices. With the entire system deployed as snaps, and further restrictions on what snaps can do, Ubuntu Core is a dependable choice for IoT deployments.If you have any thoughts or feedback on this article, we invite you join our discussion forum.

Photo by Sandra Ahn Mode on Unsplash.

Newsletter Signup

Related posts

Creating Snaps on Ubuntu Touch

This article was written in collaboration with Alfred E. Neumayer of the UBports Project. Tablets, phones and current technology’s capabilities are phenomenal. Who would have thought a thin, light, barely 10 inch device would provide all the power necessary to run Virtual Machines, wherever one desires while powered on battery? That a sma […]