Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drop privileges as regular non-root user for sandboxing?

Is it possible to use a set of C library or system calls to drop all user privileges on POSIX, or at least on Linux? Note that I am not asking how to drop root privileges, which is what all of the other StackOverflow search results seem to be asking and answering.

I want the same effect as switching to user nobody, but stronger if possible. That is, I want my C application to do the following:

  • Run as a normal user, not root, and without the setuid file permission bit
  • Retain the ability to access specific files and open outgoing network connections
  • Voluntarily and permanently lose the ability to read and write files in specified (or all) directories, especially $HOME
  • If possible, give up or sandbox all other nonessential abilities, like opening a listening socket with accept

Things I have considered so far that don't fit the bill:

  • Switching to user nobody with setuid/setgid
    • Ordinary users are forbidden from switching to other users (like nobody), and the application should not require root just to switch to nobody.
  • Linux/POSIX.1e Capabilities
    • Capabilities only add root-like privileges, not take away ordinary user privileges
  • Traditional seccomp
    • My application will need more than just exit, sigreturn, read, and write

Things that look interesting, but for which I couldn't find documentation, appear to be unmaintained, or appear to be non-portable:

  • seccomp-bpf
  • AppArmor
  • grsecurity RBAC/role-based access control

So is there a well-documented, preferably portable way to drop nonessential user privileges and sandbox a process without having to become root first?

like image 993
nitrogen Avatar asked Oct 19 '22 07:10

nitrogen


1 Answers

It's unlikely any solution will work on all POSIX, since POSIX doesn't define the mechanism you're looking for.

Looking at just the requirements and just Linux, probably the easiest way to satisfy them is actual via the security modules. Any of apparmor, selinux, RBAC will do what you need, but only via external profile - not something built into your app. The problem may be that adding a profile in all those cases requires the root user to do it (but the profile applies to user process too).

A bit more complicated solution that almost satisfies the requirements is seccomp. While it doesn't understand paths at all (you can only see pointers), there are ways to limit the access: seccomp policies can be defined per thread, so you could redesign your system to have a "path verification thread", which doesn't do anything apart from reading paths and returning sockets if they match your specification. Then limit that thread to just recv(), open() and send(). Thread doing other work can then drop open() and use the other service.

Or if you can configure the paths at program startup, you can put them into an array, mark that page as read-only, and setup seccomp policy which will only accept open() with filenames from that array (that's just a pointer comparison in that case).

To some extent, the approach of splitting application into separate processes which have very limited responsibilities is something you could replicate on other systems, but without the same guarantees as on Linux. For example qmail is kind of a system of very small processes which work as a pipeline for data (simplification). On Linux you could still apply seccomp to them, on Solaris just drop exec and other capabilities, on other systems... I don't know, but probably you can do something.

like image 77
viraptor Avatar answered Oct 22 '22 01:10

viraptor