bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next v1] bpftool: adding support for BTF program names
@ 2022-01-18 21:02 Raman Shukhau
  2022-01-19  4:21 ` Andrii Nakryiko
  0 siblings, 1 reply; 2+ messages in thread
From: Raman Shukhau @ 2022-01-18 21:02 UTC (permalink / raw)
  To: bpf, ast, andrii, daniel; +Cc: Raman Shukhau

`bpftool prog list` and other bpftool subcommands that show
BPF program names currently get them from bpf_prog_info.name.
That field is limited by 16 (BPF_OBJ_NAME_LEN) chars what leads
to truncated names since many progs have much longer names.

The idea of this change is to improve all bpftool commands that
output prog name so that bpftool uses info from BTF to print
program names if available.

It tries bpf_prog_info.name first and fall back to btf only if
the name is suspected to be truncated (has 15 chars length).

Right now `bpftool p show id <id>` returns capped prog name

<id>: kprobe  name example_cap_cap  tag 712e...
...

With this change it would return

<id>: kprobe  name example_cap_capable  tag 712e...
...

Note, other commands that prints prog names (e.g. "bpftool
cgroup tree") are also addressed in this change.

Signed-off-by: Raman Shukhau <ramasha@fb.com>
---
 tools/bpf/bpftool/cgroup.c |  6 ++++--
 tools/bpf/bpftool/common.c | 34 ++++++++++++++++++++++++++++++++++
 tools/bpf/bpftool/main.h   |  2 ++
 tools/bpf/bpftool/prog.c   | 17 +++++++++--------
 4 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
index 3571a281c43f..5e098d9772ae 100644
--- a/tools/bpf/bpftool/cgroup.c
+++ b/tools/bpf/bpftool/cgroup.c
@@ -73,7 +73,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
 			jsonw_uint_field(json_wtr, "attach_type", attach_type);
 		jsonw_string_field(json_wtr, "attach_flags",
 				   attach_flags_str);
-		jsonw_string_field(json_wtr, "name", info.name);
+		jsonw_string_field(json_wtr, "name",
+				   get_prog_full_name(&info, prog_fd));
 		jsonw_end_object(json_wtr);
 	} else {
 		printf("%s%-8u ", level ? "    " : "", info.id);
@@ -81,7 +82,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
 			printf("%-15s", attach_type_name[attach_type]);
 		else
 			printf("type %-10u", attach_type);
-		printf(" %-15s %-15s\n", attach_flags_str, info.name);
+		printf(" %-15s %-15s\n", attach_flags_str,
+		       get_prog_full_name(&info, prog_fd));
 	}
 
 	close(prog_fd);
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index fa8eb8134344..b94d0020e4b4 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -24,6 +24,7 @@
 #include <bpf/bpf.h>
 #include <bpf/hashmap.h>
 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
+#include <bpf/btf.h>
 
 #include "main.h"
 
@@ -304,6 +305,39 @@ const char *get_fd_type_name(enum bpf_obj_type type)
 	return names[type];
 }
 
+const char *get_prog_full_name(const struct bpf_prog_info *prog_info,
+			       int prog_fd)
+{
+	const struct btf_type *func_type;
+	const struct bpf_func_info finfo;
+	struct bpf_prog_info info = {};
+	__u32 info_len = sizeof(info);
+	const struct btf *prog_btf;
+
+	if (strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
+		return prog_info->name;
+
+	if (!prog_info->btf_id || prog_info->nr_func_info == 0)
+		return prog_info->name;
+
+	info.nr_func_info = 1;
+	info.func_info_rec_size = prog_info->func_info_rec_size;
+	info.func_info = ptr_to_u64(&finfo);
+
+	if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len))
+		return prog_info->name;
+
+	prog_btf = btf__load_from_kernel_by_id(info.btf_id);
+	if (libbpf_get_error(prog_btf))
+		return prog_info->name;
+
+	func_type = btf__type_by_id(prog_btf, finfo.type_id);
+	if (!func_type || !btf_is_func(func_type))
+		return prog_info->name;
+
+	return btf__name_by_offset(prog_btf, func_type->name_off);
+}
+
 int get_fd_type(int fd)
 {
 	char path[PATH_MAX];
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 8d76d937a62b..cbd03cc821b7 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -142,6 +142,8 @@ int cmd_select(const struct cmd *cmds, int argc, char **argv,
 
 int get_fd_type(int fd);
 const char *get_fd_type_name(enum bpf_obj_type type);
+const char *get_prog_full_name(const struct bpf_prog_info *prog_info,
+			       int prog_fd);
 char *get_fdinfo(int fd, const char *key);
 int open_obj_pinned(const char *path, bool quiet);
 int open_obj_pinned_any(const char *path, enum bpf_obj_type exp_type);
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 33ca834d5f51..e54d97ee998c 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -424,7 +424,7 @@ static void show_prog_metadata(int fd, __u32 num_maps)
 	free(value);
 }
 
-static void print_prog_header_json(struct bpf_prog_info *info)
+static void print_prog_header_json(struct bpf_prog_info *info, int fd)
 {
 	jsonw_uint_field(json_wtr, "id", info->id);
 	if (info->type < ARRAY_SIZE(prog_type_name))
@@ -434,7 +434,8 @@ static void print_prog_header_json(struct bpf_prog_info *info)
 		jsonw_uint_field(json_wtr, "type", info->type);
 
 	if (*info->name)
-		jsonw_string_field(json_wtr, "name", info->name);
+		jsonw_string_field(json_wtr, "name",
+				   get_prog_full_name(info, fd));
 
 	jsonw_name(json_wtr, "tag");
 	jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"",
@@ -455,7 +456,7 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
 	char *memlock;
 
 	jsonw_start_object(json_wtr);
-	print_prog_header_json(info);
+	print_prog_header_json(info, fd);
 	print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
 
 	if (info->load_time) {
@@ -507,7 +508,7 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
 	jsonw_end_object(json_wtr);
 }
 
-static void print_prog_header_plain(struct bpf_prog_info *info)
+static void print_prog_header_plain(struct bpf_prog_info *info, int fd)
 {
 	printf("%u: ", info->id);
 	if (info->type < ARRAY_SIZE(prog_type_name))
@@ -516,7 +517,7 @@ static void print_prog_header_plain(struct bpf_prog_info *info)
 		printf("type %u  ", info->type);
 
 	if (*info->name)
-		printf("name %s  ", info->name);
+		printf("name %s  ", get_prog_full_name(info, fd));
 
 	printf("tag ");
 	fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
@@ -534,7 +535,7 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
 {
 	char *memlock;
 
-	print_prog_header_plain(info);
+	print_prog_header_plain(info, fd);
 
 	if (info->load_time) {
 		char buf[32];
@@ -972,10 +973,10 @@ static int do_dump(int argc, char **argv)
 
 		if (json_output && nb_fds > 1) {
 			jsonw_start_object(json_wtr);	/* prog object */
-			print_prog_header_json(&info);
+			print_prog_header_json(&info, fds[i]);
 			jsonw_name(json_wtr, "insns");
 		} else if (nb_fds > 1) {
-			print_prog_header_plain(&info);
+			print_prog_header_plain(&info, fds[i]);
 		}
 
 		err = prog_dump(&info, mode, filepath, opcodes, visual, linum);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH bpf-next v1] bpftool: adding support for BTF program names
  2022-01-18 21:02 [PATCH bpf-next v1] bpftool: adding support for BTF program names Raman Shukhau
@ 2022-01-19  4:21 ` Andrii Nakryiko
  0 siblings, 0 replies; 2+ messages in thread
