diff mbox

[net] bpf: don't zero out the info struct in bpf_obj_get_info_by_fd()

Message ID 20170725221612.6937-1-jakub.kicinski@netronome.com
State Accepted, archived
Delegated to: David Miller
Headers show

Commit Message

Jakub Kicinski July 25, 2017, 10:16 p.m. UTC
The buffer passed to bpf_obj_get_info_by_fd() should be initialized
to zeros.  Kernel will enforce that to guarantee we can safely extend
info structures in the future.

Making the bpf_obj_get_info_by_fd() call in libbpf perform the zeroing
is problematic, however, since some members of the info structures
may need to be initialized by the callers (for instance pointers
to buffers to which kernel is to dump translated and jited images).

Remove the zeroing and fix up the in-tree callers before any kernel
has been released with this code.

As Daniel points out this seems to be the intended operation anyway,
since commit 95b9afd3987f ("bpf: Test for bpf ID") is itself setting
the buffer pointers before calling bpf_obj_get_info_by_fd().

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
I have a small patch to add checking if kernel actually populated
the instruction dumps which I will post after this ends up in net-next.

 tools/lib/bpf/bpf.c                      | 1 -
 tools/testing/selftests/bpf/test_progs.c | 8 ++++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

Comments

Daniel Borkmann July 25, 2017, 10:59 p.m. UTC | #1
On 07/26/2017 12:16 AM, Jakub Kicinski wrote:
> The buffer passed to bpf_obj_get_info_by_fd() should be initialized
> to zeros.  Kernel will enforce that to guarantee we can safely extend
> info structures in the future.
>
> Making the bpf_obj_get_info_by_fd() call in libbpf perform the zeroing
> is problematic, however, since some members of the info structures
> may need to be initialized by the callers (for instance pointers
> to buffers to which kernel is to dump translated and jited images).
>
> Remove the zeroing and fix up the in-tree callers before any kernel
> has been released with this code.
>
> As Daniel points out this seems to be the intended operation anyway,
> since commit 95b9afd3987f ("bpf: Test for bpf ID") is itself setting
> the buffer pointers before calling bpf_obj_get_info_by_fd().
>
> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> ---
> I have a small patch to add checking if kernel actually populated
> the instruction dumps which I will post after this ends up in net-next.
>
>   tools/lib/bpf/bpf.c                      | 1 -
>   tools/testing/selftests/bpf/test_progs.c | 8 ++++++--
>   2 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
> index 412a7c82995a..256f571f2ab5 100644
> --- a/tools/lib/bpf/bpf.c
> +++ b/tools/lib/bpf/bpf.c
> @@ -314,7 +314,6 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
>   	int err;
>
>   	bzero(&attr, sizeof(attr));
> -	bzero(info, *info_len);
>   	attr.info.bpf_fd = prog_fd;
>   	attr.info.info_len = *info_len;
>   	attr.info.info = ptr_to_u64(info);
> diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
> index 5855cd3d3d45..1f7dd35551b9 100644
> --- a/tools/testing/selftests/bpf/test_progs.c
> +++ b/tools/testing/selftests/bpf/test_progs.c
> @@ -340,6 +340,7 @@ static void test_bpf_obj_id(void)
>
>   		/* Check getting prog info */
>   		info_len = sizeof(struct bpf_prog_info) * 2;
> +		bzero(&prog_infos[i], info_len);
>   		prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns);
>   		prog_infos[i].jited_prog_len = sizeof(jited_insns);
>   		prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns);
> @@ -369,6 +370,7 @@ static void test_bpf_obj_id(void)
>
>   		/* Check getting map info */
>   		info_len = sizeof(struct bpf_map_info) * 2;
> +		bzero(&map_infos[i], info_len);
>   		err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i],
>   					     &info_len);
>   		if (CHECK(err ||
> @@ -394,7 +396,7 @@ static void test_bpf_obj_id(void)
>   	nr_id_found = 0;
>   	next_id = 0;
>   	while (!bpf_prog_get_next_id(next_id, &next_id)) {
> -		struct bpf_prog_info prog_info;
> +		struct bpf_prog_info prog_info = {};
>   		int prog_fd;
>
>   		info_len = sizeof(prog_info);
> @@ -418,6 +420,8 @@ static void test_bpf_obj_id(void)
>   		nr_id_found++;
>
>   		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
> +		prog_infos[i].jited_prog_insns = 0;
> +		prog_infos[i].xlated_prog_insns = 0;

Can you elaborate why this one above is needed?

>   		CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
>   		      memcmp(&prog_info, &prog_infos[i], info_len),
>   		      "get-prog-info(next_id->fd)",
> @@ -436,7 +440,7 @@ static void test_bpf_obj_id(void)
>   	nr_id_found = 0;
>   	next_id = 0;
>   	while (!bpf_map_get_next_id(next_id, &next_id)) {
> -		struct bpf_map_info map_info;
> +		struct bpf_map_info map_info = {};
>   		int map_fd;
>
>   		info_len = sizeof(map_info);
>
Jakub Kicinski July 25, 2017, 11:15 p.m. UTC | #2
On Wed, 26 Jul 2017 00:59:49 +0200, Daniel Borkmann wrote:
> > @@ -418,6 +420,8 @@ static void test_bpf_obj_id(void)
> >   		nr_id_found++;
> >
> >   		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
> > +		prog_infos[i].jited_prog_insns = 0;
> > +		prog_infos[i].xlated_prog_insns = 0;  
> 
> Can you elaborate why this one above is needed?

Ah, I removed the comment about it at the last minute.  The check below
compares the info we get here with info we got reading the programs in
the earlier loop - using memcmp().  This call, however, doesn't fill in
the pointers for jited and xlated images, so the memcmp() would fail.

It used to work when bpf_obj_get_info_by_fd() was zeroing info, since
the pointers would be cleared by it, and no dump ever returned, it
didn't matter that the call sites differ.

> >   		CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
> >   		      memcmp(&prog_info, &prog_infos[i], info_len),
> >   		      "get-prog-info(next_id->fd)",
Jakub Kicinski July 25, 2017, 11:20 p.m. UTC | #3
On Tue, 25 Jul 2017 16:15:47 -0700, Jakub Kicinski wrote:
> On Wed, 26 Jul 2017 00:59:49 +0200, Daniel Borkmann wrote:
> > > @@ -418,6 +420,8 @@ static void test_bpf_obj_id(void)
> > >   		nr_id_found++;
> > >
> > >   		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
> > > +		prog_infos[i].jited_prog_insns = 0;
> > > +		prog_infos[i].xlated_prog_insns = 0;    
> > 
> > Can you elaborate why this one above is needed?  
> 
> Ah, I removed the comment about it at the last minute.  The check below
> compares the info we get here with info we got reading the programs in
> the earlier loop - using memcmp().  This call, however, doesn't fill in
> the pointers for jited and xlated images, so the memcmp() would fail.
> 
> It used to work when bpf_obj_get_info_by_fd() was zeroing info, since
> the pointers would be cleared by it, and no dump ever returned, it
> didn't matter that the call sites differ.

FWIW the comment was this:
+               /* Clear the insns pointers, we're not requesting dumps here.   
+                * Otherwise the byte-by-byte comparison below would fail.      
+                */ 

> > >   		CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
> > >   		      memcmp(&prog_info, &prog_infos[i], info_len),
> > >   		      "get-prog-info(next_id->fd)",  
>
Daniel Borkmann July 25, 2017, 11:29 p.m. UTC | #4
On 07/26/2017 01:15 AM, Jakub Kicinski wrote:
> On Wed, 26 Jul 2017 00:59:49 +0200, Daniel Borkmann wrote:
>>> @@ -418,6 +420,8 @@ static void test_bpf_obj_id(void)
>>>    		nr_id_found++;
>>>
>>>    		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
>>> +		prog_infos[i].jited_prog_insns = 0;
>>> +		prog_infos[i].xlated_prog_insns = 0;
>>
>> Can you elaborate why this one above is needed?
>
> Ah, I removed the comment about it at the last minute.  The check below
> compares the info we get here with info we got reading the programs in
> the earlier loop - using memcmp().

Yep, makes sense. I mistook it for 'length' given it is not NULL but 0,
but that is due to __aligned_u64. ;) Anyway, thanks for clarifying.

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
David Miller July 27, 2017, 12:03 a.m. UTC | #5
From: Jakub Kicinski <jakub.kicinski@netronome.com>
Date: Tue, 25 Jul 2017 15:16:12 -0700

> The buffer passed to bpf_obj_get_info_by_fd() should be initialized
> to zeros.  Kernel will enforce that to guarantee we can safely extend
> info structures in the future.
> 
> Making the bpf_obj_get_info_by_fd() call in libbpf perform the zeroing
> is problematic, however, since some members of the info structures
> may need to be initialized by the callers (for instance pointers
> to buffers to which kernel is to dump translated and jited images).
> 
> Remove the zeroing and fix up the in-tree callers before any kernel
> has been released with this code.
> 
> As Daniel points out this seems to be the intended operation anyway,
> since commit 95b9afd3987f ("bpf: Test for bpf ID") is itself setting
> the buffer pointers before calling bpf_obj_get_info_by_fd().
> 
> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>

Applied, thanks Jakub.
diff mbox

Patch

diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 412a7c82995a..256f571f2ab5 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -314,7 +314,6 @@  int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
 	int err;
 
 	bzero(&attr, sizeof(attr));
-	bzero(info, *info_len);
 	attr.info.bpf_fd = prog_fd;
 	attr.info.info_len = *info_len;
 	attr.info.info = ptr_to_u64(info);
diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c
index 5855cd3d3d45..1f7dd35551b9 100644
--- a/tools/testing/selftests/bpf/test_progs.c
+++ b/tools/testing/selftests/bpf/test_progs.c
@@ -340,6 +340,7 @@  static void test_bpf_obj_id(void)
 
 		/* Check getting prog info */
 		info_len = sizeof(struct bpf_prog_info) * 2;
+		bzero(&prog_infos[i], info_len);
 		prog_infos[i].jited_prog_insns = ptr_to_u64(jited_insns);
 		prog_infos[i].jited_prog_len = sizeof(jited_insns);
 		prog_infos[i].xlated_prog_insns = ptr_to_u64(xlated_insns);
@@ -369,6 +370,7 @@  static void test_bpf_obj_id(void)
 
 		/* Check getting map info */
 		info_len = sizeof(struct bpf_map_info) * 2;
+		bzero(&map_infos[i], info_len);
 		err = bpf_obj_get_info_by_fd(map_fds[i], &map_infos[i],
 					     &info_len);
 		if (CHECK(err ||
@@ -394,7 +396,7 @@  static void test_bpf_obj_id(void)
 	nr_id_found = 0;
 	next_id = 0;
 	while (!bpf_prog_get_next_id(next_id, &next_id)) {
-		struct bpf_prog_info prog_info;
+		struct bpf_prog_info prog_info = {};
 		int prog_fd;
 
 		info_len = sizeof(prog_info);
@@ -418,6 +420,8 @@  static void test_bpf_obj_id(void)
 		nr_id_found++;
 
 		err = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &info_len);
+		prog_infos[i].jited_prog_insns = 0;
+		prog_infos[i].xlated_prog_insns = 0;
 		CHECK(err || info_len != sizeof(struct bpf_prog_info) ||
 		      memcmp(&prog_info, &prog_infos[i], info_len),
 		      "get-prog-info(next_id->fd)",
@@ -436,7 +440,7 @@  static void test_bpf_obj_id(void)
 	nr_id_found = 0;
 	next_id = 0;
 	while (!bpf_map_get_next_id(next_id, &next_id)) {
-		struct bpf_map_info map_info;
+		struct bpf_map_info map_info = {};
 		int map_fd;
 
 		info_len = sizeof(map_info);