Classic confinement for `hibp`

You’d have to uninstall the whole OS, any native package on your system can do this, the strict snaps at least have safeguards. But when you install a third party repo / PPA for example, you’re handing over admin access to the repository owner, because they can simply redefine any package to have anything they want in it.

So explicitly, if you add a PPA without trusting the publisher, said publisher can replace your Linux kernel and install cryptominers and all sorts. Classic snaps are in no different position there to every other package format, the only technical solution comes down to trust in publisher and trust in the system.

It’s why we encourage strict snaps, to shift trust from humans to the machine itself.

Imagine you have a bug in your HTTP server. You’ve done the classic easy mistake in C of assigning in an if statement rather than an equality comparison, something like: if (user = 0), and now the authentication mechanism is knackered and people can remotely control it.

The sandboxing defends against that. The sandboxing also defends against the trust in publisher. If you publish as strict and try replace my Linux kernel, you’re going to have a bad time because it’s well beyond the permissions you’ll have.

The security model is relying on people being unable to do bad things, and not just specifically bad things, but make mistakes like everyone does; by imposing a lot of mitigations at every level of the stack. Now you don’t just need to find a logic bug in the HTTP server, you’ll have to find an exploit in the kernel itself, the barrier to making a trivial bug into an exploitable one shoots through the roof.

It’s not a silverbullet to all problems. The bug in the HTTP server for one of my own snaps mentioned earlier was still shockingly bad even with sandboxing. But the problem existed with or without snap, but it was significantly better with snap than without.

The answer is yes, you can drop permissions of the daemon with https://snapcraft.io/docs/system-usernames and you can write your wrapper script for the daemon to check if the daemon should run and abort if a setting isn’t set, I don’t know if you can define your daemon to default to not starting at all (the way Fedora would), but you can definitely make use of snap set to set a boolean toggle, and in your daemon have a script that checks the toggle and cancels execution if it’s not supposed to be on.

Hang on, I don’t think that’s a reasonable analogy.

The threat you describe exists, because the ppa “has root” only during the moment of installation. ie the user runs dpkg or apt with sudo and this root power is used to install the packages from the ppa.

Whereas, what I had understood from you above, is that a --classic snap can create a new daemon on an auto-upgrade and that this daemon could have runtime root privileges? All automagically?

Those are two different problems. The former is that dpkg is conferring trust in an untrustworthy datasource in order to change the installed packages on the machine. And the latter is that snapd is executing untrusted code as root, without the sysadmin ever having giving permission for that?

Yes it is true that the trust model of apt + ppas is broken. That’s why I don’t install ppas and certainly not on servers, especially those providing critical services. Systems like FreeBSD are somewhat safer, because upgrading ports / pkgs is a completely separate process to upgrading the base system.

Have I misunderstood?

But thank you for teaching me something about --classic snaps. I certainly would not want my software to be distruted like that, where the user is expected to trust me not to to run arbitrary daemons as root on an upgrade. I will now definitely be uninstalling any --classic snaps from all servers.

I think generally you’ve understood correctly, and you’re right that in effect the package manager only briefly grants the packages it installs root, but that brief moment is all that’s needed, because a native package can do the same, install a daemon and run dodgy code as root as on ongoing basis. The package manager won’t prevent this, the defence in distributions are peer review and identity verification; but any Apt package can absolutely just install a backdoor in the 1 second it has root, because that’s all that’s needed.

I can’t see a functional difference between a PPA and a classic snap in that regard. If a classic snap installs a root daemon, it can do that because for a split second the package manager is giving it assistance to do so. The same is true of Apt, DNF, and most other generic OS package managers.

But a strict snap can’t. Whilst it can install a root daemon, that daemon will be confined, so you can go e.g., “If I disconnect the home interface, and assuming the OS is set up fully to support the sandboxing, then it’s not getting $HOME access at all, ever, until the admin reapproves it”.

That’s covered whether the package is malicious, accidental, or happens to have a bug that unfortunately might end up doing bad things completely innocently by mistake. The kernel makes the guarantee that the app can’t do it, not the trust in publisher.

There is a significant difference, IMO.

apt and dnf repos are vetted. So they are “somewhat reasonably” conferring trust to a quality source.

ppas are just bad should not be installed. So I don’t and I hope neither would most server admins.

--classic snaps are also bad, probably worse than ppas. The attack surface is much larger. So I will be removing all those from servers right now. (I only started using cmake snap recently, so no big deal). Thank you.

and…