From: Andrii Nakryiko @ 2022-01-19  4:21 UTC (permalink / raw)
  To: Raman Shukhau; +Cc: bpf, Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann

On Tue, Jan 18, 2022 at 1:02 PM Raman Shukhau <ramasha@fb.com> wrote:
>
> `bpftool prog list` and other bpftool subcommands that show
> BPF program names currently get them from bpf_prog_info.name.
> That field is limited by 16 (BPF_OBJ_NAME_LEN) chars what leads

typo: limited to? which leads?

> to truncated names since many progs have much longer names.
>
> The idea of this change is to improve all bpftool commands that
> output prog name so that bpftool uses info from BTF to print
> program names if available.
>
> It tries bpf_prog_info.name first and fall back to btf only if
> the name is suspected to be truncated (has 15 chars length).
>
> Right now `bpftool p show id <id>` returns capped prog name
>
> <id>: kprobe  name example_cap_cap  tag 712e...
> ...
>
> With this change it would return
>
> <id>: kprobe  name example_cap_capable  tag 712e...
> ...
>
> Note, other commands that prints prog names (e.g. "bpftool

typo: print

> cgroup tree") are also addressed in this change.
>
> Signed-off-by: Raman Shukhau <ramasha@fb.com>
> ---
>  tools/bpf/bpftool/cgroup.c |  6 ++++--
>  tools/bpf/bpftool/common.c | 34 ++++++++++++++++++++++++++++++++++
>  tools/bpf/bpftool/main.h   |  2 ++
>  tools/bpf/bpftool/prog.c   | 17 +++++++++--------
>  4 files changed, 49 insertions(+), 10 deletions(-)
>
> diff --git a/tools/bpf/bpftool/cgroup.c b/tools/bpf/bpftool/cgroup.c
> index 3571a281c43f..5e098d9772ae 100644
> --- a/tools/bpf/bpftool/cgroup.c
> +++ b/tools/bpf/bpftool/cgroup.c
> @@ -73,7 +73,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
>                         jsonw_uint_field(json_wtr, "attach_type", attach_type);
>                 jsonw_string_field(json_wtr, "attach_flags",
>                                    attach_flags_str);
> -               jsonw_string_field(json_wtr, "name", info.name);
> +               jsonw_string_field(json_wtr, "name",
> +                                  get_prog_full_name(&info, prog_fd));
>                 jsonw_end_object(json_wtr);
>         } else {
>                 printf("%s%-8u ", level ? "    " : "", info.id);
> @@ -81,7 +82,8 @@ static int show_bpf_prog(int id, enum bpf_attach_type attach_type,
>                         printf("%-15s", attach_type_name[attach_type]);
>                 else
>                         printf("type %-10u", attach_type);
> -               printf(" %-15s %-15s\n", attach_flags_str, info.name);
> +               printf(" %-15s %-15s\n", attach_flags_str,
> +                      get_prog_full_name(&info, prog_fd));
>         }
>
>         close(prog_fd);
> diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
> index fa8eb8134344..b94d0020e4b4 100644
> --- a/tools/bpf/bpftool/common.c
> +++ b/tools/bpf/bpftool/common.c
> @@ -24,6 +24,7 @@
>  #include <bpf/bpf.h>
>  #include <bpf/hashmap.h>
>  #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */
> +#include <bpf/btf.h>
>
>  #include "main.h"
>
> @@ -304,6 +305,39 @@ const char *get_fd_type_name(enum bpf_obj_type type)
>         return names[type];
>  }
>
> +const char *get_prog_full_name(const struct bpf_prog_info *prog_info,
> +                              int prog_fd)

