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]
Date:   Thu, 20 Dec 2018 12:24:30 +0000
From:   Quentin Monnet <quentin.monnet@...ronome.com>
To:     Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>
Cc:     netdev@...r.kernel.org, oss-drivers@...ronome.com,
        Quentin Monnet <quentin.monnet@...ronome.com>,
        Arnaldo Carvalho de Melo <acme@...nel.org>,
        Jesper Dangaard Brouer <brouer@...hat.com>,
        Stanislav Fomichev <sdf@...gle.com>
Subject: [RFC PATCH bpf-next v2 7/9] tools: bpftool: add C-style "#define" output for probes

Make bpftool able to dump a subset of the parameters collected by
probing the system as a listing of C-style #define macros, so that
external projects can reuse the result of this probing and build
BPF-based project in accordance with the features available on the
system.

The new "macros" keyword is used to select this output. An additional
"prefix" keyword is added so that users can select a custom prefix for
macro names, in order to avoid any namespace conflict.

Sample output:

    # bpftool feature probe kernel macros prefix FOO_
    /*** System call availability ***/
    #define FOO_HAVE_BPF_SYSCALL

    /*** eBPF program types ***/
    #define FOO_HAVE_SOCKET_FILTER_PROG_TYPE
    #define FOO_HAVE_KPROBE_PROG_TYPE
    #define FOO_HAVE_SCHED_CLS_PROG_TYPE
    ...

    /*** eBPF map types ***/
    #define FOO_HAVE_HASH_MAP_TYPE
    #define FOO_HAVE_ARRAY_MAP_TYPE
    #define FOO_HAVE_PROG_ARRAY_MAP_TYPE
    ...

    /*** eBPF helper functions ***/
    ...
    #define FOO_BPF_SKB_CHANGE_HEAD_HELPER_COMPAT_LIST      ""      \
            "lwt_xmit "     \
            "sk_skb "
    #define FOO_BPF_XDP_ADJUST_HEAD_HELPER_COMPAT_LIST      ""      \
            "xdp "
    #define FOO_BPF_PROBE_READ_STR_HELPER_COMPAT_LIST       ""      \
            "kprobe "       \
            "tracepoint "   \
            "perf_event "   \
            "raw_tracepoint "
    ...

v2:
- #define-based output added as a distinct patch.
- "HAVE_" prefix appended to all macro names.
- Output limited to bpf() syscall availability, BPF prog and map types,
  helper functions. In this version kernel config options, procfs
  parameter or kernel version are intentionally left aside.
- Following the change on helper probes, format for helper probes in
  this output style has changed (now a list of compatible program
  types).

Signed-off-by: Quentin Monnet <quentin.monnet@...ronome.com>
---
 .../bpftool/Documentation/bpftool-feature.rst |  13 +-
 tools/bpf/bpftool/feature.c                   | 138 ++++++++++++++----
 2 files changed, 120 insertions(+), 31 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
index 255e3b3629a0..53092995f46b 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst
@@ -19,15 +19,24 @@ SYNOPSIS
 MAP COMMANDS
 =============
 
-|	**bpftool** **feature probe** [**kernel**]
+|	**bpftool** **feature probe** [**kernel**] [**macros** [**prefix** *PREFIX*]]
 |	**bpftool** **feature help**
 
 DESCRIPTION
 ===========
-	**bpftool feature probe** [**kernel**]
+	**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.
 
+		  If the **macros** keyword (but not the **-j** option) is
+		  passed, a subset of the 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.
+
 		  Keyword **kernel** can be omitted.
 
 		  Note that when probed, some eBPF helpers (e.g.
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index bc483823014b..cd84617312dc 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -44,13 +44,25 @@ static bool check_procfs(void)
 	return true;
 }
 
+static void uppercase(char *str, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len && str[i] != '\0'; i++)
+		str[i] = toupper(str[i]);
+}
+
 /* Printing utility functions */
 
 static void
-print_bool_feature(const char *feat_name, const char *plain_name, bool res)
+print_bool_feature(const char *feat_name, const char *plain_name,
+		   const char *define_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%sHAVE_%s\n", define_prefix,
+		       res ? "" : "NO_", define_name);
 	else
 		printf("%s is %savailable\n", plain_name, res ? "" : "NOT ");
 }
@@ -60,6 +72,8 @@ static void print_kernel_option(const char *name, const char *value)
 	char *endptr;
 	int res;
 
+	/* No support for C-style ouptut */
+
 	if (json_output) {
 		if (!value) {
 			jsonw_null_field(json_wtr, name);
@@ -80,25 +94,31 @@ static void print_kernel_option(const char *name, const char *value)
 }
 
 static void
-print_start_section(const char *json_title, const char *plain_title)
+print_start_section(const char *json_title, const char *plain_title,
+		    const char *define_comment, 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);
 	}
 }
 
 static void