--strict snaps are arguably also bad as you have just explained, because they also get daemons as root. Behind the “confinement wall” which is however perforated by the interfaces? Which user is going to “disconnect the xxx interface” after each automagic snap upgrade?

TBH, the automatic upgrades are a really big part of the problem for snap IMO. I can see how that is useful for the desktop, but on the server, it makes me very nervous.

Upgrades should be triggered by the sysadmin, IMHO, who confers root privileges, and is at least reading the console, hopefully.

I’d disagree, I think the attack surface is lower because of the discussion we’re having right now. We don’t just let anyone submit classic snaps, identities are verified when classic is given, we actively push back on people granting classic, and openly refuse requests. (This can come off as aggressive sometimes, but hopefully from a general ecosystem POV, it makes sense why we do it).

But, the attack surface is there yes; it’s why if you don’t pass the classic flag, snap install will complain and warn you that all hands are off. That doesn’t make snaps worse, because you’re still going to have the other benefits, such as packages being signed through a central authority (canonical) that might not exist in other third party repos, as well as technical ones, version rollbacks, dependency improvements, etc.

The majority of interfaces don’t connect if they’re risky.

If you’d have requested the personal files interface instead, you’d go through similar review. Any snap uploaded to the store is automatically checked, if the automatic check finds aspects that need review, as you say, somebody trying to add an interface that opens up too much scope, it’ll get queried by a real person and we’re not shy in telling people no.

Broadly, interfaces come in:

*Ones that can be autoconnected, such as network, for being reasonably secure and expected

*Ones that can be defined but autoconnection requires review (similar to this here), they otherwise won’t connect until the admin/user approves it on their own device, unless they go through a review like this to make it an override.

*Ones that even attempting to define it will block the snap from being uploaded until a review occurs (personal files is a good example, since it’s configurable via attributes, those attributes are inspected manually).

And if for example, you changed your personal-files interface to try add something after the fact, we’ll catch that too.

You can use snap refresh --hold and configure it forever, on an all snaps or per snaps basis, making updates manual.

https://snapcraft.io/docs/managing-updates

--strict

OK, so you gave me network-bind and home without any vetting?

So I get a root daemon that listens to a port, which only comes into existence during a subsequent automatic update. Assuming not blocked by firewall, I now own your home directory at least? If I spent another hour, I could probably come up with much worse?

Unless I am misunderstanding, the more I find out, the more I worry.


The benefit to me, in snaps and similar services is to “build software in a somewhat platform agnostic way”.

Not in “automagically running self creating root daemons”.

That’s why I have been peddling the idea, for servers, of an --sysadmin. Build the software, but don’t install extra things and especially don’t run anything and do automatic stuff. Then don’t get in the way when I manually run the software.

that should probably be the default… ? At least on server OSs?

Actually no, the home interface won’t give root access to normal user homes because the interface has an @owner flag on it and root doesn’t own other users files, so the root daemon can’t, that’s why QHTTP above says “use /root” instead of “/home” if you want port 80.

The default for server OS’s is to install security updates, the advantage they have is that security updates are often purely security patches without new functionality. Which is also a disadvantage in some cases, because who’s going to support software with less functionality (well, RHEL, Canonical, etc, is the obvious answer, but they won’t support anything and everything).

LOL… roots home is arguably worse!

That’s where I (and prob a few other sysadmins?) put stuff, that’s “for root’s eyes only” precisely because it can’t be read without root permissions?

You can disconnect the home plug then. If manually disconnected, even a store override won’t budge it.

That snap will never get access to /root or /home without some serious exploits going on. (Except for e.g., /root/snap/qhttp/common, which is reserved purely for itself!)

For your own snap, with the daemon owning $SNAP_DATA, and writing purely to a known path, you can remove home entirely most likely, and would be a great example of the sandboxing working in full effect. The developer can avoid adding the interface and even the users can’t enable it.

But it’s enabled by default. autoconnect=on in your lingo?

and unless the sysadmin is prescient enough to anticipate this scenario, then the snap can just, during an automagic upgrade, create a new root daemon and start reading the “roots eyes only” content, and the sysadmin will never know…

I’d agree with this being a conceptual weakness, but the scenario required to exploit it seems to be people doing things 99% of people don’t do. I do recall there was a thread though that suggested the ability to deny interfaces regardless and in advance of installations so that you’d not have this problem, but unfortunately I don’t think it’s there yet.

Explicitly though, I can’t make the QHTTP snap suddenly start reading every users files even if I added home to it, I’d have to rely on changing the binary so that it scans and uploads when invoked by hand. Possible sure. Also likely to get me some nasty letters. And still going to not get me $HOME/.ssh/.

