Achieving the same thing via libcap
is actually not that much code:
#include <stdio.h>
#include <sys/capability.h>
int main(int arc, char *argv[]) {
cap_t c = cap_from_text("cap_sys_rawio=ep");
int status = cap_set_file("./bench", c);
cap_free(c);
if (status)
perror("attempt failed");
return status != 0;
}
To compile this (on debian, you'll need to sudo apt-get install libcap-dev
; on fedora, sudo dnf install libcap-devel
):
$ gcc -o mkcap mkcap.c -lcap
If you just run it as is, it will fail since the program needs to have sufficient privilege to actually add the capability to ./bench
:
$ ./mkcap
attempt failed: Operation not permitted
So, you need to make it sufficiently capable itself:
$ sudo /sbin/setcap cap_setfcap=ep ./mkcap
$ ./mkcap
$ echo $?
0
- You might want to consider being more explicit with the path to the
"./bench"
binary since, depending on your environment, you might worry that someone could abuse mkcap
to give cap_sys_rawio
to some other program. Using a full pathname would be less ambiguous.
- You could also
chmod go-x ./mkcap
to limit who can run it.
- You could also consider using inheritable capabilities for all this:
basic $ sudo setcap cap_setfcap=ei ./mkcap
basic $ ./mkcap
attempt failed: Operation not permitted
basic $ sudo capsh --inh=cap_setfcap --user=$(whoami) --
enhanced $ ./mkcap
enhanced $ echo $?
0
In the enhanced
(capsh shell) layer you are able to raise that capability on binaries that have their file inheritable bit set. This way, the default basic
layer shells can't get any privilege out of mkcap
. In all other ways, the enhanced
shell layer is identical to a basic
layer. For example, you can execute builds and pretty much do things as normal. (Use exit
to leave the enhanced
shell.)
There is a pam_cap
module that can also add an inheritable bit to all shells of specific users at login etc time.