4

Given a service that needs access to some secrets from a config file to start, I can imagine three approaches:

1) Keep the file readable only by root. Start the process as root, read the config and drop privileges.

2) Keep the file readable only by daemon user, start the process as the daemon user.

3) Keep the file readable only by root. Start the process as the daemon user with the CAP_DAC_READ_SEARCH capability and drop it after reading the config.

My initial analysis of the alternatives:

Option 1

+ If there's a vulnerability an attacker needs to read own process memory to get sensitive data (fairly hard?)

- More complex due to need for setuid/setgid

- If the software is compromised before dropping privileges it'll run as root

Option 2

+ simpler to program, drop privileges from init script

- If there's a vulnerability an attacker can read sensitive data from disk (easy)

Option 3

+ Never gives full root access to the process

+ If there's a bug an attacker would have to read process memory instead of just a file

- Plenty complex

- Still gives very broad access to reading files outside the config file (like /etc/shadow and similar)

Are there any other options that should be considered, or pros or cons I have missed? Are there any good reasons to handle privilege dropping yourself instead of letting the init process handle it?

thusoy
  • 143
  • 3
  • Option 2 with correct permissions (any of your sensitive data should not be readable by the user the app is running as) is the best. Short of a kernel exploit, your other files will be safe even if this particular process is compromised (but if the attacker uses a kernel exploit the other options won't save you either). – André Borie Feb 19 '17 at 07:49

1 Answers1

1

Avoid giving the daemon privileges it doesn't need, even for startup. This rules out option 1 and 3. It doesn't mean you have to go for option 2 though.

First let me recall the basics, just in case:

  • Run the daemon as a dedicated user, that runs this service only.
  • Don't allow the daemon to modify its configuration files. This means that all configuration files must be owned by a different user. Support for ACL is ubiquitous these days, so have root or some other user own the configuration files, and use an ACL to allow the daemon's user or group to read them.

Whether there's significant benefit to preventing the daemon to read sensitive configuration files after startup depends on what it uses the sensitive data for and what else it does. If these are credentials that the daemon uses only once during startup and then wipes from memory, there's a benefit to making it impossible to read them again later. If the sensitive data remains in memory there isn't that much benefit, but it also depends which is the most likely: an exploit that allows memory disclosure but not arbitrary code execution (e.g. uninitialized memory or bad pointer — although those usually do allow arbitrary code execution), or an exploit that allows file disclosure but dot arbitrary code execution (e.g. bad path sanitization).

If you decide that the protection of not allowing the daemon to read the sensitive file after startup is beneficial, then let the init system manage the privilege dropping. Open the configuration file from the supervisor process, then drop the associated privilege (a supplementary group, presumably), and pass the file descriptor to the process (--sensitive-config-fd=3 or --sensitive-config-file=/dev/fd/3).

Gilles 'SO- stop being evil'
  • 50,912
  • 13
  • 120
  • 179
  • There's a related situation which doesn't work with option 2, though: binding to privileged ports. Lots of commonly used network services run on ports below 1024, and you can't bind to those without administrative privileges. I'd argue that that's a place for the relevant capability, which can be dropped after binding. (I'm too lazy to look up which one exactly that is, though.) Or *maybe* you could have a small wrapper that only binds to the port and passes the file descriptor in a manner similar to that described in your last paragraph; I'm not sure if that would work or not. – user Feb 19 '17 at 12:26
  • @MichaelKjörling Binding privileged ports is commonly done through a wrapper, e.g. `tcpwrapper` does this and the service listens on the fd, just like what I suggest for the configuration file. – Gilles 'SO- stop being evil' Feb 19 '17 at 12:28
  • Ah, thanks for the tip on passing only the file descriptor, nice way to pass something that can be closed after use. – thusoy Feb 19 '17 at 19:05