Reputation: 1693
I have a wrapper program, which is used only to add CAP_NET_RAW
capability to a nodejs script. The binary has set capabilities to cap_net_raw+eip
, but the process does not get them and setting them causes EPERM (Operation not permitted)
. The wrapper stopped working after upgrading from Debian 9 to 10. Adding the capability to nodejs binary works and the nodejs script runs fine, but it is not desired to allow raw access to network adapters to any nodejs script.
Here is the wrapper source code:
#include <sys/capability.h>
#include <unistd.h>
void main() {
cap_t caps = cap_get_proc();
cap_value_t newcaps[1] = { CAP_NET_RAW, };
cap_set_flag(caps, CAP_INHERITABLE, 1, newcaps, CAP_SET);
cap_set_proc(caps);
cap_free(caps);
execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
}
Running it under strace results in following:
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, NULL) = 0
capget({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=0}) = 0
capset({version=_LINUX_CAPABILITY_VERSION_3, pid=0}, {effective=0, permitted=0, inheritable=1<<CAP_NET_RAW}) = -1 EPERM (Operation not permitted)
Upvotes: 1
Views: 1090
Reputation: 1068
Too long for a comment, here is a more complete explanation.
First, file capabilities only work on binaries.
Let's call your wrapper program wrapper.c
(compiled as wrapper
). What it is coded to do is raise an Inheritable capability. The way Inheritable capabilities can cause a subsequently executed program to have privilege is they AND with the 'file Inheritable' capabilities on the executable.
That is, you could do this:
$ sudo setcap cap_net_raw=p ./wrapper
$ sudo setcap cap_net_raw=ie /usr/bin/node
Now, when you execute ./wrapper
it will raise an inheritable capability and when it execl()
s /usr/bin/node
the combination will inherit and raise the cap_net_raw
capabilitiy in the permitted and effective flags of the running /usr/bin/node
program.
If you don't use the ./wrapper
, you won't have the process-inheritable capability and /usr/bin/node
will not inherit any privilege.
Alternatively, you can clear those capabilities and modify your wrapper.c
to look like this:
#include <stdio.h>
#include <stdlib.h>
#include <sys/capability.h>
#include <unistd.h>
void main() {
cap_iab_t iab = cap_iab_from_text("^cap_net_raw");
if (iab == NULL) {
perror("iab not parsed");
exit(1);
}
if (cap_iab_set_proc(iab)) {
perror("unable to set iab");
exit(1);
}
cap_free(iab);
execl("/usr/bin/node", "node", "/opt/sitemp/sitemp.js", NULL);
perror("execl failed");
}
You will need to compile and set this version of wrapper
up as follows:
$ sudo setcap -r /usr/bin/node
$ cc -o wrapper wrapper.c -lcap
$ sudo setcap cap_net_raw,cap_setpcap=p ./wrapper
Now, when you run ./wrapper
it will raise both the Ambient and Inheritable capabilities and the combination will cause /usr/bin/node
to inherit some privilege directly from ./wrapper
.
Upvotes: 0