-
Notifications
You must be signed in to change notification settings - Fork 592
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 /usr/bin/snap
. The 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, snap-confine
.
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-confine
and 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 PATH
, 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/bpf/*.src
(formerly /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.
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
/media
directory shares mount events (e.g. udisks2 snap can mount globally visible things there) -
so does
/run/netns
, it is a location used by theip
tool to manage network namespaces. -
The mount profile of the snap is applied (e.g. content sharing uses this)
-
/dev
-
/etc
-
/home
-
/root
-
/proc
-
/sys
-
/tmp
-
/var/snap
-
/var/lib/snapd
-
/var/tmp
-
/run
-
/lib/modules
-
/usr/src
-
/var/log
-
/run/media
or/media
(depending on the distribution) -
/run/netns
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.
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.
violethaze74 This is the snapd wiki, feel free!