2

I am developing a daemon started by upstart (Ubuntu 14.04) which needs to run as a non-privileged user (for security), but bind privileged port 443.

I am using setcap to set the CAP_NET_BIND_SERVICE capability for the executable (it's not a script). I am setting it in Permitted, Effective, and Inherited sets (setcap 'cap_net_bind_service+eip' EXEC).

I can su to the non-privileged user, and run it directly, and it works perfectly. It correctly binds the port, and /proc/PID/status shows the proper capabilities masks with 0x400 bit set.

But when I start the service via upstart it does not run with the capabilities specified for the binary, and the bind() fails (EPERM). /proc/PID/status shows capabilities masks are all 0.

Any ideas?

1

I'm now thinking this is a bug, and related to the way upstart starts services with "expect daemon" (i.e. services that fork twice upon startup). I notice that if I use strace on a process that is using capabilities(7) the capabilities are also ignored. I suspect that upstart, in order to determine the PID to wait on, traces a service specified with "expect daemon" long enough to obtain the PID, and that's causing the kernel capabilities mechanism to fail. So the bug is in the way that capabilities interact with process tracing, and the fact that upstart uses process tracing when starting a service with "expect daemon" (this is supposition).

As a simple test:

  1. Write a small C PROGRAM to bind to port 443 (you cannot use an interpreted language such as python with capabilities(7)).
  2. Run it as non-root, and see that it fails to bind due to lack of privilege.
  3. Set the CAP_NET_BIND_SERVICE capability for your PROGRAM (as root run setcap 'cap_net_bind_service+epi' PROGRAM)
  4. Run it as non-root, and see that it now succeeds.
  5. Now run it with strace, and see that it now fails.

(note that in step 3 strictly speaking the Inherited capability set (i flag) does not need to be modified for this test, but it does for a process that forks() such as my daemon).

This behavior is necessary to avoid privilege exploits but makes Upstart behavior incompatible with Capabilities.

  • if capabilities worked while you're tracing the process, that would be a pretty trivial privilege escalation vulnerability. the kernel's behavior is not a bug, it's exactly right. – thejh Oct 15 '15 at 20:58
  • You're right. It's a bug in Upstart and/or its documentation. There is no indication that Upstart cannot handle daemons with capabilities set, yet due to the way it monitors execution in order to obtain the PID to watch, capabilities are unusable. I've modified my answer to reflect this. – BobDoolittle Oct 16 '15 at 18:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.