Granting a capability to a service

Steve Grubb sgrubb at redhat.com
Mon Jul 20 14:21:25 UTC 2015


On Saturday, July 18, 2015 10:42:43 AM Florian Weimer wrote:
> Let's assume I want to start a service as an ordinary user, but allow to
> bind it to a privileged port.  The program implementing the service does
> not manipulate capabilities in any way.
> 
> I came up with with this system unit for testing purposes:
> 
> [Unit]
> Description=Test unit
> 
> [Service]
> Type=oneshot
> ExecStart=/usr/sbin/getpcaps self
> Capabilities=cap_net_bind_service+ep
> SecureBits=keep-caps
> User=fweimer
> StandardOutput=journal
> 
> However, this does not work, the capability set remains empty.  Is there
> a way to achieve what I want?
> 
> The algorithm documented in capabilities(7) suggests that retaining
> effective capabilities across an execve system call absolutely requires
> file capabilities (the inheritable part).

No. You can start off as root, then change to your target uid retaining, then
open the socket. Just do it right away.


> The only way to bypass that
> if you perform the execve call with UID 0 (i.e., the literal UID 0, not
> a capability).

Using libcap-ng, its 3 lines of code. Assuming the desired uid is 500:

     capng_clear(CAPNG_SELECT_BOTH);
     capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_BIND_SERVICE);
     if (capng_change_id(500, 500, CAPNG_DROP_SUPP_GRP | CAPNG_CLEAR_BOUNDING))
         error();

-Steve

> This design is really odd because setting file capabilities always
> increases the attack surface (even if it is just the inheritable bits),
> and the only alternative appears to modify the service so that it is
> capability-aware and switches away from UID 0, and grant sufficient
> capabilities so that it can do so.  At that point, you can just skip the
> configuration in the systemd service and do everything capablity-related
> within the program.




More information about the devel mailing list