-print_end_then_start_section(const char *json_title, const char *plain_title)
+print_end_then_start_section(const char *json_title, const char *plain_title,
+			     const char *define_comment,
+			     const char *define_prefix)
 {
 	if (json_output)
 		jsonw_end_object(json_wtr);
 	else
 		printf("\n");
 
-	print_start_section(json_title, plain_title);
+	print_start_section(json_title, plain_title, define_comment,
+			    define_prefix);
 }
 
 /* Probing functions */
@@ -132,6 +152,8 @@ static void probe_unprivileged_disabled(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/kernel/unprivileged_bpf_disabled");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "unprivileged_bpf_disabled", res);
@@ -156,6 +178,8 @@ static void probe_jit_enable(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_enable");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_enable", res);
@@ -184,6 +208,8 @@ static void probe_jit_harden(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_harden");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_harden", res);
@@ -212,6 +238,8 @@ static void probe_jit_kallsyms(void)
 {
 	int res;
 
+	/* No support for C-style ouptut */
+
 	res = read_procfs("/proc/sys/net/core/bpf_jit_kallsyms");
 	if (json_output) {
 		jsonw_int_field(json_wtr, "bpf_jit_kallsyms", res);
@@ -344,7 +372,7 @@ static void probe_kernel_image_config(void)
 		print_kernel_option(options[i], NULL);
 }
 
-static int probe_kernel_version(void)
+static int probe_kernel_version(const char *define_prefix)
 {
 	int version, subversion, patchlevel, code = 0;
 	struct utsname utsn;
@@ -354,6 +382,10 @@ static int probe_kernel_version(void)
 			   &version, &subversion, &patchlevel) == 3)
 			code = (version << 16) + (subversion << 8) + patchlevel;
 
+	if (define_prefix)
+		/* Nothing currently displayed for this ouptut */
+		return code;
+
 	if (json_output)
 		jsonw_uint_field(json_wtr, "kernel_version_code", code);
 	else if (code)
@@ -365,7 +397,7 @@ static int probe_kernel_version(void)
 	return code;
 }
 
-static bool probe_bpf_syscall(void)
+static bool probe_bpf_syscall(const char *define_prefix)
 {
 	bool res;
 
@@ -374,17 +406,18 @@ static bool probe_bpf_syscall(void)
 
 	print_bool_feature("have_bpf_syscall",
 			   "bpf() syscall",
-			   res);
+			   "BPF_SYSCALL",
+			   res, define_prefix);
 
 	return res;
 }
 
 static void
 probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
-		bool *supported_types)
+		bool *supported_types, const char *define_prefix)
 {
+	char feat_name[128], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF program_type ";
-	char feat_name[128], plain_desc[128];
 	size_t maxlen;
 	bool res;
 
@@ -399,14 +432,18 @@ probe_prog_type(enum bpf_prog_type prog_type, int kernel_version,
 	}
 
 	sprintf(feat_name, "have_%s_prog_type", prog_type_name[prog_type]);
+	sprintf(define_name, "%s_prog_type", prog_type_name[prog_type]);
+	uppercase(define_name, sizeof(define_name));
 	sprintf(plain_desc, "%s%s", plain_comment, prog_type_name[prog_type]);
-	print_bool_feature(feat_name, plain_desc, res);
+	print_bool_feature(feat_name, plain_desc, define_name, res,
+			   define_prefix);
 }
 
-static void probe_map_type(enum bpf_map_type map_type)
+static void
+probe_map_type(enum bpf_map_type map_type, const char *define_prefix)
 {
+	char feat_name[128], plain_desc[128], define_name[128];
 	const char *plain_comment = "eBPF map_type ";
-	char feat_name[128], plain_desc[128];
 	size_t maxlen;
 	bool res;
 
@@ -419,18 +456,23 @@ static void probe_map_type(enum bpf_map_type map_type)
 	}
 
 	sprintf(feat_name, "have_%s_map_type", map_type_name[map_type]);
+	sprintf(define_name, "%s_map_type", map_type_name[map_type]);
+	uppercase(define_name, sizeof(define_name));
 	sprintf(plain_desc, "%s%s", plain_comment, map_type_name[map_type]);
