Base runtime freedesktop-sdk-runtime-19-08

I have found out that my installation on Debian does not have full confinement. Only devmode. So that might be the issue why I can call lzip.

1 Like

That would explain it, yes.

@valentind - it sounds like you are working on trying to make the runtime smaller. Is this so it will run with the default template or will it still have things outside of the default template that the snap should have access to? If the latter, can you provide that list? (cc @pedronis - this is sounding like we will need a concept of base snap security policy templates…)

Not much will be removed. I think the last thing I have to remove are some gettext utilities.

The list of executable needed might change from one release to another. I suggest, in order to make snap-confine to work with other bases, to allow execution for the following:

  • {/usr,}/bin/*
  • {/usr,}/sbin/*
  • {/usr,}/libexec/**
  • {/usr,}/lib{,32,64,x32}/**

For the case of the Freedesktop SDK, we need only:

  • /usr/bin/*
  • /usr/libexec/**
  • /usr/lib/**

The alternative can be that we provide the exact list of paths in the metadata to generate the apparmor file.

@jdstrand is off for a little while, but I let him comment on this when he is back. It’s unlikely we can have blank permissions like that tough.

These accesses are indeed quite broad. @pedronis - we need to think through what we want confinement to look like for base snaps. I’ll list a few random thoughts to seed the conversation and then provide my current view.

In a lot of ways, the broad access makes sense since in a sense a base snap is like a content snap and we allow this sort of access with content snaps. In terms of security, there is tremendous trust in the base snap publisher for snaps that use the base and we have seccomp, apparmor capabilities, etc, etc in place (just like we do with content snaps and for people that stage-packages), but apparmor file access could provide some guardrails here. We will definitely want to continue to disallow file caps, setuid, etc regardless of how we move forward.

Base snaps overlap with content snaps but are different in that they are the base runtime and limiting the access has benefits beyond security (as well as maintenance costs). The apparmor policies could assist with declaring what is meant to be there and supported. The default apparmor template was always meant to expose the bits of the core snap that would be meaningful as a runtime of snaps and no more, which suggests we should do the same with base snaps. Where it breaks down is that apparmor is imperfect for this since apparmor won’t detect if something that was allowed is removed and it doesn’t help with cross-distro with forced devmode (indeed, we use the same template for core{,16} and core18 even though core18 doesn’t ship things allowed in the template; the fact that we are using the same template is AFAIK not by design, is evolutionary and arguably a mistake).

I’m a bit concerned about exposing all of /usr/bin/, etc since some of those binaries are going to be poking around in /etc and I foresee compatibility issues with the shared-/etc-with-the-host and binaries in the base snap. If the binaries can be curated and enumerated, the enumeration process can provide a form of sanity check to the whole process. We already have processes for reviewing new file accesses in the template/interfaces, so this same process could be extended to base snap policy which is a natural forum to discuss how things work, might break, etc.

Finally, I also have concerns with how base snaps will interact with implicit interfaces. Eg, do we really want to go in the direction of having each interface be the superset of accesses for all base snaps? I suspect not, and I’m a little uncomfortable in the direction of https://github.com/snapcore/snapd/pull/7073 in this regard: it is extending the opengl apparmor policy to account for paths provided by a particular base snap.

I admit that I didn’t bring all this up when the concept of base snaps was first introduced (since no one was using them), but now that people are actively creating new ones and they are being suggested for various uses, I feel like we need to press pause for a moment and think through how this should work more. I’m feeling like a better path forward is:

  • for each base snap where the default template is not sufficient, provide an alternative base snap template or append base-specific policy to the current template (whichever is more appropriate)
  • for each base snap where interface policy is not sufficient, provide an alternative base snap interface policy or append base-specific policy to the interface policy (whichever is more appropriate. For the opengl PR, this would mean breaking out the base snap policy into a separate snippet that is only added when the base in question is in use).

This adds implementation complexity, but in addition to the aforementioned guardrails, it is tidier in many ways, helps with policy auditing and helps prevent inflated policy. I suspect it would help with longterm maintenance as well since would accommodate situations where, for example, we know that an access is ok in base snap ‘foo’, but not ‘bar’, because ‘foo’ is hardened in some way where ‘bar’ is not.

We will be fine providing either a policy template or fragment along with our runtime. Just say when there is something to test.

Do you have any thoughts about how a base snap would describe these rules? If it is as raw AppArmor rules, that will likely need manual review on each release (or each release that modifies its policy fragment). I do wonder a bit how much customisation each base snap would need though.

As you’ve said, a lot of the policy complexity comes down to the dual purpose of the core and core18 snaps: on the one hand they provide an application runtime, and on the other they provide a bootable root file system for an Ubuntu Core system. Just because the base includes a full systemd install in order to fulfil it’s role as a boot file system doesn’t mean the presence of those files form part of its contract as an application runtime.

But if we have a base that is a pure application runtime, this seems less of an isue: why write an AppArmor rule to hide a file/directory when it could simply be omitted from the base entirely? Would there be any downside to having a mostly permissive policy granting read access to everything provided by the base (i.e. keeping current restrictions on /dev, /sys, /proc, etc)?

There are some cases where certain command line utilities are progressively exposed as you plug various interfaces, but does that actually increase security rather than just aid in debugging? For example, is it a problem if a base snap provides the lsusb command but it only functions correctly with hardware-observe plugged? Is it a problem if a base includes OpenGL libraries/drivers that will only function correctly when opengl is plugged? If we decide that it is okay to make those files from the base readable unconditionally, then it also removes the need to have base-specific rules inside the interface implementations.

how would this work with core and core18 themselves? and afaiu we will still need control around setuid binaries etc? it’s not fully clear to me how we would express that intention considering that bases can have differing fs layouts than what we usually expect, and we can’t simply grant a read anything under / .

My suggestion was that the permissive policy be applied for what I termed “pure application runtime base snaps”. The core and core18 snaps don’t fit that description due to their use in booting Ubuntu Core systems.

My point was more that if we are going to have a base specific portion of the template AppArmor policy, that a fair number (perhaps all other than core*) might be able to use the same permissive policy fragment without loss of security.

to be clear, in any case, I really want to avoid that:

  • it’s too low-level
  • we would likely need to parse it and analyze it and/or bless it somehow
  • we really want to keep the purpose of bases clear:
    • ship the skeleton of a root filesystem
    • a coherent set of system/runtime libraries and binaries
    • possibly some “/etc”-like configuration/data

Could we just a provide with the base a list of paths that need to have execution rights?

So how do we move forward on this?

Does the rationale for allowing fairly permissive AppArmor file access to non-bootable base snaps make sense? It seems like an option that would remove most of the need for most base snap specific policy in both the base template and interface implementations.

I agree with this sentiment. We used to do something similar to this with the ‘frameworks’ concept in snappy 15.04 (which is long gone now) where SDKs, runtimes, etc could explicitly declare security policies for using the framework which would need human oversight for design and approval. It was actively decided for the redesign that we would not bring this concept forward in any capacity and out of that came the interfaces system.

IME, runtimes are different from interfaces but share some important characteristics. We often talk about how interfaces form contracts between the slot and the plug. I would argue that base snaps form a contract between the runtime and the consumer of the runtime. As such and for the same reasons we do this for interfaces, snapd should encode the runtime’s security policies (whether they are lenient or not is an implementation detail). snapd is implicitly doing this today, but assuming core policies are correct, so we just need a mechanism in snapd to define the base runtime policies and when to use them. In this manner, the base runtime developer doesn’t need to do anything special in the snap, but does need to work with the snapd team on the security policies. This is analogous to adding and maintaining a new interface (but keying off the value of 'base: ’ instead of adding new plugs/slots).

Possibly but that depends on my points above. If we use fine-grained policy, there is a maintenance burden, but it importantly provides an opportunity to curate and declare that the exposed binaries are always expected to work cross-distro.

Let’s say that a base did include a binary that didn’t work cross distro? Does that mean that the base snap would have to provide different policy for each host system it runs on top of? That’s starting to sound like either (a) something that shouldn’t be in the base snap, or (b) out of the scope for the security policy.

I guess my feeling is that we should treat these third party bases the same way we treat application snaps: that we should try to control what those executables could do rather than control access to the libraries/executables themselves. As far as automated review of third part base snaps goes, I think it would be reasonable to require the following:

  1. consists of only regular files, directories, and symlinks
    • Rationale: while snaps are mounted nodev, it is probably worth ensuring the base doesn’t include any device files anyway: we don’t want device files at unexpected paths to be used for privilege escalation should the mount security fail. It’s also possible that fifos in the file system could be used for communication between snaps in unexpected ways too.
  2. all files in the snap satisfy st_mode & ~0777 == 0
    • Rationale: the base snap should not enable setuid/setgid privilege changes. As the snap is not intended to be bootable, there is no rationale for including utilities like su, sudo, pkexec, etc.
    • There’s a good argument for mounting such base snaps with nosuid too.
1 Like

This is what we want for Freedesktop SDK. We do not need anything special. We only provide files, some are executable, and there is no suid or sgid. I believe most of 3rd party base runtimes will want the same.

1 Like

FYI, we met this week at the sprint and discussed this topic; thank you for being patient while we work through the processes and implementation for enabling base snaps like the freedesktop-sdk-runtime snap. We’ve agreed to take the approach that we will have a single base policy that is separate from the default template, that is mostly open, except for the areas where we overlay portions of the host fs onto the runtime (eg, when overlaying /etc, continue to not allow /etc/shadow). We will also refine our Process for reviewing base snaps a bit and make updates to the review-tools for base snap checks.

This requires a fair amount of unplanned engineering work, but we’ll work towards getting that into 2.42 or so.

1 Like

This won’t be in 2.42, but is now scheduled to start in November. Sorry for the delay on this, but once the work is completed, this will make everything straightforward in terms of reviews, processes and new base snaps.

@jdstrand, any news about it? Will there be some progress any time soon?