I'm trying to understand how Linux capabilities are passed to a process that has been exec()
'd by another one. From what I've read, in order for a capability to be kept after exec, it must be in the inheritable set. What I am not sure of, though, is how that set gets populated.
My goal is to be able to run a program as a regular user that would normally require root. The capability it needs is cap_dac_override
so it can read a private file. I do not want to give it any other capabilities.
Here's my wrapper:
#include <unistd.h>
int main(int argc, char *argv[]) {
return execl("/usr/bin/net", "net", "ads", "dns", "register", "-P", NULL);
}
This works when I set the setuid permission on the resulting executable:
~ $ sudo chown root: ./registerdns
~ $ sudo chmod u+s ./registerdns
~ $ ./registerdns
Successfully registered hostname with DNS
I would like to use capabilities instead of setuid, though. I've tried setting the cap_dac_override
capability on the wrapper:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
I've also tried setting the inheritable flag on the cap_dac_override
capability for the net
executable itself:
~ $ sudo setcap cap_dac_override=eip ./registerdns
~ $ sudo setcap cap_dac_override=i /usr/bin/net
~ $ ./registerdns
Failed to open /var/lib/samba/private/secrets.tdb
ERROR: Unable to open secrets database
I need to use the wrapper to ensure that the capability is only available when using that exact set of arguments; the net
program does several other things that could be dangerous to give users too broad of permissions on it.
I'm obviously misunderstanding how the inheritance works. I can't seem to figure out how to set up the wrapper to pass its capabilities along to the replacement process so it can use them. I've read the man page, and countless other documents on how it should work, and I thought I was doing what it describes.
Best Answer
It turns out that setting +i on the wrapper does not add the capability to the
CAP_INHERITABLE
set for the wrapper process, thus it is not passed throughexec
. I therefore had to manually addCAP_DAC_OVERRIDE
toCAP_INHERITABLE
before callingexecl
:In addition, I had to add
cap_dac_override
to the permitted file capabilities set on/usr/bin/net
and set the effective bit:I think I now fully understand what's happening:
CAP_DAC_OVERRIDE
in its permitted set so it can add it to its inheritable set.CAP_DAC_OVERRIDE
toCAP_INHERITABLE
usingcap_set_flag
/cap_set_proc
.net
file needs to haveCAP_DAC_OVERRIDE
in its inheritable set so that it can in fact inherit the capability from the wrapper into itsCAP_PERMITTED
set. It also needs the effective bit to be set so that it will be automatically promoted toCAP_EFFECTIVE
.