Core Snap Refresh and Your App

5 minute read Published:

What happens for your app when the core is refreshed

The core snap is universally installed on every machine that runs any snap applications. That snap provides the root filesystem which is used as a base of the execution environment of all snap application processes. Most snaps use the core as the base though technically we can now offer other base snaps, as ubuntu 18.04 approaches this will be more and more visible but for now we will just ignore that aspect.

The core snap is both small and huge. It contains whooping 848 shared objects (344 if you ignore text encoding codecs) that are potentially used, perhaps indirectly, by your application. Among that set you can find some usual suspects such as openSSL or PAM. It also contains a complete Python installation. While the core snap is just 84MB, and will hopefully get a lot smaller in Ubuntu 18.04, it is still fundamental pretty much every snap application out there.

When there’s another huge software vulnerability that requires coordinated disclosure and patching of one of the fundamental or widely used libraries the core snap can be updated for you, automatically, without user intervention.

But is it? Let’s see what really happens.

Preserved execution environments

As you undoubtedly know, snap applications inhabit a sort of twilight zone that partially sees your normal computer system and partially lives in a nice and consistent world established by the core snap. When you run a long lived application it will obviously keep that execution environment around during its lifetime. What you may not know is that even short lived processes, from a particular snap, share their execution environment. This has many advantages. Files placed in a volatile storage (like, say, /tmp) stick around and don’t magically disappear. Shell sessions (snap run --shell <snapname>) can be used to explore the same space that is used by ongoing or priorly started applications. It all feels consistent.

This is done by doing a neat trick which technically bind-mounts the mount namespace of the first snap application process into a special space in /run/snapd/ns/. That and inverting the shield polarity, perhaps.

This is the good stuff, but it is not without some issues.

Refreshing the core snap

So let’s do a mental exercise and work through a scenario that is happening periodically to everyone’s snap-bearing machines. You are happily running your snap apps of all kinds while a new snapd or core snap release comes along and is automatically refreshed onto your computer.

So what happens with existing application processes? In traditional systems the packages are installed or updated, files are added, removed or replaced and you can immediately see the new (updated) things. Running processes are still using the old copy of the libraries they have loaded at startup due to a specific way Linux and some other operating systems handle the filesystem and files that are mapped into memory.

In simple terms until you restart your application you are still using the old shared libraries but will immediately see and perhaps use new data. This can have some nasty consequences (see various “restart now” pop-ups in Firefox) and is generally not immediately obvious to non-technical users. Some systems choose to apply updates in a special boot mode, using a technique pioneered by systemd. In this way updates don’t break running applications and applications don’t stick around with stale (or potentially insecure) libraries mapped into their address space.

What happens in snapd? Pretty much the same thing happens at the system level (shared libraries still behave the same way) but there’s one new interesting aspect. The core snap is an integral part of the preserved execution environment, and because snaps don’t change any files on disk but instead they mount the whole new revision of the snap, all running applications still see the old thing. To use the new core snap you’d have to reboot your machine.

With snapd 2.31 this will change and core snap refreshes will start to get applied as soon as possible, without needing a reboot. What will happen is that when all of the processes belonging to a particular snap terminate the next started process will switch to the updated revision of the core snap. Before all processes (of that particular snap) terminate we will keep using the preserved execution environment for both old and new processes because otherwise we would fracture the world into per-revision spaces that don’t see the same things in usual places. It would just cause confusion for developers that would have to consider how their application update process can split the world into separate shards.

All processes of a given snap always see the same execution environment and will atomically switch to the new revision of the core snap when this can be done consistently after the last process, of that snap, terminates.

Imperfections and road ahead

This is way better than running with outdated software but it is still not perfect. In ideal world we would notify long-running processes that they can update (perhaps using a hook mechanism) and ensure that important use cases (e.g. web server or application server) are handled correctly without any extra hand-holding.

For now application developers cannot do more than instructing their users to restart the application / service periodically (after updates). We will be working on additional mechanism to handle updates in future releases.

comments powered by Disqus