skip to content

A snap-installed application refuses to open a file under /mnt/data even though the file is world-readable and you can read it with `cat` as the same user. Why does snap's strict confinement block it, and how do you grant the access?

level: middleimportance: must knowfreq 50%

answer

  1. mode bits are not the gate here
  2. a sandbox wraps every strict snap
  3. capabilities are named and connected explicitly
  4. /mnt is not covered by home
  5. snap connect the removable-media plug

basics

~20 s

Strict snap confinement sandboxes the process with AppArmor and seccomp, so access depends on the interfaces the snap has connected rather than on Unix permissions. Paths under /mnt need the removable-media interface, which does not auto-connect; attach it with snap connect.

solid answer

~40 s

A snap installed with the default *strict* confinement runs inside a sandbox: an AppArmor profile over file paths, a seccomp syscall filter, a device cgroup and a private mount namespace. AppArmor is checked before Unix permissions, so a world-readable file is still denied unless some connected **interface** grants the path. Everything a strict snap may touch outside its own directories comes from an interface — `home`, `removable-media`, `network`, `system-files` and so on — declared by the snap as a *plug* and connected to a matching *slot*. `network` and (on classic Ubuntu) `home` auto-connect; `removable-media`, which covers `/mnt`, `/media` and `/run/media`, does not. I would confirm with `snap connections <name>` and an `apparmor="DENIED"` line in `journalctl -k`, then run `sudo snap connect <name>:removable-media`.

code

bash · 9 lines
bash
# Which capabilities does the snap actually have?
snap connections vlc

# Confirm the sandbox is what refused the open
journalctl -k --since "5 min ago" | grep DENIED

# Grant access to /mnt, /media and /run/media, then verify
sudo snap connect vlc:removable-media
snap connections vlc

go deeper

for a junior

Know that a snap runs inside a sandbox and that being able to read a file in your own shell does not mean the snap can. Be able to say that snap connections lists what it is allowed to touch.

for a middle

Explain the plug/slot model, name the mechanisms doing the enforcement (AppArmor, seccomp, device cgroup, private mount namespace), and know that home skips hidden files while /mnt needs removable-media.

for a senior

Show the diagnosis: reproduce inside the sandbox, find the apparmor="DENIED" line with its profile name, then make the narrowest grant that fixes it. Be ready to say where a snap's writable data actually lives and what that breaks in existing backup and log tooling.

for a principal

Own the policy: which snaps are permitted on the fleet, whether classic confinement is ever acceptable and who signs off, and how interface connections are made reproducible in configuration management rather than typed once by hand on one host.

