The magic behind snap interfaces

This article is more than 3 years old.


Snaps are confined, self-contained applications, designed with portability and security in mind. By default, strictly confined snaps run in isolation, with minimal access to system resources. For instance, they cannot access home, network, audio, or display. To make their snaps usable, developers and publishers can declare a set of interfaces, which allow granular, per-resource access to the underlying system in a secure, controlled manner.

In today’s article, we want to talk a bit more about the mechanics behind the interface. What happens when a developer declares an interface plug in snapcraft.yaml, and when that snap gets installed on a user’s machine?

Declaration

Interfaces consist of two components – slots and plugs. The slot of an interface is a provider of functionality (and access) to a system resource. The plug of an interface is a component of a built snap, which can then connect to the relevant slot, and thus gain access to the underlying resource. Multiple plugs can connect to a specific slot, e.g.: multiple snaps with the home plug can connect to the home slot, and thus gain access to the user’s home directory.

For security reasons, some interfaces can be auto-connected – on snap installation on a client’s machine, the declared plugs will be able to connect to the slots without any manual intervention. In other scenarios, this will not be possible by default. The user will need to manually connect their snap, or request an override from the Snap Store team. In some cases, this functionality may be granted, especially if it’s part of the necessary application functionality. Typical examples would be network control or audio recording capabilities.

In some cases, the snaps will notify you that a specific connection is required. In others, you will need to determine this yourself, perhaps if you encounter a functionality problem. You can also manually choose to connect or disconnect interfaces as you see fit, but be aware that this may alter the application’s expected behavior.

snap connections vlc
Interface               Plug                        Slot                     Notes
audio-playback          vlc:audio-playback          :audio-playback          -
audio-record            vlc:audio-record            -                        -
avahi-control           vlc:avahi-control           -                        -
camera                  vlc:camera                  -                        -
desktop                 vlc:desktop                 :desktop                 -
desktop-legacy          vlc:desktop-legacy          :desktop-legacy          -
dvb                     vlc:dvb                     -                        -
home                    vlc:home                    :home                    -
jack1                   vlc:jack1                   -                        -
mount-observe           vlc:mount-observe           -                        -
mpris                   -                           vlc:mpris                -
network                 vlc:network                 :network                 -   

In the snippet above, the VLC media player has access to a wide range of typical resources required for its functionality. The camera isn’t auto-connected, though. For example, if you need VLC to capture a video stream using the camera device, you will need this interface to be connected. 

sudo snap connect vlc:camera

Now, in a typical snapcraft.yaml file, a plug section declaration may look like this:

apps:
  segfexample:
    command: segfexample
    plugs:
    - home
    - network

If you’re interested in a broader overview of interfaces and specific use cases, we have already covered this in detail in a blog post a while back.

Installation

During the installation, if you install a snap on the command line and you pay attention to the output in your terminal window, you may see a number of messages from the snapd service about mounts, connections, etc. The installation of the snap includes two principal steps:

  • Unpacking of the snap (a compressed Squashfs archive).
  • Configuration of the security profiles.

Once the snap is installed, you can inspect the system configuration. The snapd AppArmor profiles are stored under:

/var/lib/snapd/apparmor/profiles

Depending on how complex your snap is, there may be one or more profiles, e.g.:

-rw-r--r-- 1 root root  4706 Jun  3 12:32 snap-update-ns.segfexample
-rw-r--r-- 1 root root 23379 Jun  3 12:32 snap.segfexample.segfexample

Provided you have the right permissions, you can now open these profiles in a text editor, and examine the contents. You need some familiarity with the AppArmor syntax, but in essence, you will see the capabilities declared in your snapcraft.yaml plug section listed and expanded here


# Description: Can access the network as a client.
#include <abstractions/nameservice>
/run/systemd/resolve/stub-resolv.conf rk,
/etc/mdns.allow r,     # not yet included in the mdns abstraction
network netlink dgram, # not yet included in the nameservice abstraction
...

Source code

If you want to know more about how a particular interface works, you can also look at the snapd source on GitHub. For instance, the home interface. The code declares the slot specifications, including read and auto-connect attributes, and the AppArmor profile details that will be applied on installation. In this example, the profile allows read/write access to all files in the user’s home directory, except for the snap application path and top-level hidden directories, allows creation of new files, allows access to GVFS mounts for files owned by the user, and disallows writes to the bin subdirectory.


const homeBaseDeclarationSlots = `
  home:
    allow-installation:
      slot-snap-type:
        - core
    deny-connection:
      plug-attributes:
        read: all
    deny-auto-connection:
      -
        on-classic: false
      -
        plug-attributes:
          read: all
`
...

Summary

Snap interfaces may look a bit confusing at first, especially since their behavior diverges from the classic Linux model. However, they can be useful in making sure applications only use the necessary system resources. This can improve both security and predictability, and minimize long-term cruft in the system.

If you want to understand exactly what will happen when you declare a plug in your snapcraft.yaml, you can check the snapd source code and/or the AppArmor profiles for the installed snap to get a clearer view on the specific implementation of the security confinement logic. Hopefully, this article makes things simpler, and reveals the “magician’s trick”. Let us know if you have any questions or suggestions on this topic by joining the Snapcraft forum.

Photo by note thanun on Unsplash.

Talk to us today

Interested in running Ubuntu in your organisation?

Newsletter signup

Get the latest Ubuntu news and updates in your inbox.

By submitting this form, I confirm that I have read and agree to Canonical's Privacy Policy.

Related posts

Canonical announces Ubuntu Security Research Alliance Program 

Today, Canonical, the publisher of Ubuntu, announced its new Ubuntu Security Research Alliance Program, a free partnership between Canonical and open source...

Needrestart local privilege escalation vulnerability fixes available

Qualys discovered vulnerabilities which allow a local attacker to gain root privileges in the needrestart package (CVE-2024-48990, CVE-2024-48991,...

Imagining the future of Cybersecurity

October 2024 marks the 20th anniversary of Ubuntu. The cybersecurity landscape has significantly shifted since 2004. If you have been following the Ubuntu...