From patchwork Wed Apr 29 14:45:04 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279442 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=isovalent.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=isovalent-com.20150623.gappssmtp.com header.i=@isovalent-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=wUbi7mkp; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49C1Wv37vTz9sSM for ; Thu, 30 Apr 2020 00:45:15 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726773AbgD2OpO (ORCPT ); Wed, 29 Apr 2020 10:45:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35602 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726456AbgD2OpN (ORCPT ); Wed, 29 Apr 2020 10:45:13 -0400 Received: from mail-wm1-x344.google.com (mail-wm1-x344.google.com [IPv6:2a00:1450:4864:20::344]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 554D3C035493 for ; Wed, 29 Apr 2020 07:45:12 -0700 (PDT) Received: by mail-wm1-x344.google.com with SMTP id u127so2335339wmg.1 for ; Wed, 29 Apr 2020 07:45:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=isovalent-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=aRCfBdadPVTEiQclG9/KJeo/s7dbbAmCdTeG8F+tkxA=; b=wUbi7mkpnNEN5zj8+u1ht0k7eGCD4TBzIziguxbHRtKxdpq702xSX1p0yi+H7Pmy79 q/QyCXAMqlHh4OFoXREH9QVKGlfkidf+KNl7b7jbaYtb1Bd8nOggBQMOEsv3lREyI6MW S+7FutxSUe65+1EuBYmtb3vz9fb9y7lhiCkrT/nwY5jvx5v1qB9dfDTgsDx5FFdRhDyv HnxWsvajaIw9XWTics3PDB5GNkOnrIuwyfHNQcWrFYwW9eSZmR1z1ggpiD1xCEj6w/SC fPJKmK0cqSXBLtBrSCLvsKgdN7OPIYMha/rtVR7BpOjShPQWAZs76TUSlzcTdivjTeOj Rs2A== 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:mime-version:content-transfer-encoding; bh=aRCfBdadPVTEiQclG9/KJeo/s7dbbAmCdTeG8F+tkxA=; b=lZkBJVPJhQleyKaBVuFVdR5StnjXDt2uTd2wB0NBzIpCGyiQyRVWKVs3IZiZ5YlBdN 9eLCtm9mxJYDmNN1rzpR45Y0aFzhHtBhxrvFrRC5m9L0oB68qh96OOnIEWqGb6CqUsuv qSrYuHXxeYPwfp5iLfIBvKrRuZ6VXxCpfQcMZRugxJkFJDZ4qf3qKG3B7KsI2665v0/y sspJR3cLJOS5ykTdPuRqwIgVThMJgxg518erKCnsKifuy95iwI6aTHAOL5B6fDYeJbVA +/aI3mrO9Q3JClBG8/wbB+hXo+TerjOXyZWN904GSpP8b2Hnw3f6A0n0NfBYMOpZtdNq e2Hw== X-Gm-Message-State: AGi0Pua6fK259k9Z3Rme/yiygGUfnh+TFS8byVSIhPhgJ+P18qYpxLgV dYM+bAMgCOM94kLqZ7doK6aNxRvKvHw= X-Google-Smtp-Source: APiQypLwdrvK53EjnxC1heRJ+0O+lYXa9rz26GtDEw4NdoFZtPrvL2dF2E9fefS7WeDR/I3BG2Pkfw== X-Received: by 2002:a05:600c:441a:: with SMTP id u26mr3883647wmn.154.1588171511003; Wed, 29 Apr 2020 07:45:11 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id a10sm20071739wrg.32.2020.04.29.07.45.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 07:45:10 -0700 (PDT) From: Quentin Monnet To: Alexei Starovoitov , Daniel Borkmann Cc: bpf@vger.kernel.org, netdev@vger.kernel.org, Quentin Monnet , Richard Palethorpe , Michael Kerrisk Subject: [PATCH bpf-next v3 1/3] tools: bpftool: for "feature probe" define "full_mode" bool as global Date: Wed, 29 Apr 2020 15:45:04 +0100 Message-Id: <20200429144506.8999-2-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429144506.8999-1-quentin@isovalent.com> References: <20200429144506.8999-1-quentin@isovalent.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The "full_mode" variable used for switching between full or partial feature probing (i.e. with or without probing helpers that will log warnings in kernel logs) was piped from the main do_probe() function down to probe_helpers_for_progtype(), where it is needed. Define it as a global variable: the calls will be more readable, and if other similar flags were to be used in the future, we could use global variables as well instead of extending again the list of arguments with new flags. Signed-off-by: Quentin Monnet --- tools/bpf/bpftool/feature.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 88718ee6a438..59e4cb44efbc 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -35,6 +35,8 @@ static const char * const helper_name[] = { #undef BPF_HELPER_MAKE_ENTRY +static bool full_mode; + /* Miscellaneous utility functions */ static bool check_procfs(void) @@ -540,8 +542,7 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, static void probe_helpers_for_progtype(enum bpf_prog_type prog_type, bool supported_type, - const char *define_prefix, bool full_mode, - __u32 ifindex) + const char *define_prefix, __u32 ifindex) { const char *ptype_name = prog_type_name[prog_type]; char feat_name[128]; @@ -678,8 +679,7 @@ static void section_map_types(const char *define_prefix, __u32 ifindex) } static void -section_helpers(bool *supported_types, const char *define_prefix, - bool full_mode, __u32 ifindex) +section_helpers(bool *supported_types, const char *define_prefix, __u32 ifindex) { unsigned int i; @@ -704,8 +704,8 @@ section_helpers(bool *supported_types, const char *define_prefix, define_prefix, define_prefix, define_prefix, define_prefix); for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++) - probe_helpers_for_progtype(i, supported_types[i], - define_prefix, full_mode, ifindex); + probe_helpers_for_progtype(i, supported_types[i], define_prefix, + ifindex); print_end_section(); } @@ -725,7 +725,6 @@ static int do_probe(int argc, char **argv) enum probe_component target = COMPONENT_UNSPEC; const char *define_prefix = NULL; bool supported_types[128] = {}; - bool full_mode = false; __u32 ifindex = 0; char *ifname; @@ -803,7 +802,7 @@ static int do_probe(int argc, char **argv) goto exit_close_json; section_program_types(supported_types, define_prefix, ifindex); section_map_types(define_prefix, ifindex); - section_helpers(supported_types, define_prefix, full_mode, ifindex); + section_helpers(supported_types, define_prefix, ifindex); section_misc(define_prefix, ifindex); exit_close_json: From patchwork Wed Apr 29 14:45:05 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279446 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=isovalent.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=isovalent-com.20150623.gappssmtp.com header.i=@isovalent-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=fiecpfI8; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49C1X031zxz9sP7 for ; Thu, 30 Apr 2020 00:45:20 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726840AbgD2OpT (ORCPT ); Wed, 29 Apr 2020 10:45:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35608 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726556AbgD2OpO (ORCPT ); Wed, 29 Apr 2020 10:45:14 -0400 Received: from mail-wr1-x442.google.com (mail-wr1-x442.google.com [IPv6:2a00:1450:4864:20::442]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 819B7C08E859 for ; Wed, 29 Apr 2020 07:45:13 -0700 (PDT) Received: by mail-wr1-x442.google.com with SMTP id d15so2883691wrx.3 for ; Wed, 29 Apr 2020 07:45:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=isovalent-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1pb24uR21VUp2hP8cBfznro73d21AmZJyr3yv94fFwc=; b=fiecpfI8clFN5Z0FzTo0DpVc6f+SEaGEsHeOhU1ErsmCHxViSsoXpmk3loess4FWBn LH75L8fAQSZ/QmP98vbrd1/gDXNaJJCbwOHGrjCtAbw97QqDdT2mHnSznee00j+t90D2 Ubaczyg7snsEbfpCgXkzlO22SK6jECIacwbmGN1G8I8FR1daUElyQWw5RsVBTAnjjrkW UqpBdcLLUoEB3imfMJHz0GRIlS75zKB11/1OWgsOqmrKabULOcdpLIuLAcDi3DdRCTwl tmvvrK3HEnTCK7bjJ1hfUCBlqOXCwkl8FJtFC7SHlqcOpvmJfLeAUOIwNW+Bzu/HnGzT D+qg== 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:mime-version:content-transfer-encoding; bh=1pb24uR21VUp2hP8cBfznro73d21AmZJyr3yv94fFwc=; b=tF8eaxcr3+R3cqXTr10BC+xXOC/Cvd2kbyLRkGcptnECeJ8B9+fT2C85yl37NP1yBg +FN/aMfQJUj6bi/86fsPDb1u/4oFbvkm8PJVQjogwKh6nLAMqEqUxpJOtng8rLRiyP1g L+ENQugMXBHPKUMv1wasMB49SvbV11SD8rhnnV3IhXzoJpSACFWafPLbb+sm/BKMRLsz Fh54+ZzLLRap8s4f9IoEAaitv7ykLH3LBNdudbAji94aP7QK4+uQQkEL4znTBBWC4i27 IwVUkL3zKxIvaaNmJBI13zjv+LLeHrRY34WrdD72efyFPsZzYfcuGXz4+E5qN4xlh/Zm N4TA== X-Gm-Message-State: AGi0PuZ3dKophXT4hLH72d/CyhT+2enon0RYwP4/8xZ79RSEqAQXwm6J M+s1FbHMrm+NHBb4dtZqrqLXlQ== X-Google-Smtp-Source: APiQypJ7pnQNRJFUjwKAVrPErbXIgDwzJbeOExZJS0w0O0LQ/aBH549HfMbteYxcE0hcqe4SJ0p8Og== X-Received: by 2002:a5d:6145:: with SMTP id y5mr38936686wrt.126.1588171512113; Wed, 29 Apr 2020 07:45:12 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id a10sm20071739wrg.32.2020.04.29.07.45.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 07:45:11 -0700 (PDT) From: Quentin Monnet To: Alexei Starovoitov , Daniel Borkmann Cc: bpf@vger.kernel.org, netdev@vger.kernel.org, Quentin Monnet , Richard Palethorpe , Michael Kerrisk Subject: [PATCH bpf-next v3 2/3] tools: bpftool: allow unprivileged users to probe features Date: Wed, 29 Apr 2020 15:45:05 +0100 Message-Id: <20200429144506.8999-3-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429144506.8999-1-quentin@isovalent.com> References: <20200429144506.8999-1-quentin@isovalent.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org There is demand for a way to identify what BPF helper functions are available to unprivileged users. To do so, allow unprivileged users to run "bpftool feature probe" to list BPF-related features. This will only show features accessible to those users, and may not reflect the full list of features available (to administrators) on the system. To avoid the case where bpftool is inadvertently run as non-root and would list only a subset of the features supported by the system when it would be expected to list all of them, running as unprivileged is gated behind the "unprivileged" keyword passed to the command line. When used by a privileged user, this keyword allows to drop the CAP_SYS_ADMIN and to list the features available to unprivileged users. Note that this addsd a dependency on libpcap for compiling bpftool. Note that there is no particular reason why the probes were restricted to root, other than the fact I did not need them for unprivileged and did not bother with the additional checks at the time probes were added. Signed-off-by: Quentin Monnet --- .../bpftool/Documentation/bpftool-feature.rst | 10 +- tools/bpf/bpftool/Makefile | 2 +- tools/bpf/bpftool/bash-completion/bpftool | 2 +- tools/bpf/bpftool/feature.c | 102 +++++++++++++++--- 4 files changed, 100 insertions(+), 16 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index b04156cfd7a3..ca085944e4cf 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -19,7 +19,7 @@ SYNOPSIS FEATURE COMMANDS ================ -| **bpftool** **feature probe** [*COMPONENT*] [**full**] [**macros** [**prefix** *PREFIX*]] +| **bpftool** **feature probe** [*COMPONENT*] [**full**] [**unprivileged**] [**macros** [**prefix** *PREFIX*]] | **bpftool** **feature help** | | *COMPONENT* := { **kernel** | **dev** *NAME* } @@ -49,6 +49,14 @@ DESCRIPTION Keyword **kernel** can be omitted. If no probe target is specified, probing the kernel is the default behaviour. + When the **unprivileged** keyword is used, bpftool will dump + only the features available to a user who does not have the + **CAP_SYS_ADMIN** capability set. The features available in + that case usually represent a small subset of the parameters + supported by the system. Unprivileged users MUST use the + **unprivileged** keyword: This is to avoid misdetection if + bpftool is inadvertently run as non-root, for example. + **bpftool feature probe dev** *NAME* [**full**] [**macros** [**prefix** *PREFIX*]] Probe network device for supported eBPF features and dump results to the console. diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index f584d1fdfc64..89d7962a4a44 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -55,7 +55,7 @@ ifneq ($(EXTRA_LDFLAGS),) LDFLAGS += $(EXTRA_LDFLAGS) endif -LIBS = $(LIBBPF) -lelf -lz +LIBS = $(LIBBPF) -lelf -lz -lcap INSTALL ?= install RM ?= rm -f diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool index c033c3329f73..fc989ead7313 100644 --- a/tools/bpf/bpftool/bash-completion/bpftool +++ b/tools/bpf/bpftool/bash-completion/bpftool @@ -1079,7 +1079,7 @@ _bpftool() COMPREPLY+=( $( compgen -W 'macros' -- "$cur" ) ) fi _bpftool_one_of_list 'kernel dev' - _bpftool_once_attr 'full' + _bpftool_once_attr 'full unprivileged' return 0 ;; *) diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 59e4cb44efbc..952f4b1987c0 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ static const char * const helper_name[] = { #undef BPF_HELPER_MAKE_ENTRY static bool full_mode; +static bool run_as_unprivileged; /* Miscellaneous utility functions */ @@ -473,6 +475,11 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, } res = bpf_probe_prog_type(prog_type, ifindex); + /* Probe may succeed even if program load fails, for unprivileged users + * check that we did not fail because of insufficient permissions + */ + if (run_as_unprivileged && errno == EPERM) + res = false; supported_types[prog_type] |= res; @@ -501,6 +508,10 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix, res = bpf_probe_map_type(map_type, ifindex); + /* Probe result depends on the success of map creation, no additional + * check required for unprivileged users + */ + maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1; if (strlen(map_type_name[map_type]) > maxlen) { p_info("map type name too long"); @@ -520,12 +531,17 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, const char *define_prefix, unsigned int id, const char *ptype_name, __u32 ifindex) { - bool res; + bool res = false; - if (!supported_type) - res = false; - else + if (supported_type) { res = bpf_probe_helper(id, prog_type, ifindex); + /* Probe may succeed even if program load fails, for + * unprivileged users check that we did not fail because of + * insufficient permissions + */ + if (run_as_unprivileged && errno == EPERM) + res = false; + } if (json_output) { if (res) @@ -720,6 +736,65 @@ static void section_misc(const char *define_prefix, __u32 ifindex) print_end_section(); } +static int handle_perms(void) +{ + cap_value_t cap_list[1] = { CAP_SYS_ADMIN }; + bool has_sys_admin_cap = false; + cap_flag_value_t val; + int res = -1; + cap_t caps; + + caps = cap_get_proc(); + if (!caps) { + p_err("failed to get capabilities for process: %s", + strerror(errno)); + return -1; + } + + if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val)) { + p_err("bug: failed to retrieve CAP_SYS_ADMIN status"); + goto exit_free; + } + if (val == CAP_SET) + has_sys_admin_cap = true; + + if (!run_as_unprivileged && !has_sys_admin_cap) { + p_err("full feature probing requires CAP_SYS_ADMIN, run as root or use 'unprivileged'"); + goto exit_free; + } + + if ((run_as_unprivileged && !has_sys_admin_cap) || + (!run_as_unprivileged && has_sys_admin_cap)) { + /* We are all good, exit now */ + res = 0; + goto exit_free; + } + + /* if (run_as_unprivileged && has_sys_admin_cap), drop CAP_SYS_ADMIN */ + + if (cap_set_flag(caps, CAP_EFFECTIVE, ARRAY_SIZE(cap_list), cap_list, + CAP_CLEAR)) { + p_err("bug: failed to clear CAP_SYS_ADMIN from capabilities"); + goto exit_free; + } + + if (cap_set_proc(caps)) { + p_err("failed to drop CAP_SYS_ADMIN: %s", strerror(errno)); + goto exit_free; + } + + res = 0; + +exit_free: + if (cap_free(caps) && !res) { + p_err("failed to clear storage object for capabilities: %s", + strerror(errno)); + res = -1; + } + + return res; +} + static int do_probe(int argc, char **argv) { enum probe_component target = COMPONENT_UNSPEC; @@ -728,14 +803,6 @@ static int do_probe(int argc, char **argv) __u32 ifindex = 0; char *ifname; - /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). - * Let's approximate, and restrict usage to root user only. - */ - if (geteuid()) { - p_err("please run this command as root user"); - return -1; - } - set_max_rlimit(); while (argc) { @@ -784,6 +851,9 @@ static int do_probe(int argc, char **argv) if (!REQ_ARGS(1)) return -1; define_prefix = GET_ARG(); + } else if (is_prefix(*argv, "unprivileged")) { + run_as_unprivileged = true; + NEXT_ARG(); } else { p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", *argv); @@ -791,6 +861,12 @@ static int do_probe(int argc, char **argv) } } + /* Full feature detection requires CAP_SYS_ADMIN privilege. + * Let's approximate, and warn if user is not root. + */ + if (handle_perms()) + return -1; + if (json_output) { define_prefix = NULL; jsonw_start_object(json_wtr); @@ -821,7 +897,7 @@ static int do_help(int argc, char **argv) } fprintf(stderr, - "Usage: %s %s probe [COMPONENT] [full] [macros [prefix PREFIX]]\n" + "Usage: %s %s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n" " %s %s help\n" "\n" " COMPONENT := { kernel | dev NAME }\n" From patchwork Wed Apr 29 14:45:06 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279443 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=isovalent.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=isovalent-com.20150623.gappssmtp.com header.i=@isovalent-com.20150623.gappssmtp.com header.a=rsa-sha256 header.s=20150623 header.b=Cu8Xcoo9; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49C1Wx3m6cz9sP7 for ; Thu, 30 Apr 2020 00:45:17 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726800AbgD2OpQ (ORCPT ); Wed, 29 Apr 2020 10:45:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:35616 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726456AbgD2OpP (ORCPT ); Wed, 29 Apr 2020 10:45:15 -0400 Received: from mail-wr1-x443.google.com (mail-wr1-x443.google.com [IPv6:2a00:1450:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AAB17C03C1AE for ; Wed, 29 Apr 2020 07:45:14 -0700 (PDT) Received: by mail-wr1-x443.google.com with SMTP id k1so2879049wrx.4 for ; Wed, 29 Apr 2020 07:45:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=isovalent-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=DPPOrgBA7YSTdrd+i7ZC6pH/Ktq+pTutZ/a9hfmxBNY=; b=Cu8Xcoo9BIhJUKO3/OO3pntl2jZytTlHH0vNoLfclyIkpyfmN0/woDWnHUoL90J2a7 Dz1G+jhB/GC3ifPy/XfZ3vTXx+roQEZnywH2ztQ7jIZYAXsGIzhKdUIrFe3MgjGqePBq 4KxzIt20q37UWrtNKnmY1g5BfJBiunqlcAt2WzQF7F6yY0drXmTPFEIKsEHTPrfisxik BPfHtRewNFGrYibuVMlKgtavgQVoJPh/K9dRABeXx6n89ZuMtjxLTxKwVvoUhdo4ldfp Sf6fBG4ANITGVNDeJezePBBiRFQCrbRjvAm0xjIao+H36fhEHZK4gwh9wjYjIO0tYLyF 75Kg== 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:mime-version:content-transfer-encoding; bh=DPPOrgBA7YSTdrd+i7ZC6pH/Ktq+pTutZ/a9hfmxBNY=; b=XEKEffmMYXZYf30wbbNDJtSCk/+cNbLJxN+sedgIXMhuUJYtvTomvDq0Ro7SEzY1e+ g84nJJOzEyc1lVFZjx4IXTCkkbBz+Em5Jvr7tYfYX04lJKXgCt6OBoHViWz6lmun2QCi fD5BdD+LFHedONeQD7dUoqzikt1EWi661vn9LomdLs/6osMa27e3IIDKA4aHWVPKVaHV QFxLETP6ojHTYxn/aI+xrfRSs9lleGcohe3mbmGVOnDIUBFiKwtN2qq/HOSUGVivyR17 IZ20E1QESPZOcSuoM99CmhPcWiEjffNPMA2/Mi0dAjCj08jYWmNWT9UNuDkCDE9IqsIr ppjg== X-Gm-Message-State: AGi0PuYbQVPcxJQKwE/MUmqUSjTU4lCXZgAsVd3N8KMkBt7DiNc8635f ieexXxHCSUhH6U7RIp8adKMSCg== X-Google-Smtp-Source: APiQypKacRfK99rf6iQOnxtQnKY1aL5+xx4THk8Igo/+4QWdtzZAGWlpf5bor+7yahyBS/O7wTHAmw== X-Received: by 2002:adf:d091:: with SMTP id y17mr38466279wrh.418.1588171513405; Wed, 29 Apr 2020 07:45:13 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id a10sm20071739wrg.32.2020.04.29.07.45.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 07:45:12 -0700 (PDT) From: Quentin Monnet To: Alexei Starovoitov , Daniel Borkmann Cc: bpf@vger.kernel.org, netdev@vger.kernel.org, Quentin Monnet , Richard Palethorpe , Michael Kerrisk Subject: [PATCH bpf-next v3 3/3] tools: bpftool: make libcap dependency optional Date: Wed, 29 Apr 2020 15:45:06 +0100 Message-Id: <20200429144506.8999-4-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429144506.8999-1-quentin@isovalent.com> References: <20200429144506.8999-1-quentin@isovalent.com> MIME-Version: 1.0 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The new libcap dependency is not used for an essential feature of bpftool, and we could imagine building the tool without checks on CAP_SYS_ADMIN by disabling probing features as an unprivileged users. Make it so, in order to avoid a hard dependency on libcap, and to ease packaging/embedding of bpftool. Signed-off-by: Quentin Monnet --- .../bpftool/Documentation/bpftool-feature.rst | 4 ++- tools/bpf/bpftool/Makefile | 13 +++++++--- tools/bpf/bpftool/feature.c | 26 +++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index ca085944e4cf..1fa755f55e0c 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -55,7 +55,9 @@ DESCRIPTION that case usually represent a small subset of the parameters supported by the system. Unprivileged users MUST use the **unprivileged** keyword: This is to avoid misdetection if - bpftool is inadvertently run as non-root, for example. + bpftool is inadvertently run as non-root, for example. This + keyword is unavailable if bpftool was compiled without + libcap. **bpftool feature probe dev** *NAME* [**full**] [**macros** [**prefix** *PREFIX*]] Probe network device for supported eBPF features and dump diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 89d7962a4a44..2759f9cc3289 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -55,16 +55,15 @@ ifneq ($(EXTRA_LDFLAGS),) LDFLAGS += $(EXTRA_LDFLAGS) endif -LIBS = $(LIBBPF) -lelf -lz -lcap - INSTALL ?= install RM ?= rm -f CLANG ?= clang FEATURE_USER = .bpftool -FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib \ +FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ + clang-bpf-global-var +FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ clang-bpf-global-var -FEATURE_DISPLAY = libbfd disassembler-four-args zlib clang-bpf-global-var check_feat := 1 NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall @@ -90,6 +89,12 @@ ifeq ($(feature-reallocarray), 0) CFLAGS += -DCOMPAT_NEED_REALLOCARRAY endif +LIBS = $(LIBBPF) -lelf -lz +ifeq ($(feature-libcap), 1) +CFLAGS += -DUSE_LIBCAP +LIBS += -lcap +endif + include $(wildcard $(OUTPUT)*.d) all: $(OUTPUT)bpftool diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 952f4b1987c0..f54347f55ee0 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -6,7 +6,9 @@ #include #include #include +#ifdef USE_LIBCAP #include +#endif #include #include @@ -37,7 +39,9 @@ static const char * const helper_name[] = { #undef BPF_HELPER_MAKE_ENTRY static bool full_mode; +#ifdef USE_LIBCAP static bool run_as_unprivileged; +#endif /* Miscellaneous utility functions */ @@ -475,11 +479,13 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, } res = bpf_probe_prog_type(prog_type, ifindex); +#ifdef USE_LIBCAP /* Probe may succeed even if program load fails, for unprivileged users * check that we did not fail because of insufficient permissions */ if (run_as_unprivileged && errno == EPERM) res = false; +#endif supported_types[prog_type] |= res; @@ -535,12 +541,14 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, if (supported_type) { res = bpf_probe_helper(id, prog_type, ifindex); +#ifdef USE_LIBCAP /* Probe may succeed even if program load fails, for * unprivileged users check that we did not fail because of * insufficient permissions */ if (run_as_unprivileged && errno == EPERM) res = false; +#endif } if (json_output) { @@ -738,6 +746,7 @@ static void section_misc(const char *define_prefix, __u32 ifindex) static int handle_perms(void) { +#ifdef USE_LIBCAP cap_value_t cap_list[1] = { CAP_SYS_ADMIN }; bool has_sys_admin_cap = false; cap_flag_value_t val; @@ -793,6 +802,18 @@ static int handle_perms(void) } return res; +#else + /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). + * We do not use libpcap so let's approximate, and restrict usage to + * root user only. + */ + if (geteuid()) { + p_err("full feature probing requires root privileges"); + return -1; + } + + return 0; +#endif /* USE_LIBCAP */ } static int do_probe(int argc, char **argv) @@ -852,8 +873,13 @@ static int do_probe(int argc, char **argv) return -1; define_prefix = GET_ARG(); } else if (is_prefix(*argv, "unprivileged")) { +#ifdef USE_LIBCAP run_as_unprivileged = true; NEXT_ARG(); +#else + p_err("unprivileged run not supported, recompile bpftool with libcap"); + return -1; +#endif } else { p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", *argv);