From patchwork Tue Mar 27 17:48:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luca Boccassi X-Patchwork-Id: 891759 X-Patchwork-Delegate: shemminger@vyatta.com Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=debian.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 409dn53bMLz9ryk for ; Wed, 28 Mar 2018 04:49:29 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753101AbeC0RtZ (ORCPT ); Tue, 27 Mar 2018 13:49:25 -0400 Received: from mail-wr0-f196.google.com ([209.85.128.196]:39698 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752410AbeC0RtW (ORCPT ); Tue, 27 Mar 2018 13:49:22 -0400 Received: by mail-wr0-f196.google.com with SMTP id c24so23247035wrc.6 for ; Tue, 27 Mar 2018 10:49:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Q3nLjgPsOsob9meUMiZhWWayDTWOAJrz8cot7oIxyB8=; b=TS9vW7+si7gOVsfSgbzhYpP59NxaTauHKKI35buFJnNmhS1sSzaJrzIQKNOXdkH53I wvHhjf2wSQFkdBjPbbrUaSE90sjDgWfa6tDvJqI60talAKlFwNzDQOYY/r9oWBcICurR x5ezmP2WplxZ/RIxaHwVvOQTIq3Q16NL36OXGOTLCxNMLi7W3jdksV1TOeUMnLUysnZd i3FaYiUHn62cNCoL0UJK+UPAytMPrAPQT2CwQKrGg6pca3ji2i3jdLJZotbjk+MGQa+P tARSI2EYnhST8v2kuBmTrCxVrDi8F2eIvDJ2dsGKWfu/h3fDVaovFtKsVhJQI6suLGc4 G13A== X-Gm-Message-State: AElRT7FWiY2dRNh19Nf9UKhAex1AM5eHlrdCnf78dDKjxkPOrN8Qj9Xn kebgqfnEaxV634rjURLX/yEABBMa X-Google-Smtp-Source: AIpwx4/+4YY7zjW9P2LwFUagZ7KxS5rV9nGyTnlz2c3axO29376umaXCFq5tdDEUoAUk5n5oU/kinQ== X-Received: by 10.223.178.87 with SMTP id y23mr247175wra.95.1522172961259; Tue, 27 Mar 2018 10:49:21 -0700 (PDT) Received: from localhost ([2a00:23c5:be85:1400:6930:196b:56ac:33db]) by smtp.gmail.com with ESMTPSA id q90sm3952183wrb.6.2018.03.27.10.49.20 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Tue, 27 Mar 2018 10:49:20 -0700 (PDT) From: Luca Boccassi To: netdev@vger.kernel.org Cc: dsahern@gmail.com, luto@amacapital.net, stephen@networkplumber.org, Luca Boccassi Subject: [PATCH iproute2 v1] Drop capabilities if not running ip exec vrf with libcap Date: Tue, 27 Mar 2018 18:48:55 +0100 Message-Id: <20180327174855.30497-1-bluca@debian.org> X-Mailer: git-send-email 2.14.2 In-Reply-To: <20180327162419.8962-1-bluca@debian.org> References: <20180327162419.8962-1-bluca@debian.org> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org 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 --- 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(+) diff --git a/configure b/configure index f7c2d7a7..5ef5cd4c 100755 --- a/configure +++ b/configure @@ -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 <> $CONFIG echo "%.o: %.c" >> $CONFIG echo ' $(QUIET_CC)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $<' >> $CONFIG diff --git a/include/utils.h b/include/utils.h index 0394268e..e7bffe8a 100644 --- a/include/utils.h +++ b/include/utils.h @@ -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__ */ diff --git a/ip/ip.c b/ip/ip.c index e0cd96cb..e716fed8 100644 --- a/ip/ip.c +++ b/ip/ip.c @@ -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]; diff --git a/ip/ipvrf.c b/ip/ipvrf.c index f9277e1e..8a6b7f97 100644 --- a/ip/ipvrf.c +++ b/ip/ipvrf.c @@ -436,6 +436,8 @@ out2: out: free(mnt); + drop_cap(); + return rc; } diff --git a/lib/utils.c b/lib/utils.c index eba4fa74..d20cc594 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -30,6 +30,9 @@ #include #include #include +#ifdef HAVE_LIBCAP +#include +#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 +} diff --git a/man/man8/ip-vrf.8 b/man/man8/ip-vrf.8 index 18789339..1a42cebe 100644 --- a/man/man8/ip-vrf.8 +++ b/man/man8/ip-vrf.8 @@ -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