Drop capabilities if not running ip exec vrf with libcap
Subsystems (3)
RFC PATCH 1/1 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.
---
I'd like to be able to run ip vrf exec as a normal user, does this approach sound sensible? Any concerns? Are there any other alternatives? It would be up to each user/admin/whatever to make sure the program is built with libcap and to add the capabilities manually, so nothing will be there by default.
configure | 17 +++++++++++++++++ ip/ip.c | 34 ++++++++++++++++++++++++++++++++++ man/man8/ip-vrf.8 | 8 ++++++++ 3 files changed, 59 insertions(+)
configure +17 -0
@@ -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
ip/ip.c +34 -0
@@ -17,6 +17,10 @@#include <netinet/in.h> #include <string.h> #include <errno.h> +#include <sys/types.h> +#ifdef HAVE_LIBCAP +#include <sys/capability.h> +#endif #include "SNAPSHOT.h" #include "utils.h"
@@ -68,6 +72,24 @@ static int do_help(int argc, char **argv)return 0 ; } +static 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 +} + static const struct cmd { const char *cmd; int (*func)(int argc, char **argv);
@@ -174,6 +196,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 ];
man/man8/ip-vrf.8 +8 -0
@@ -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
Signature · 1 line
2.14.2
Quoted 8 lines · Luca Boccassi
ip vrf exec requires root or
CAP_NET_ADMIN,CAP_SYS_ADMINandCAP_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.
Quoted 8 lines
Signed-off-by Luca Boccassi <[email protected]>---
I'd like to be able to run ip vrf exec as a normal user, does this approach sound sensible? Any concerns? Are there any other alternatives? It would be up to each user/admin/whatever to make sure the program is built with libcap and to add the capabilities manually, so nothing will be there by default.
This is very similar to a change I recently made for our distribution. I created a separate 'runvrf' command so as to not contaminate 'ip' (the runvrf command has the limitation it can not configure the VRF cgroup so that needs to be done before runvrf).
Quoted 67 lines
configure | 17 +++++++++++++++++ ip/ip.c | 34 ++++++++++++++++++++++++++++++++++ man/man8/ip-vrf.8 | 8 ++++++++ 3 files changed, 59 insertions(+)configure +17
-0@@ -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 $@ $<' >> $CONFIGip/ip.c +11
-0@@ -17,6 +17,10 @@#include <netinet/in.h> #include <string.h> #include <errno.h> +#include <sys/types.h> +#ifdef HAVE_LIBCAP +#include <sys/capability.h> +#endif #include "SNAPSHOT.h" #include "utils.h" @@ -68,6 +72,24 @@ static int do_help(int argc, char **argv)return 0 ; } +static void drop_cap (void ) +{ +#ifdef HAVE_LIBCAP +/* don't harmstring root/sudo */ +if (getuid () !=0 &&geteuid () !=0 ) { +cap_t capabilities; + capabilities =cap_get_proc ();
ip/ip.c static int do_help(int argc, char **argv) · line 91
Quoted 10 lines
ip/ip.c +10
-0+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 +}
You don't need the capabilities after the cgroup has been changed, so you can add a call to drop_cap at the end of vrf_switch.
Quoted 43 lines
ip/ip.c +13
-0+ static const struct cmd { const char *cmd; int (*func)(int argc, char **argv);@@ -174,6 +196,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 ];man/man8/ip-vrf.8 +8
-0@@ -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
Quoted 22 lines · David Ahern
Quoted 12 lines · Luca Boccassi
ip vrf exec requires root or
CAP_NET_ADMIN,CAP_SYS_ADMINandCAP_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 <[email protected]>---
Quoted 8 lines
I'd like to be able to run ip vrf exec as a normal user, does this approach
sound sensible? Any concerns? Are there any other alternatives? It would be up to each user/admin/whatever to make sure the program is
built with libcap and to add the capabilities manually, so nothing will be
there by default.
Quoted 7 lines
This is very similar to a change I recently made for our distribution. I
created a separate 'runvrf' command so as to not contaminate 'ip' (the
runvrf command has the limitation it can not configure the VRF cgroup so
that needs to be done before runvrf).
Great, thanks for the feedback!
Quoted 75 lines
Quoted 75 lines
configure | 17 +++++++++++++++++
ip/ip.c | 34 ++++++++++++++++++++++++++++++++++ man/man8/ip-vrf.8 | 8 ++++++++3 files changed, 59 insertions(+)configure +0
-0@@ -336,6 +336,20 @@ EOFrm -f
$TMPDIR/strtest.c$TMPDIR/strtest
}configure +8
-0+check_cap() +{ + if ${PKG_CONFIG} libcap --exists + then + echo "HAVE_CAP:=y" >>$CONFIG + echo "yes" + + echo 'CFLAGS += -DHAVE_LIBCAP' `${PKG_CONFIG}libcap --cflags` >>$CONFIG
configure +1
-0+ echo 'LDLIBS +=' `${PKG_CONFIG} libcap --libs` >>$CONFIG
configure +5
-0+ else + echo "no" + fi +} +quiet_config()
{
cat <<EOFconfigure +0
-0@@ -410,6 +424,9 @@ check_berkeley_dbecho -n "need for strlcpy: "
check_strlcpyconfigure +3
-0+echo -n "libcap support: " +check_cap +echo >> $CONFIG
echo "%.o: %.c" >> $CONFIG
echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@
$<' >> $CONFIGip/ip.c +4
-0@@ -17,6 +17,10 @@ #include <netinet/in.h> #include <string.h> #include <errno.h> +#include <sys/types.h> +#ifdef HAVE_LIBCAP +#include <sys/capability.h> +#endif
#include "SNAPSHOT.h"
#include "utils.h"ip/ip.c +0
-0@@ -68,6 +72,24 @@ static int do_help(int argc, char **argv) return 0; }ip/ip.c +12
-0+static 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 )
Quoted 8 lines
ip/ip.c static int do_help(int argc, char **argv) · line 91
Quoted 5 lines
ip/ip.c +5
-0+exit (EXIT_FAILURE ); + cap_free(capabilities); + } +#endif +}You don't need the capabilities after the cgroup has been changed, so you can add a call to
drop_capat the end ofvrf_switch.
Ok, if Stephen finds the approach correct I'll send a v1 with that change (it shouldn't be strictly necessary as execvp which is ran just after vrf_switch drops caps, but it won't hurt either).
Signature · 2 lines
Kind regards, Luca Boccassi
Quoted 9 lines · On Tue, 27 Mar 2018 17:24:19 +0100 Luca Boccassi <[email protected]> wrote:
ip vrf exec requires root or
CAP_NET_ADMIN,CAP_SYS_ADMINandCAP_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 <[email protected]>
Gets a little messy, but don't have a better answer. When a command like iproute gets involved in security policy things I become concerned that it may have unexpected consequences.
Quoted 12 lines · Stephen Hemminger
Quoted 9 lines · On Tue, 27 Mar 2018 17:24:19 +0100 Luca Boccassi <[email protected]> wrote:
ip vrf exec requires root or
CAP_NET_ADMIN,CAP_SYS_ADMINandCAP_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.
Quoted 5 lines
Quoted 1 line
Signed-off-by Luca Boccassi <[email protected]>Gets a little messy, but don't have a better answer. When a command like iproute gets involved in security policy things I become concerned that it may have unexpected consequences.
Yeah I understand. It requires an explicit action by the sysadmin, to give you plausible deniability :-)
I've seen changes to let BPF permissions be managed via an LSM (I think SELinux support is already merged in 4.15), so perhaps one day we'll be able to do the whole shebang (subdir in /sys + load bpf + manipulate cgroup) in a more fine-grained way, but for now I think this will do.
I'll send v1 shortly with the change asked by David.
Signature · 2 lines
Kind regards, Luca Boccassi
PATCH 1/1 Drop capabilities if not running ip exec vrf with libcap
In reply to Luca Boccassiip 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.
---
Changes since RFC: moved drop_cap to lib/util.c to call it from ipvrf.c after vrf_switch, which is the function that requires the additional permissions, has finished.
configure | 17 +++++++++++++++++ include/utils.h | 2 ++ ip/ip.c | 12 ++++++++++++ ip/ipvrf.c | 2 ++ lib/utils.c | 21 +++++++++++++++++++++ man/man8/ip-vrf.8 | 8 ++++++++ 6 files changed, 62 insertions(+)
configure +17 -0
@@ -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
include/utils.h +2 -0
@@ -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__ */
ip/ip.c +12 -0
@@ -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 ];
ip/ipvrf.c +2 -0
@@ -436,6 +436,8 @@ out2: out:free (mnt); +drop_cap (); +return rc; }
lib/utils.c +21 -0
@@ -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"
@@ -1482,3 +1485,21 @@ 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 +}
man/man8/ip-vrf.8 +8 -0
@@ -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
Signature · 1 line
2.14.2
Stephen Hemminger
AppliedQuoted 9 lines · On Tue, 27 Mar 2018 18:48:55 +0100 Luca Boccassi <[email protected]> wrote:
ip vrf exec requires root or
CAP_NET_ADMIN,CAP_SYS_ADMINandCAP_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 <[email protected]>
Applied