Drop capabilities if not running ip exec vrf with libcap

ip vrf exec requires root or CAP_NET_ADMIN, CAP_SYS_ADMIN and
CAP_DAC_OVERRIDE. It is not possible to run unprivileged commands like
ping as non-root or non-cap-enabled due to this requirement.
To allow users and administrators to safely add the required
capabilities to the binary, drop all capabilities on start if not
invoked with "vrf exec".
Update the manpage with the requirements.

Signed-off-by: Luca Boccassi <bluca@debian.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
Luca Boccassi 2018-03-27 18:48:55 +01:00 committed by Stephen Hemminger
parent b2038cc0b2
commit ba2fc55b99
6 changed files with 63 additions and 0 deletions

17
configure vendored
View File

@ -336,6 +336,20 @@ EOF
rm -f $TMPDIR/strtest.c $TMPDIR/strtest
}
check_cap()
{
if ${PKG_CONFIG} libcap --exists
then
echo "HAVE_CAP:=y" >>$CONFIG
echo "yes"
echo 'CFLAGS += -DHAVE_LIBCAP' `${PKG_CONFIG} libcap --cflags` >>$CONFIG
echo 'LDLIBS +=' `${PKG_CONFIG} libcap --libs` >> $CONFIG
else
echo "no"
fi
}
quiet_config()
{
cat <<EOF
@ -410,6 +424,9 @@ check_berkeley_db
echo -n "need for strlcpy: "
check_strlcpy
echo -n "libcap support: "
check_cap
echo >> $CONFIG
echo "%.o: %.c" >> $CONFIG
echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> $CONFIG

View File

@ -299,4 +299,6 @@ size_t strlcpy(char *dst, const char *src, size_t size);
size_t strlcat(char *dst, const char *src, size_t size);
#endif
void drop_cap(void);
#endif /* __UTILS_H__ */

12
ip/ip.c
View File

@ -174,6 +174,18 @@ int main(int argc, char **argv)
char *batch_file = NULL;
int color = 0;
/* to run vrf exec without root, capabilities might be set, drop them
* if not needed as the first thing.
* execv will drop them for the child command.
* vrf exec requires:
* - cap_dac_override to create the cgroup subdir in /sys
* - cap_sys_admin to load the BPF program
* - cap_net_admin to set the socket into the cgroup
*/
if (argc < 3 || strcmp(argv[1], "vrf") != 0 ||
strcmp(argv[2], "exec") != 0)
drop_cap();
basename = strrchr(argv[0], '/');
if (basename == NULL)
basename = argv[0];

View File

@ -436,6 +436,8 @@ out2:
out:
free(mnt);
drop_cap();
return rc;
}

View File

@ -30,6 +30,9 @@
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#ifdef HAVE_LIBCAP
#include <sys/capability.h>
#endif
#include "rt_names.h"
#include "utils.h"
@ -1495,3 +1498,22 @@ size_t strlcat(char *dst, const char *src, size_t size)
return dlen + strlcpy(dst + dlen, src, size - dlen);
}
#endif
void drop_cap(void)
{
#ifdef HAVE_LIBCAP
/* don't harmstring root/sudo */
if (getuid() != 0 && geteuid() != 0) {
cap_t capabilities;
capabilities = cap_get_proc();
if (!capabilities)
exit(EXIT_FAILURE);
if (cap_clear(capabilities) != 0)
exit(EXIT_FAILURE);
if (cap_set_proc(capabilities) != 0)
exit(EXIT_FAILURE);
cap_free(capabilities);
}
#endif
}

View File

@ -63,6 +63,14 @@ a VRF other than the default VRF (main table). A command can be run against
the default VRF by passing the "default" as the VRF name. This is useful if
the current shell is associated with another VRF (e.g, Management VRF).
This command requires the system to be booted with cgroup v2 (e.g. with systemd,
add systemd.unified_cgroup_hierarchy=1 to the kernel command line).
This command also requires to be ran as root or with the CAP_SYS_ADMIN,
CAP_NET_ADMIN and CAP_DAC_OVERRIDE capabilities. If built with libcap and if
capabilities are added to the ip binary program via setcap, the program will
drop them as the first thing when invoked, unless the command is vrf exec.
.TP
.B ip vrf identify [PID] - Report VRF association for process
.sp