lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20181214025056.GC31012@mini-arch.hsd1.ca.comcast.net>
Date:   Thu, 13 Dec 2018 18:50:56 -0800
From:   Stanislav Fomichev <sdf@...ichev.me>
To:     Quentin Monnet <quentin.monnet@...ronome.com>
Cc:     Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>, netdev@...r.kernel.org,
        oss-drivers@...ronome.com,
        Arnaldo Carvalho de Melo <acme@...nel.org>,
        Jesper Dangaard Brouer <brouer@...hat.com>,
        Stanislav Fomichev <sdf@...gle.com>
Subject: Re: [PATCH bpf-next 1/8] tools: bpftool: add basic probe capability,
 probe syscall and kversion

On 12/13, Quentin Monnet wrote:
> Add a new component and command for bpftool, in order to probe the
> system to dump a set of eBPF-related parameters so that users can know
> what features are available on the system.
> 
> Parameters are dumped in plain or JSON output (with -j/-p options).
> Additionally, a specific keyword can be used to provide a third possible
> output so that the parameters are dumped as #define-d macros, ready to
> be saved to a header file and included in an eBPF-based project.
> 
> The current patch introduces probing of two simple parameters:
> availability of the bpf() system call, and kernel version. Later commits
> will add other probes.
> 
> Sample output:
> 
>     # bpftool feature probe kernel
>     Scanning system call and kernel version...
>     Kernel release is 4.19.0
>     bpf() syscall is available
> 
>     # bpftool --json --pretty feature probe kernel
>     {
>         "syscall_config": {
>             "kernel_version_code": 267008,
>             "have_bpf_syscall": true
>         }
>     }
> 
>     # bpftool feature probe kernel macros prefix BPFTOOL_
>     /*** System call and kernel version ***/
>     #define BPFTOOL_LINUX_VERSION_CODE 267008
>     #define BPFTOOL_BPF_SYSCALL
> 
> The optional "kernel" keyword enforces probing of the current system,
> which is the only possible behaviour at this stage. It can be safely
> omitted.
> 
> The feature comes with the relevant man page, but bash completion will
> come in a dedicated commit.
> 
> Signed-off-by: Quentin Monnet <quentin.monnet@...ronome.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@...ronome.com>
> ---
>  .../bpftool/Documentation/bpftool-cgroup.rst  |   1 +
>  .../bpftool/Documentation/bpftool-feature.rst |  69 +++++++
>  .../bpf/bpftool/Documentation/bpftool-map.rst |   1 +
>  .../bpf/bpftool/Documentation/bpftool-net.rst |   1 +
>  .../bpftool/Documentation/bpftool-perf.rst    |   1 +
>  .../bpftool/Documentation/bpftool-prog.rst    |   1 +
>  tools/bpf/bpftool/Documentation/bpftool.rst   |   1 +
>  tools/bpf/bpftool/feature.c                   | 184 ++++++++++++++++++
>  tools/bpf/bpftool/main.c                      |   3 +-
>  tools/bpf/bpftool/main.h                      |   1 +
>  10 files changed, 262 insertions(+), 1 deletion(-)
>  create mode 100644 tools/bpf/bpftool/Documentation/bpftool-feature.rst
>  create mode 100644 tools/bpf/bpftool/feature.c
> 
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> index d07ccf8a23f7..d43fce568ef7 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-cgroup.rst
> @@ -142,5 +142,6 @@ SEE ALSO
>  	**bpftool**\ (8),
>  	**bpftool-prog**\ (8),
>  	**bpftool-map**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-net**\ (8),
>  	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> new file mode 100644
> index 000000000000..23920a7490e9
> --- /dev/null
> +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
> @@ -0,0 +1,69 @@
> +===============
> +bpftool-feature
> +===============
> +-------------------------------------------------------------------------------
> +tool for inspection of eBPF-related parameters for Linux kernel or net device
> +-------------------------------------------------------------------------------
> +
> +:Manual section: 8
> +
> +SYNOPSIS
> +========
> +
> +	**bpftool** [*OPTIONS*] **feature** *COMMAND*
> +
> +	*OPTIONS* := { { **-j** | **--json** } [{ **-p** | **--pretty** }] }
> +
> +	*COMMANDS* := { **probe** | **help** }
> +
> +MAP COMMANDS
> +=============
> +
> +|	**bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
> +|	**bpftool** **feature help**
> +
> +DESCRIPTION
> +===========
> +	**bpftool feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
> +		  Probe the running kernel and dump a number of eBPF-related
> +		  parameters, such as availability of the **bpf()** system call.
> +
> +		  Keyword **kernel** can be omitted.
> +
> +		  If the **macros** keyword (but not the **-j** option) is
> +		  passed, output is dumped as a list of **#define** macros that
> +		  are ready to be included in a C header file, for example.
> +		  If, additionally, **prefix** is used to define a *PREFIX*,
> +		  the provided string will be used as a prefix to the names of
> +		  the macros: this can be used to avoid conflicts on macro
> +		  names when including the output of this command as a header
> +		  file.
> +
> +	**bpftool feature help**
> +		  Print short help message.
> +
> +OPTIONS
> +=======
> +	-h, --help
> +		  Print short generic help message (similar to **bpftool help**).
> +
> +	-v, --version
> +		  Print version number (similar to **bpftool version**).
> +
> +	-j, --json
> +		  Generate JSON output. For commands that cannot produce JSON, this
> +		  option has no effect.
> +
> +	-p, --pretty
> +		  Generate human-readable JSON output. Implies **-j**.
> +
> +SEE ALSO
> +========
> +	**bpf**\ (2),
> +	**bpf-helpers**\ (7),
> +	**bpftool**\ (8),
> +	**bpftool-prog**\ (8),
> +	**bpftool-map**\ (8),
> +	**bpftool-cgroup**\ (8),
> +	**bpftool-net**\ (8),
> +	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-map.rst b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> index 5318dcb2085e..b432c5cc20c8 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-map.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-map.rst
> @@ -177,5 +177,6 @@ SEE ALSO
>  	**bpftool**\ (8),
>  	**bpftool-prog**\ (8),
>  	**bpftool-cgroup**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-net**\ (8),
>  	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> index ed87c9b619ad..779dab3650ee 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> @@ -142,4 +142,5 @@ SEE ALSO
>  	**bpftool-prog**\ (8),
>  	**bpftool-map**\ (8),
>  	**bpftool-cgroup**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-perf.rst b/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> index f4c5e5538bb8..bca5590a80d0 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-perf.rst
> @@ -84,4 +84,5 @@ SEE ALSO
>  	**bpftool-prog**\ (8),
>  	**bpftool-map**\ (8),
>  	**bpftool-cgroup**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-net**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> index bb1aeb98b6da..595b4538c0d7 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
> @@ -243,5 +243,6 @@ SEE ALSO
>  	**bpftool**\ (8),
>  	**bpftool-map**\ (8),
>  	**bpftool-cgroup**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-net**\ (8),
>  	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/Documentation/bpftool.rst b/tools/bpf/bpftool/Documentation/bpftool.rst
> index 129b7a9c0f9b..f6526b657677 100644
> --- a/tools/bpf/bpftool/Documentation/bpftool.rst
> +++ b/tools/bpf/bpftool/Documentation/bpftool.rst
> @@ -68,5 +68,6 @@ SEE ALSO
>  	**bpftool-prog**\ (8),
>  	**bpftool-map**\ (8),
>  	**bpftool-cgroup**\ (8),
> +	**bpftool-feature**\ (8),
>  	**bpftool-net**\ (8),
>  	**bpftool-perf**\ (8)
> diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
> new file mode 100644
> index 000000000000..e1784611575d
> --- /dev/null
> +++ b/tools/bpf/bpftool/feature.c
> @@ -0,0 +1,184 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/* Copyright (c) 2018 Netronome Systems, Inc. */
> +
> +#include <errno.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/utsname.h>
> +
> +#include <linux/filter.h>
> +#include <linux/limits.h>
> +
> +#include <bpf.h>
> +
> +#include "main.h"
> +
> +enum probe_component {
> +	COMPONENT_UNSPEC,
> +	COMPONENT_KERNEL,
> +};
> +
> +/* Printing utility functions */
> +
> +static void
> +print_bool_feature(const char *feat_name, const char *define_name,
> +		   const char *plain_name, bool res, const char *define_prefix)
> +{
> +	if (json_output)
> +		jsonw_bool_field(json_wtr, feat_name, res);
> +	else if (define_prefix)

[..]

> +		printf("#define %s%s%s\n", define_prefix,
> +		       res ? "" : "NO_", define_name);

Should we keep it autoconf style and do:
#define XYZ 1 - in case of supported feature
/* #undef XYZ */ - in case of unsupported feature

?

> +	else
> +		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");

Why not do printf("%s %s\n", feat_name, res ? "yes" : "no") instead?
And not complicate (drop) the output with human readability. One
possible (dis)advantage - scripts can use this.

> +}
> +
> +static void
> +print_start_section(const char *json_title, const char *define_comment,
> +		    const char *plain_title, const char *define_prefix)
> +{
> +	if (json_output) {
> +		jsonw_name(json_wtr, json_title);
> +		jsonw_start_object(json_wtr);
> +	} else if (define_prefix) {
> +		printf("%s\n", define_comment);
> +	} else {
> +		printf("%s\n", plain_title);
> +	}
> +}
> +
> +/* Probing functions */
> +
> +static int probe_kernel_version(const char *define_prefix)
> +{
> +	int version, subversion, patchlevel, code = 0;
> +	struct utsname utsn;
> +
> +	if (!uname(&utsn))
> +		if (sscanf(utsn.release, "%d.%d.%d",
> +			   &version, &subversion, &patchlevel) == 3)
> +			code = (version << 16) + (subversion << 8) + patchlevel;
> +
> +	if (json_output)
> +		jsonw_uint_field(json_wtr, "kernel_version_code", code);
> +	else if (define_prefix)
> +		printf("#define %sLINUX_VERSION_CODE %d\n",
> +		       define_prefix, code);
> +	else if (code)
> +		printf("Kernel release is %d.%d.%d\n",
> +		       version, subversion, patchlevel);
> +	else
> +		printf("Unable to parse kernel release number\n");
> +
> +	return code;
> +}
> +
> +static bool probe_bpf_syscall(const char *define_prefix)
> +{
> +	bool res;
> +
> +	bpf_load_program(BPF_PROG_TYPE_UNSPEC, NULL, 0, NULL, 0, NULL, 0);
> +	res = (errno != ENOSYS);
> +
> +	print_bool_feature("have_bpf_syscall",
> +			   "BPF_SYSCALL",
> +			   "bpf() syscall",
> +			   res, define_prefix);
> +
> +	return res;
> +}
> +
> +static int do_probe(int argc, char **argv)
> +{
> +	enum probe_component target = COMPONENT_UNSPEC;
> +	const char *define_prefix = NULL;
> +
> +	/* 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) {
> +		if (is_prefix(*argv, "kernel")) {
> +			if (target != COMPONENT_UNSPEC) {
> +				p_err("component to probe already specified");
> +				return -1;
> +			}
> +			target = COMPONENT_KERNEL;
> +			NEXT_ARG();
> +		} else if (is_prefix(*argv, "macros") && !define_prefix) {
> +			define_prefix = "";
> +			NEXT_ARG();
> +		} else if (is_prefix(*argv, "prefix")) {
> +			if (!define_prefix) {
> +				p_err("'prefix' argument can only be use after 'macros'");
> +				return -1;
> +			}
> +			if (strcmp(define_prefix, "")) {
> +				p_err("'prefix' already defined");
> +				return -1;
> +			}
> +			NEXT_ARG();
> +
> +			if (!REQ_ARGS(1))
> +				return -1;
> +			define_prefix = GET_ARG();
> +		} else {
> +			p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
> +			      *argv);
> +			return -1;
> +		}
> +	}
> +
> +	if (json_output)
> +		jsonw_start_object(json_wtr);
> +
> +	print_start_section("syscall_config",
> +			    "/*** System call and kernel version ***/",
> +			    "Scanning system call and kernel version...",
> +			    define_prefix);
> +
> +	probe_kernel_version(define_prefix);
> +	probe_bpf_syscall(define_prefix);
> +
> +	if (json_output) {
> +		/* End current "section" of probes */
> +		jsonw_end_object(json_wtr);
> +		/* End root object */
> +		jsonw_end_object(json_wtr);
> +	}
> +
> +	return 0;
> +}
> +
> +static int do_help(int argc, char **argv)
> +{
> +	if (json_output) {
> +		jsonw_null(json_wtr);
> +		return 0;
> +	}
> +
> +	fprintf(stderr,
> +		"Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
> +		"       %s %s help\n"
> +		"",
> +		bin_name, argv[-2], bin_name, argv[-2]);
> +
> +	return 0;
> +}
> +
> +static const struct cmd cmds[] = {
> +	{ "help",	do_help },
> +	{ "probe",	do_probe },
> +	{ 0 }
> +};
> +
> +int do_feature(int argc, char **argv)
> +{
> +	return cmd_select(cmds, argc, argv, do_help);
> +}
> diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c
> index 9e657e7d5172..baf07f8be737 100644
> --- a/tools/bpf/bpftool/main.c
> +++ b/tools/bpf/bpftool/main.c
> @@ -55,7 +55,7 @@ static int do_help(int argc, char **argv)
>  		"       %s batch file FILE\n"
>  		"       %s version\n"
>  		"\n"
> -		"       OBJECT := { prog | map | cgroup | perf | net }\n"
> +		"       OBJECT := { prog | map | cgroup | perf | net | feature }\n"
>  		"       " HELP_SPEC_OPTIONS "\n"
>  		"",
>  		bin_name, bin_name, bin_name);
> @@ -186,6 +186,7 @@ static const struct cmd cmds[] = {
>  	{ "cgroup",	do_cgroup },
>  	{ "perf",	do_perf },
>  	{ "net",	do_net },
> +	{ "feature",	do_feature },
>  	{ "version",	do_version },
>  	{ 0 }
>  };
> diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
> index d2beb88f0e2e..2acd8c08e8b6 100644
> --- a/tools/bpf/bpftool/main.h
> +++ b/tools/bpf/bpftool/main.h
> @@ -141,6 +141,7 @@ int do_cgroup(int argc, char **arg);
>  int do_perf(int argc, char **arg);
>  int do_net(int argc, char **arg);
>  int do_tracelog(int argc, char **arg);
> +int do_feature(int argc, char **argv);
>  
>  int parse_u32_arg(int *argc, char ***argv, __u32 *val, const char *what);
>  int prog_parse_fd(int *argc, char ***argv);
> -- 
> 2.17.1
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