Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Snap Execution Environment
Snap applications and hooks execute in a specially crafted environment. The word environment does not merely refer to environment variables but to the set of observable properties of the system.
When a snap application is started it is typically done so by executing one of the programs in the
/snap/bin/ directory. Curious observer will notice that all such applications are symbolic links to
snap executable detects this and behaves as if
snap run had been invoked. This locates the correct snap and application name and proceeds to
exec the first helper program,
The purpose of
snap-confine is twofold: As the name implies it is responsible for confining the started process by establishing the security sandbox. In addition it also sets up the mount namespace of the process in a way that will be described below.
Confined and in a modified mount namespace,
snap-confine proceeds to run (no longer with elevated permissions) the last of the helper programs called
snap-exec. The purpose of that program is to parse the
snap.yaml file belonging to the application that is being started and execute the command listed there.
All of the transitions here, from the
/snap/bin/foo -> /usr/bin/snap, to
snap-exec are done with the
exec system call. At all times there is only one process going through this transition.
Applications built with snapcraft usually have one more step. The actual command that was spelled out in the
snapcraft.yaml file is moved to a shell wrapper script
command-SNAP-APP-wrapper. The wrapper sets
LD_LIBRARY_PATH and executes the real command.
There are two main parts of the confinement that are applied to each process: apparmor and seccomp.
snap-confine ensures that upon exec an apparmor label is associated with the process. The label is always derived from the snap and application name (snapd code often refers to this as the security tag). A program like
hello-world has the apparmor label of
snap.hello-world.hello-world (the snap name and application name are always separate in the security tag).
The apparmor profile is stored directly in the kernel memory. The profiles as they exist on disk can be found in
/var/lib/snapd/apparmor/profiles. They are loaded by snapd when they are generated or are loaded on boot by one of the apparmor systemd units (TBD: clarify which).
The apparmor profile defines most of the policy. It specifies which files can be read, which can be written, it specifies details of what is allowed by various IPCs (including DBus) and more. Typically when something is not allowed by the policy, apparmor returns a permission denied error (
EACCES) at the lowest level of the system.
Apparmor profiles use a standardised syntax that is documented extensively by the apparmor project. If you want to learn more about that please visit http://apparmor.net/
The seccomp profile is stored on disk and is loaded and parsed each time. The profiles are in
/var/lib/snapd/seccomp/profiles) and are named the same way as their apparmor brethren. Seccomp profiles mainly define which system calls are allowed. In some cases system calls are also filtered by the particular arguments.
The syntax for expressing seccomp profiles is unique to snapd. You can find more about this in the snapd source code.
Setting up the mount namespace
The mount namespace defines what a process "sees" in the file system. Two process running on the same kernel can see different root file system and set of mount points thanks to this feature. Snappy uses this feature extensively to construct a consistent look of the file system that is not strongly affected by how the host distribution arranges the file system.
The details are somewhat complicated but the result is that:
The application sees the core snap as the root of the file system. You can think of this as a chroot of sort.
Certain directories from the host file system are mapped (bind-mounted) to the mount namespace (see below).
The mount event propagation is restricted so that anything that is mounted in the mount namespace is only visible there
As an exception the
/mediadirectory shares mount events (e.g. udisks2 snap can mount globally visible things there)
/run/netns, it is a location used by the
iptool to manage network namespaces.
The mount profile of the snap is applied (e.g. content sharing uses this)
/media(depending on the distribution)
Keep in mind that the core snap which now acts as the root file system is read only. This is not a limitation of the security sandbox but an inherent property of the squashfs file system that snaps rely on.
Preserving the mount namespace
snap-confine prepares the mount namespace and then preserves it for subsequent runs of applications in the same snap. The prepared namespace is saved as a bind mounted
nsfs (namespace file system) file in
/run/snapd/ns/$SNAP_NAME.mnt. As with all files in
/run the mount namespace is not preserved across system reboots.