-	print_bool_feature(feat_name, plain_desc, res);
+	print_bool_feature(feat_name, plain_desc, define_name, res,
+			   define_prefix);
 }
 
 static void
 probe_helper(__u32 id, const char *name, int kernel_version,
-	     bool *supported_types)
+	     bool *supported_types, const char *define_prefix)
 {
-	char feat_name[128], plain_desc[128];
+	char feat_name[128], plain_desc[128], define_name[128];
 	unsigned int i;
 
 	sprintf(feat_name, "%s_compat_list", name);
+	sprintf(define_name, "%s_helper_compat_list", name);
+	uppercase(define_name, sizeof(define_name));
 	sprintf(plain_desc,
 		"eBPF helper %s supported for program types:",
 		name);
@@ -438,6 +480,8 @@ probe_helper(__u32 id, const char *name, int kernel_version,
 	if (json_output) {
 		jsonw_name(json_wtr, feat_name);
 		jsonw_start_array(json_wtr);
+	} else if (define_prefix) {
+		printf("#define %s%s\t\"\"", define_prefix, define_name);
 	} else {
 		printf("%s", plain_desc);
 	}
@@ -452,19 +496,22 @@ probe_helper(__u32 id, const char *name, int kernel_version,
 
 		if (json_output)
 			jsonw_string(json_wtr, prog_type_name[i]);
+		else if (define_prefix)
+			printf("\t\\\n\t\"%s \"", prog_type_name[i]);
 		else
 			printf(" %s", prog_type_name[i]);
 	}
 
 	if (json_output)
 		jsonw_end_array(json_wtr);
-	else
+	else /* For both C-style and plain output */
 		printf("\n");
 }
 
 static int do_probe(int argc, char **argv)
 {
 	enum probe_component target = COMPONENT_UNSPEC;
+	const char *define_prefix = NULL;
 	bool supported_types[128] = {};
 	int kernel_version;
 	unsigned int i;
@@ -487,21 +534,45 @@ static int do_probe(int argc, char **argv)
 			}
 			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', got: '%s'?",
+			p_err("expected no more arguments, 'kernel', 'macros' or 'prefix', got: '%s'?",
 			      *argv);
 			return -1;
 		}
 	}
 
-	if (json_output)
+	if (json_output) {
+		define_prefix = NULL;
 		jsonw_start_object(json_wtr);
+	}
 
 	switch (target) {
 	case COMPONENT_KERNEL:
 	case COMPONENT_UNSPEC:
+		if (define_prefix)
+			break;
+
 		print_start_section("system_config",
-				    "Scanning system configuration...");
+				    "Scanning system configuration...",
+				    NULL, /* define_comment never used here */
+				    NULL); /* define_prefix always NULL here */
 		if (check_procfs()) {
 			probe_unprivileged_disabled();
 			probe_jit_enable();
@@ -519,31 +590,40 @@ static int do_probe(int argc, char **argv)
 	}
 
 	print_start_section("syscall_config",
-			    "Scanning system call and kernel version...");
+			    "Scanning system call and kernel version...",
+			    "/*** System call availability ***/",
+			    define_prefix);
 
-	kernel_version = probe_kernel_version();
-	if (!probe_bpf_syscall())
+	kernel_version = probe_kernel_version(define_prefix);
+	if (!probe_bpf_syscall(define_prefix))
 		/* bpf() syscall unavailable, don't probe other BPF features */
 		goto exit_close_json;
 
 	print_end_then_start_section("program_types",
-				     "Scanning eBPF program types...");
+				     "Scanning eBPF program types...",
+				     "/*** eBPF program types ***/",
+				     define_prefix);
 
 	for (i = BPF_PROG_TYPE_UNSPEC + 1; i < ARRAY_SIZE(prog_type_name); i++)
-		probe_prog_type(i, kernel_version, supported_types);
+		probe_prog_type(i, kernel_version, supported_types,
+				define_prefix);
 
 	print_end_then_start_section("map_types",
-				     "Scanning eBPF map types...");
+				     "Scanning eBPF map types...",
+				     "/*** eBPF map types ***/",
+				     define_prefix);
 
 	for (i = BPF_MAP_TYPE_UNSPEC + 1; i < map_type_name_size; i++)
-		probe_map_type(i);
+		probe_map_type(i, define_prefix);
 
 	print_end_then_start_section("helpers",
-				     "Scanning eBPF helper functions...");
+				     "Scanning eBPF helper functions...",
+				     "/*** eBPF helper functions ***/",
+				     define_prefix);
 
 	for (i = 1; i < ARRAY_SIZE(helper_name); i++)
 		probe_helper(i, helper_name[i], kernel_version,
-			     supported_types);
+			     supported_types, define_prefix);
 
 exit_close_json:
 	if (json_output) {
@@ -564,7 +644,7 @@ static int do_help(int argc, char **argv)
 	}
 
 	fprintf(stderr,
-		"Usage: %s %s probe [kernel]\n"
+		"Usage: %s %s probe [kernel] [macros [prefix PREFIX]]\n"
 		"       %s %s help\n"
 		"",
 		bin_name, argv[-2], bin_name, argv[-2]);
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