see below about leaks and corrupted pointer, you need to handle string
returning more carefully. Either alway strdup() and then free in each
caller (which honestly sucks from usability and safety point of view)
or let callers pass buffer and buffer size and make sure you put the
result into that buffer (and truncate, if necessary).

> +{
> +       const struct btf_type *func_type;
> +       const struct bpf_func_info finfo;
> +       struct bpf_prog_info info = {};
> +       __u32 info_len = sizeof(info);
> +       const struct btf *prog_btf;
> +
> +       if (strlen(prog_info->name) < BPF_OBJ_NAME_LEN - 1)
> +               return prog_info->name;
> +
> +       if (!prog_info->btf_id || prog_info->nr_func_info == 0)
> +               return prog_info->name;
> +
> +       info.nr_func_info = 1;
> +       info.func_info_rec_size = prog_info->func_info_rec_size;

if prog_info->func_info_rec_size is bigger than sizeof(finfo) you'll
let kernel overwrite stack (corrupting info, probably). Should this be
min of sizeof(finfo) and prog_info->func_info_rec_size?

> +       info.func_info = ptr_to_u64(&finfo);
> +
> +       if (bpf_obj_get_info_by_fd(prog_fd, &info, &info_len))
> +               return prog_info->name;
> +
> +       prog_btf = btf__load_from_kernel_by_id(info.btf_id);
> +       if (libbpf_get_error(prog_btf))

bpftool is using libbpf 1.0 strict mode, so prog_btf will be NULL on
error, so just check for NULL instead of libbpf_get_error().

> +               return prog_info->name;
> +
> +       func_type = btf__type_by_id(prog_btf, finfo.type_id);
> +       if (!func_type || !btf_is_func(func_type))
> +               return prog_info->name;

leaking prog_btf here

> +
> +       return btf__name_by_offset(prog_btf, func_type->name_off);

and here. Also, here you are returning a pointer to a string inside
that prog_btf, so once you fix up the leak you'll be returning invalid
pointer.

> +}
> +
>  int get_fd_type(int fd)
>  {
>         char path[PATH_MAX];

[...]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2022-01-19  4:22 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-18 21:02 [PATCH bpf-next v1] bpftool: adding support for BTF program names Raman Shukhau
2022-01-19  4:21 ` Andrii Nakryiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).