## Confinement is not a permission check A snap installed with the default *strict* confinement does not run as an ordinary process governed only by ownership and mode bits. snapd starts it inside a sandbox assembled from four kernel mechanisms: a generated **AppArmor** profile (mandatory access control over file paths, D-Bus names, ptrace, signals), a **seccomp** filter (an allow-list of syscalls), a **device cgroup** (which device nodes may be opened), and a **private mount namespace** in which the snap sees its own read-only squashfs at `/snap/<name>/current` and a private `/tmp`. Unix ownership and mode bits are still enforced, but AppArmor is consulted as well, and a denial there produces the same `EACCES` your application reports as "permission denied". So "the file is 0644 and my shell can read it" tells you nothing about whether the snap can open it. This is the single most common snap support ticket. ## Interfaces, plugs and slots Everything a strictly confined snap may touch outside its own directories is expressed as an **interface** — a named capability such as `home`, `removable-media`, `network`, `network-bind`, `system-observe`, `hardware-observe`, `camera`, `personal-files` or `system-files`. The snap declares a **plug** for each interface it wants; the system (or another snap) publishes the matching **slot**. When a plug is connected to a slot, snapd regenerates that snap's AppArmor and seccomp profiles to include the extra rules and reloads them. Connections are the thing you inspect and change: ```bash snap connections vlc ``` This prints Interface / Plug / Slot / Notes. A `-` in the Slot column means the plug is declared by the snap but is not connected, so the capability is not granted. Some interfaces **auto-connect** at install time because the store treats them as safe by default: `network`, `network-bind`, and — on classic (non-Core) systems — `home`. Many deliberately do not: `removable-media`, `system-files`, `personal-files`, `raw-usb`, `docker`. Those are exactly the ones behind "it can see the file but cannot read it". ## The two traps that produce most tickets First, `/mnt`, `/media` and `/run/media` are not covered by `home` at all. They belong to `removable-media`, which is not auto-connected — so anything you mounted for the application (an NFS share, a data disk, a bind mount) is invisible to a strict snap until you connect it. Second, the `home` interface grants access only to **non-hidden** files in the user's home directory. A snap can read `~/data.csv` and be denied `~/.config/tool/settings.toml`, which surprises people who assume "home access" means the whole directory. Dotfile access needs `personal-files` with the specific paths declared by the snap. ## Confirming it really is confinement AppArmor denials go to the kernel log: ```bash journalctl -k --since "5 min ago" | grep DENIED ``` The lines carry `apparmor="DENIED"`, the `operation=` that failed, the `profile=` (named `snap.<snap>.<app>`, which tells you exactly which snap and which app inside it) and the `name=` of the path. If nothing appears there, you are chasing an ordinary permission or path problem, not the sandbox. `snap run --shell <snap>.<app>` drops you into a shell inside the same confinement environment, which is the fastest way to reproduce an access by hand without the application in the way. ## Granting the access ```bash sudo snap connect vlc:removable-media ``` The connection is persistent: it survives refreshes and reboots, and `snap disconnect` reverses it. If no interface expresses what you need, the remaining options are `system-files`/`personal-files` (the snap must declare the exact paths, and store-published snaps need a store grant to use them), relocating the data somewhere an already-connected interface covers, or abandoning strict confinement. ## Classic confinement and devmode `snap install --classic <name>` installs a snap that runs with no sandbox, seeing the host filesystem like any other program. Publishers must be granted permission to ship a classic snap, and the `Notes` column of `snap list` shows `classic`. It is the right answer for tools that legitimately need the whole system — editors, compilers, cloud CLIs — and the wrong answer for "I could not be bothered to connect an interface". `--devmode` puts the sandbox in complain mode: violations are logged but allowed, which is a debugging aid, not a deployment mode. ## What this changes operationally A snap's writable state does not live where you expect. Per-revision system data is under `/var/snap/<name>/<revision>/`, common data under `/var/snap/<name>/common/`, and per-user data under `~/snap/<name>/`. Backup jobs, log shippers and runbooks written for a distro package will silently miss all of it, and any of them that are themselves snaps face the same interface question in reverse.

  • Why do some snap interfaces connect automatically at install while others require an explicit snap connect?
    Auto-connection is a store-side policy decision per interface: ones judged safe for any snap to hold (`network`, `network-bind`, and `home` on classic systems) connect on install, while ones that widen the sandbox substantially — `removable-media`, `raw-usb`, `system-files` — are left disconnected so a human makes the grant. A publisher can also request an auto-connect exception for a specific snap through store review.
  • A colleague fixes every confinement problem by reinstalling the snap with --classic. What is your objection?
    Classic confinement removes the sandbox entirely — the snap sees the host filesystem like any package would — so it trades a targeted grant for unlimited access, and it is not even available unless the publisher was granted permission to ship a classic snap. If the snap needs one directory, connect the interface that covers it. Reserve classic for tools such as editors and cloud CLIs that genuinely need the whole system.
  • How would you tell whether an access failure comes from AppArmor or from the seccomp filter?
    Both surface to the application as an ordinary error, so read the kernel log: an AppArmor denial logs `apparmor="DENIED"` with the `profile=snap.<snap>.<app>` and the path or object it refused, while a seccomp violation logs the blocked syscall against the same profile name. File and D-Bus problems are almost always AppArmor; an odd `EPERM` from an unusual syscall points at seccomp.

Unix permissions are the lock on the door; strict confinement is a building pass that lists which rooms you may enter at all. Being handed the key to a room you have no pass for still leaves you outside it.

saying these in an interview costs you the question

  • Says the file permissions must be wrong and chmods it
  • Thinks snap confinement is only a desktop concern
  • Believes the home interface covers dotfiles and /mnt
  • Reaches for --classic instead of connecting an interface
  • Assumes snap data lives in /etc and ~/.config

context