diff mbox series

bpftool: Fix prog dump by tag

Message ID 20190118125817.10763-1-jolsa@kernel.org
State Accepted
Delegated to: BPF Maintainers
Headers show
Series bpftool: Fix prog dump by tag | expand

Commit Message

Jiri Olsa Jan. 18, 2019, 12:58 p.m. UTC
Lance reported an issue with bpftool not being able to
dump program if there are more programs loaded and you
want to dump any but the first program, like:

  # bpftool prog
  28: kprobe  name trace_req_start  tag 1dfc28ba8b3dd597  gpl
  	loaded_at 2019-01-18T17:02:40+1100  uid 0
  	xlated 112B  jited 109B  memlock 4096B  map_ids 13
  29: kprobe  name trace_req_compl  tag 5b6a5ecc6030a683  gpl
  	loaded_at 2019-01-18T17:02:40+1100  uid 0
  	xlated 928B  jited 575B  memlock 4096B  map_ids 13,14
  #  bpftool prog dum jited tag 1dfc28ba8b3dd597
   0:	push   %rbp
   1:	mov    %rsp,%rbp
  ...

  #  bpftool prog dum jited tag 5b6a5ecc6030a683
  Error: can't get prog info (29): Bad address

The problem is in the prog_fd_by_tag function not cleaning
the struct bpf_prog_info before another request, so the
previous program length is still in there and kernel assumes
it needs to dump the program, which fails because there's no
user pointer set.

Moving the struct bpf_prog_info declaration into the loop,
so it gets cleaned before each query.

Reported-by: Lance Digby <ldigby@redhat.com>
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/bpf/bpftool/prog.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Quentin Monnet Jan. 18, 2019, 6:19 p.m. UTC | #1
2019-01-18 13:58 UTC+0100 ~ Jiri Olsa <jolsa@kernel.org>
> Lance reported an issue with bpftool not being able to
> dump program if there are more programs loaded and you
> want to dump any but the first program, like:
> 
>   # bpftool prog
>   28: kprobe  name trace_req_start  tag 1dfc28ba8b3dd597  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 112B  jited 109B  memlock 4096B  map_ids 13
>   29: kprobe  name trace_req_compl  tag 5b6a5ecc6030a683  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 928B  jited 575B  memlock 4096B  map_ids 13,14
>   #  bpftool prog dum jited tag 1dfc28ba8b3dd597
>    0:	push   %rbp
>    1:	mov    %rsp,%rbp
>   ...
> 
>   #  bpftool prog dum jited tag 5b6a5ecc6030a683
>   Error: can't get prog info (29): Bad address
> 
> The problem is in the prog_fd_by_tag function not cleaning
> the struct bpf_prog_info before another request, so the
> previous program length is still in there and kernel assumes
> it needs to dump the program, which fails because there's no
> user pointer set.
> 
> Moving the struct bpf_prog_info declaration into the loop,
> so it gets cleaned before each query.
> 
> Reported-by: Lance Digby <ldigby@redhat.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Thanks for the fix!

Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Jakub Kicinski Jan. 18, 2019, 7:16 p.m. UTC | #2
On Fri, 18 Jan 2019 13:58:17 +0100, Jiri Olsa wrote:
> Lance reported an issue with bpftool not being able to
> dump program if there are more programs loaded and you
> want to dump any but the first program, like:
> 
>   # bpftool prog
>   28: kprobe  name trace_req_start  tag 1dfc28ba8b3dd597  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 112B  jited 109B  memlock 4096B  map_ids 13
>   29: kprobe  name trace_req_compl  tag 5b6a5ecc6030a683  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 928B  jited 575B  memlock 4096B  map_ids 13,14
>   #  bpftool prog dum jited tag 1dfc28ba8b3dd597
>    0:	push   %rbp
>    1:	mov    %rsp,%rbp
>   ...
> 
>   #  bpftool prog dum jited tag 5b6a5ecc6030a683
>   Error: can't get prog info (29): Bad address
> 
> The problem is in the prog_fd_by_tag function not cleaning
> the struct bpf_prog_info before another request, so the
> previous program length is still in there and kernel assumes
> it needs to dump the program, which fails because there's no
> user pointer set.
> 
> Moving the struct bpf_prog_info declaration into the loop,
> so it gets cleaned before each query.
> 
> Reported-by: Lance Digby <ldigby@redhat.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Aw.

Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>

Thanks!
Daniel Borkmann Jan. 23, 2019, 8:58 a.m. UTC | #3
On 01/18/2019 01:58 PM, Jiri Olsa wrote:
> Lance reported an issue with bpftool not being able to
> dump program if there are more programs loaded and you
> want to dump any but the first program, like:
> 
>   # bpftool prog
>   28: kprobe  name trace_req_start  tag 1dfc28ba8b3dd597  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 112B  jited 109B  memlock 4096B  map_ids 13
>   29: kprobe  name trace_req_compl  tag 5b6a5ecc6030a683  gpl
>   	loaded_at 2019-01-18T17:02:40+1100  uid 0
>   	xlated 928B  jited 575B  memlock 4096B  map_ids 13,14
>   #  bpftool prog dum jited tag 1dfc28ba8b3dd597
>    0:	push   %rbp
>    1:	mov    %rsp,%rbp
>   ...
> 
>   #  bpftool prog dum jited tag 5b6a5ecc6030a683
>   Error: can't get prog info (29): Bad address
> 
> The problem is in the prog_fd_by_tag function not cleaning
> the struct bpf_prog_info before another request, so the
> previous program length is still in there and kernel assumes
> it needs to dump the program, which fails because there's no
> user pointer set.
> 
> Moving the struct bpf_prog_info declaration into the loop,
> so it gets cleaned before each query.
> 
> Reported-by: Lance Digby <ldigby@redhat.com>
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>

Applied to bpf and added Fixes tags, thanks!
diff mbox series

Patch

diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 2d1bb7d6ff51..b54ed82b9589 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -78,13 +78,14 @@  static void print_boot_time(__u64 nsecs, char *buf, unsigned int size)
 
 static int prog_fd_by_tag(unsigned char *tag)
 {
-	struct bpf_prog_info info = {};
-	__u32 len = sizeof(info);
 	unsigned int id = 0;
 	int err;
 	int fd;
 
 	while (true) {
+		struct bpf_prog_info info = {};
+		__u32 len = sizeof(info);
+
 		err = bpf_prog_get_next_id(id, &id);
 		if (err) {
 			p_err("%s", strerror(errno));