If your program executes with effective user ID root, then you do have root privileges.
In Linux, capabilities are divided into three sets: inheritable, permitted, and effective. Inheritable defines which capabilities stay permitted across an exec()
. Permitted defines which capabilities are permitted for a process. Effective defines which capabilities are currently in effect.
Edited to add: When the filesystem containing the binary that will be exec()
'd does support filesystem capabilities, these always affect what capabilities the executed process will have. See the Transformation of capabilities during an execve()
in the man 7 capabilities man page.
When changing the owner or group of a process from root to non-root, the effective capability set is always cleared. By default, also the permitted capability set is cleared, but calling prctl(PR_SET_KEEPCAPS, 1L)
before the identity change tells the kernel to keep the permitted set intact.
Therefore, to have the CAP_NET_RAW
capability, your program has to have it in both permitted and effective sets. If you wish for the CAP_NET_RAW
to remain in effect over an exec()
, it must be included in all three capability sets.
Edited to add: If file capabilities are supported for the target of the exec()
, the file capabilities must also contain those capabilities in the inherited and effective sets. (Only including the capability in the inherited and effective sets does not grant the capability, since it's not in the permitted set in the file capabilities; but, it is enough to allow passing the capability from the executor to the execee, if the executor has the capability).
You can use the setcap
command to grant specific capabilities to a binary. (Most Linux filesystems nowadays support these file capabilities.) It does not need to be privileged, or setuid. Just remember to add the desired capabilities to both permitted and effective sets.
Edited to add some examples:
Grant CAP_NET_RAW
to /usr/bin/myprog
(which must NOT be setuid or setgid root):
sudo setcap 'cap_net_raw=pe' /usr/bin/myprog
By default, do not grant CAP_NET_RAW
to /usr/bin/myprog
, but if the executor has the capability (in both inheritable and permitted sets), retain the capability (in inheritable and permitted sets, and activating it in the effective set):
sudo setcap 'cap_net_raw=ie' /usr/bin/myprog
If your program has to be setuid root anyway, then you can use e.g.
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/types.h>
#include <sys/capability.h>
#include <sys/prctl.h>
#define NEED_CAPS 1
static const cap_value_t need_caps[NEED_CAPS] = { CAP_NET_RAW };
int main(void)
{
uid_t real = getuid();
cap_t caps;
/* Elevate privileges */
if (setresuid(0, 0, 0))
return 1; /* Fatal error, probably not setuid root */
/* Add need_caps to current capabilities. */
caps = cap_get_proc();
if (cap_set_flag(caps, CAP_PERMITTED, NEED_CAPS, need_caps, CAP_SET) ||
cap_set_flag(caps, CAP_EFFECTIVE, NEED_CAPS, need_caps, CAP_SET) ||
cap_set_flag(caps, CAP_INHERITABLE, NEED_CAPS, need_caps, CAP_SET))
return 1; /* Fatal error */
/* Update capabilities */
if (cap_set_proc(caps))
return 1; /* Fatal error */
/* Retain capabilities over an identity change */
if (prctl(PR_SET_KEEPCAPS, 1L))
return 1; /* Fatal error */
/* Return to original, real-user identity */
if (setresuid(real, real, real))
return 1; /* Fatal error */
/* Because the identity changed, we need to
* re-install the effective set. */
if (cap_set_proc(caps))
return 1; /* Fatal error */
/* Capability set is no longer needed. */
cap_free(caps);
/* You now have the CAP_NET_RAW capability.
* It will be retained over fork() and exec().
*/
return 0;
}