From patchwork Wed Apr 29 13:05:32 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279297 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=kkknD6zn; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49BzKH4Rxzz9sT1 for ; Wed, 29 Apr 2020 23:05:55 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727103AbgD2NFv (ORCPT ); Wed, 29 Apr 2020 09:05:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48104 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726828AbgD2NFu (ORCPT ); Wed, 29 Apr 2020 09:05:50 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A9F4AC03C1AE for ; Wed, 29 Apr 2020 06:05:49 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id y24so1937891wma.4 for ; Wed, 29 Apr 2020 06:05:49 -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=kkknD6znJD9eKqwpa80nS3XJjm4Vg/Ne2ZPsAgMy5k3r9Cqllji8I7sKWJhmRqGHJk D3pqVbezVxOdWLPlvzfQKeLS91UpCmiNzhcAQ9PdTsLdXb7M0UQr5fALfWLdEhxpf+el ByD4Lw+wxQUgFh/6sp+pbfb2wc+tIvqPnFm2jnPa9uIkDiCbQS62VoWXV5tfZupymSw9 4eJDE4q+Qos3IqcoX5NW+jEN4aSj2+z605FZYvR9ESu2N/58MI7EEsqSlcuKh0FDFUD8 FCUU/DKFcaMwbFv/VI5zB2+RNDqODVPklzyEbYyBQn+xjswZ25ZJgR5AZhXu+7Q+SLk9 jIYg== 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=ua7N3oxm5jg+Bc8aHAN1bcf0qLVEh4fUwIqbH8Pmy2L4VN8HncOobsNFoThHWjaWTW PFoM0FNP0uWgneBY5pMeQrEKbljV205FKF8QR0rNSjhiXTysTkupIcIx10p0/avLqts1 DoSoxTNPWNLyoRd0xKZYZ+ZuX7JiQ/UhDrCNOuALh9RdGkezyPv9ZP2NqFxpGYrmfFC2 HBcof3keHa8UuMY+cMxRa+bFLUr0QjBJSdG2l8z9aREK7n1r4MefebGvHCRJWdG6z1fc puUyHThEYLmk4VX/iUhfzSNEIurXpk/+bhJzkqOYR1CB/NgwaNMXVWRrepS5AE/3rlF+ p4qA== X-Gm-Message-State: AGi0PuacRHNBLJTkOs3tauyqc50aPBv0BLD73J0OgWHVOrSxJvlsvyEC dCrUtCWs3PGIVm4YxxilbSnYUHq8ZsA= X-Google-Smtp-Source: APiQypJ0KgnHIRKLRRjiH/35QcG9BbymXObY4HmkCzP6WAaOBHXg+Ab/KdZn7oaXvRajqpvCxAtbOg== X-Received: by 2002:a1c:e284:: with SMTP id z126mr3405702wmg.32.1588165548378; Wed, 29 Apr 2020 06:05:48 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id 74sm31568199wrk.30.2020.04.29.06.05.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 06:05:47 -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 v2 1/3] tools: bpftool: for "feature probe" define "full_mode" bool as global Date: Wed, 29 Apr 2020 14:05:32 +0100 Message-Id: <20200429130534.11823-2-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429130534.11823-1-quentin@isovalent.com> References: <20200429130534.11823-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 13:05:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279301 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Original-To: incoming-bpf@patchwork.ozlabs.org Delivered-To: patchwork-incoming-bpf@bilbo.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=bpf-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=vwibQ9UI; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49BzKJ4rJfz9sTB for ; Wed, 29 Apr 2020 23:05:56 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727107AbgD2NFw (ORCPT ); Wed, 29 Apr 2020 09:05:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48112 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727092AbgD2NFv (ORCPT ); Wed, 29 Apr 2020 09:05:51 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 319BEC03C1AD for ; Wed, 29 Apr 2020 06:05:51 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id v8so4899099wma.0 for ; Wed, 29 Apr 2020 06:05:51 -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=8FNACjRz+3wuhbE9szWgXsgSXhQNwujbnC4c2fAwHas=; b=vwibQ9UIbwrt3ZCYoTDq8HndSPxTtdl9r+XT7AGT2PWrrNxqzxttS7dO0t88Na/ywa SP+/XzoLDRpu7lqFt1TxyXZ3cGfxMEkLgqiwv3zF2ZV7OQlUFdhPxh3pzeOmCDCqkoUV A7K3NFeBoUGtGqyU3Et03UmCQqYItU6/TwXHxi/uBpXN53W+VldWgFtFQLOWE7UeJCxu 584XKsHa9SZXrVicLRDkArp8j5TwBFDL4AJrsIih1DxopmwJqiTWEDn43G+tHvq78MV4 cU8ZDmgnz0iJ7zgRmYFQo5JvxMEd9gKD3Tqa4HU796pCPJFMbJfNm8JctPZEGNY3IZj+ XtdQ== 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=8FNACjRz+3wuhbE9szWgXsgSXhQNwujbnC4c2fAwHas=; b=DfVF+ijeDTEUXymw34LHLT5o1Q+ynkqu7qMrDMgUIYLCHBRGTBs5bLYj0auIJ7mHq2 ca3bx7UC7Pf6k+4LlgeFXqZUcX7Sx6dlaFrx74/UrMQXtx5RsiPf0+n5ZWohsi85Q6O7 aZyOUXDc7MFrQKcGir2YUCqrtMtJGvfeOSrUYfHuul4WLlox9ElwZrdNoIMyWiWF/DDS nhVj+G/ciD0ybg2nWZUspcj9t9bn9W7sx2yZj29gvaPaeR/3shvBq0p+9LcYyRwK/mxd GoxoeSJsx1ueaSRIgnqHQ4zsW79O8dN728ufO8Q62g5g2FwOYYSPbCV1amDIN5dJT2Ok b4qw== X-Gm-Message-State: AGi0PubEXPHhdRguvBwtJUk/eu3znysLuGRIT12E7ZHPpsiVHD8u+aEP ZD6lgVaqBi0Vr7CcOQDA9QNwUQ== X-Google-Smtp-Source: APiQypIrV5XOw2RUxHrmhZ6KecYpRtD2nAa/zFZoqe1EgdPC6rZ+6hvB9Rym2CccUnCLP07HAomXaA== X-Received: by 2002:a1c:4ca:: with SMTP id 193mr3230097wme.18.1588165549371; Wed, 29 Apr 2020 06:05:49 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id 74sm31568199wrk.30.2020.04.29.06.05.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 06:05:48 -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 v2 2/3] tools: bpftool: allow unprivileged users to probe features Date: Wed, 29 Apr 2020 14:05:33 +0100 Message-Id: <20200429130534.11823-3-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429130534.11823-1-quentin@isovalent.com> References: <20200429130534.11823-1-quentin@isovalent.com> MIME-Version: 1.0 Sender: bpf-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: bpf@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 | 100 +++++++++++++++--- 4 files changed, 99 insertions(+), 15 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..78cf21b27d3d 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); From patchwork Wed Apr 29 13:05:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Quentin Monnet X-Patchwork-Id: 1279303 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=bgUOlTwr; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 49BzKK3yL8z9sT2 for ; Wed, 29 Apr 2020 23:05:57 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727092AbgD2NFy (ORCPT ); Wed, 29 Apr 2020 09:05:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48120 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727112AbgD2NFw (ORCPT ); Wed, 29 Apr 2020 09:05:52 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2C5EBC03C1AE for ; Wed, 29 Apr 2020 06:05:52 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id i10so2416449wrv.10 for ; Wed, 29 Apr 2020 06:05:52 -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=PTf2nTlKoz+C9MBIBh9J9OOYB9vLQLEDWbpjGCvh6UY=; b=bgUOlTwrgWa7aU5UvwjCtkKcIU4rv8f956Szxj0HzsrtHO9skAg/+uWiqu2IwRjLyS zJ8tf1adA1jw35kd+R5SBPNss5H2omYxGRTVp4A4cL3JBr20eADvz4AhwU6AYDQoC2mk U2t9BqrGNDRGGff9HT+qbtHX6tvUN2sJ7TTAO8E2Wbo4nZSmuSQA51M07T9tOwz6jueO uUiGvaQWzXHNcFInvYJFqFhao2tAfjw+BeBbwhCxqEXRjUmr2BX1+0ZaVbfrcbY62WRK kBAE4TUvhE/6xKEzt+FkNTMb3CJpQA5ApsOJCDRhMLASWTiPC/kzA9sFMByjZjX98k0F 8GOA== 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=PTf2nTlKoz+C9MBIBh9J9OOYB9vLQLEDWbpjGCvh6UY=; b=WslzZZw53OvhWEE8CH1PFbakyMyN9V00n/eC/LME6dfvwm/3D25j5uYcnaDv7g8+6s mKzPosuQdn9+YRr+rIkmslrW+/VXDVMnOpysH82u+/DeqDPDVWopIVDRQsH/YfgAZqJj ixyjK2/Kg4N665BGtv72P4zKM3o70BApEXRll22SrF45ROFfP/gdHbyatxR1GpQ5G6ZF b9TvGQkpU/F1WeRgjD6Zbk+l+Ru1XEcgqc5Q0YM7o3ipKyYDnvyb34kkNhYreocN1iqg rMz96l02zFNRD2s1SB1QXtslLwIEIwbxvP34DuD9ixtHOCpGYGFkPBb/X5RkI75ubRVL oj0A== X-Gm-Message-State: AGi0PuaKVJq5OjgQtjuDEcGgDUkdzVDsPxJqDNSPBxjg1+NisW358kSa 5jGa8nzUJgdl0qUzNi43mbcwTQ== X-Google-Smtp-Source: APiQypI3pCKErjhfk87LcJ5BwVD6j7dCHrjk22dtOma4l2D4EMuF9M6LZS6WXpJXMepOLsUEKhIdoA== X-Received: by 2002:a5d:4e02:: with SMTP id p2mr41987775wrt.302.1588165550819; Wed, 29 Apr 2020 06:05:50 -0700 (PDT) Received: from localhost.localdomain ([194.53.185.38]) by smtp.gmail.com with ESMTPSA id 74sm31568199wrk.30.2020.04.29.06.05.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 29 Apr 2020 06:05:50 -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 v2 3/3] tools: bpftool: make libcap dependency optional Date: Wed, 29 Apr 2020 14:05:34 +0100 Message-Id: <20200429130534.11823-4-quentin@isovalent.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20200429130534.11823-1-quentin@isovalent.com> References: <20200429130534.11823-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 78cf21b27d3d..2f01f9a60792 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);