My question would be, what platform would stop that? Is snap worse or does it simply have a similar flaw the rest all do too here?

Every other platform has no sandboxing at all. So snaps sandboxing having weaknesses, whilst valid; is probably better than no sandbox at all.

(To be clear, I do generally still recommend people trust their publishers even in strict, because there will be loopholes in any system, trust can’t be eliminated entirely, but we can significantly stomp it out).

Now this is the more interesting practical part.

I am not sure we answered these questions above…

I am not sure how I could structure my snap, such that the user could use hibp-download to get a bunch of data, then manipulate it with something like hibp-topn, (both of these steps are interactive) and then starting a server to serve that content.

As I understand right now, it’s hard/impossible to get the files produced interactively across the snap boundary into $SNAP_DATA (which is “inside of snap & root only”, right?) so a “snap daemon” can serve it.

it’s the automatic upgrading and automatic starting of daemons, especially new ones, during these upgrades that worries me.

even compiling from source is MUCH safer. I can decide when to use sudo and/or run anything.

It’d probably involve rearchitecturing the app. For the interactive parts, can they be reprogrammed so that you could e.g., access the HTTP server, click a button, and invoke a download with a progress bar?

Ideally I’d say bundle the data, but, 40GB, probably not happening or desirable (especially given updates).

I’m thinking an ideal workflow for you might be

  1. User runs sudo snap install hibp
  2. The daemon kicks up automatically (Debian style). Now you’ve a choice as a developer on whether you think this needs authentication, which could be setting a password via e.g sudo snap set and having the user provide said password when accessing the webpage, or other various app level solutions.
  3. Removing the CLI entirely, but keeping the binaries doing the work, can the user click a button on the webpage that triggers the daemon into downloading the password databases on demand, as if they’d run the CLI directly instead.

Whilst then you’ve users controlling the root daemon, that’s a root daemon that’s most likely only going to have network and network-bind. You’ve predictable storage you can write to in well known paths, and this is implicitly shared now between every user on the system at the same time.

This would ultimately match how in Unix we end up with things like X11, PulseAudio, Pipewire, even snapd itself, with a client/server model where unprivileged clients can send requests to trusted daemons to process on their behalf. Except now you’ve also a nice sandbox on top.

not sure what you are referring to? What do 99% of people not do?

Store files in other peoples /home folder, especially /root.

I wouldn’t overthink that though, if that’s how you work, it makes sense to me to work that way. But it’s another weird quirk of Unix that there’s only one shared root user, unlike E.G., Windows where there can be many. The system is basically encouraging it to some degree.

If you made a /shared folder with root as owner and group though, then, home wouldn’t give access to it. Or you could do e.g., mkdir /root/shared && chown /root/shared admins, now root doesn’t own it, and the interface won’t work either.

I am root, it is my home. And yeah I share that with other people who have root. That’s appropriate. People who share root on a system need to trust each other. It’s good practice even, if I get run over by a bus, then the other roots still have root access and still have access to /root files.

The sort of things I personally store there, which I do think is reasonable, is documentation about how the system is built, notes on processes, stuff that like that. stuff that only root users would care about or should see.

This is all fine…

what is worrying for me as someone who has administered *nix systems for a while, is that my “normal understanding” of “where the walls are” appears to have significant holes in it, as soon as I install even a --strict snap.

Unfortunately, I feel the same for the entire stack (computers in general, not just snapd) to some degree.

It’s healthy to be concerned like that, but everything ultimately comes down to risks and rewards, otherwise we end up with Richard Stallman saying “the only secure database is the one that doesn’t exist”.

My mobile phone has a backdoor processor in the form of the mobile baseband and SIM card. It can take orders remotely, execute them on a second CPU the kernel doesn’t even know exists, whilst peeking into the RAM with Direct Memory Access. Android cannot defend against this at all.

Ultimately, I still need a phone.

This is not a webapp

the server is intended as a backend service for the authentication system of (typically) a website. It only has a single REST endpoint and answers with a single plain integer. Super super simple.

Effectively It just says… “this password is known to be compromised… or not”

Writing a whole admin webapp UI for that is prob not where I want to go.

So, I guess that means the snap daemon idea is out, and I just need to construct a service in the traditional OS dependent way. Put the files where I want, run the service as the user I want (with root or not), use the way of launching the service which I prefer for the OS I am on, etc…

I am totally fine with that, in fact I much prefer it, because it is much more transparent and trustworthy IMO. Just to clarify…