diff mbox series

[bpf-next,v1] selftests/bpf: fix invalid pointer check in get_xlated_program()

Message ID 20230609221637.2631800-1-eddyz87@gmail.com (mailing list archive)
State Accepted
Delegated to: BPF
Headers show
Series [bpf-next,v1] selftests/bpf: fix invalid pointer check in get_xlated_program() | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers fail 1 blamed authors not CCed: song@kernel.org; 9 maintainers not CCed: kpsingh@kernel.org shuah@kernel.org sdf@google.com john.fastabend@gmail.com song@kernel.org mykolal@fb.com linux-kselftest@vger.kernel.org jolsa@kernel.org haoluo@google.com
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 67 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-6 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-13 fail Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on s390x with gcc

Commit Message

Eduard Zingerman June 9, 2023, 10:16 p.m. UTC
Dan Carpenter reported invalid check for calloc() result in
test_verifier.c:get_xlated_program():

  ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program()
  warn: variable dereferenced before check 'buf' (see line 1364)

  ./tools/testing/selftests/bpf/test_verifier.c
    1363		*cnt = xlated_prog_len / buf_element_size;
    1364		*buf = calloc(*cnt, buf_element_size);
    1365		if (!buf) {

  This should be if (!*buf) {

    1366			perror("can't allocate xlated program buffer");
    1367			return -ENOMEM;

This commit refactors the get_xlated_program() to avoid using double
pointer type.

Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/
Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 tools/testing/selftests/bpf/test_verifier.c | 26 ++++++++++++---------
 1 file changed, 15 insertions(+), 11 deletions(-)

Comments

Daniel Borkmann June 12, 2023, 3 p.m. UTC | #1
On 6/10/23 12:16 AM, Eduard Zingerman wrote:
> Dan Carpenter reported invalid check for calloc() result in
> test_verifier.c:get_xlated_program():
> 
>    ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program()
>    warn: variable dereferenced before check 'buf' (see line 1364)
> 
>    ./tools/testing/selftests/bpf/test_verifier.c
>      1363		*cnt = xlated_prog_len / buf_element_size;
>      1364		*buf = calloc(*cnt, buf_element_size);
>      1365		if (!buf) {
> 
>    This should be if (!*buf) {
> 
>      1366			perror("can't allocate xlated program buffer");
>      1367			return -ENOMEM;
> 
> This commit refactors the get_xlated_program() to avoid using double
> pointer type.

Isn't the small reported fix above sufficient? (Either is fine with me though.)

> Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/
> Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests")
> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> ---
>   tools/testing/selftests/bpf/test_verifier.c | 26 ++++++++++++---------
>   1 file changed, 15 insertions(+), 11 deletions(-)
> 
> diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> index 71704a38cac3..c6bc9e26d333 100644
> --- a/tools/testing/selftests/bpf/test_verifier.c
> +++ b/tools/testing/selftests/bpf/test_verifier.c
> @@ -1341,45 +1341,48 @@ static bool cmp_str_seq(const char *log, const char *exp)
>   	return true;
>   }
>   
> -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt)
> +static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt)
>   {
>   	struct bpf_prog_info info = {};
>   	__u32 info_len = sizeof(info);
> +	__u32 buf_element_size;
>   	__u32 xlated_prog_len;
> -	__u32 buf_element_size = sizeof(struct bpf_insn);
> +	struct bpf_insn *buf;
> +
> +	buf_element_size = sizeof(struct bpf_insn);

Just small nit: the `__u32 buf_element_size = sizeof(struct bpf_insn);` could have
stayed as is.

>   	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
>   		perror("bpf_prog_get_info_by_fd failed");
> -		return -1;
> +		return NULL;
>   	}
>   
>   	xlated_prog_len = info.xlated_prog_len;
>   	if (xlated_prog_len % buf_element_size) {
>   		printf("Program length %d is not multiple of %d\n",
>   		       xlated_prog_len, buf_element_size);
> -		return -1;
> +		return NULL;
>   	}
>   
>   	*cnt = xlated_prog_len / buf_element_size;
> -	*buf = calloc(*cnt, buf_element_size);
> +	buf = calloc(*cnt, buf_element_size);
>   	if (!buf) {
>   		perror("can't allocate xlated program buffer");
> -		return -ENOMEM;
> +		return NULL;
>   	}
>   
>   	bzero(&info, sizeof(info));
>   	info.xlated_prog_len = xlated_prog_len;
> -	info.xlated_prog_insns = (__u64)(unsigned long)*buf;
> +	info.xlated_prog_insns = (__u64)(unsigned long)buf;
>   	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
>   		perror("second bpf_prog_get_info_by_fd failed");
>   		goto out_free_buf;
>   	}
>   
> -	return 0;
> +	return buf;
>   
>   out_free_buf:
> -	free(*buf);
> -	return -1;
> +	free(buf);
> +	return NULL;
>   }
>   
>   static bool is_null_insn(struct bpf_insn *insn)
> @@ -1512,7 +1515,8 @@ static bool check_xlated_program(struct bpf_test *test, int fd_prog)
>   	if (!check_expected && !check_unexpected)
>   		goto out;
>   
> -	if (get_xlated_program(fd_prog, &buf, &cnt)) {
> +	buf = get_xlated_program(fd_prog, &cnt);
> +	if (!buf) {
>   		printf("FAIL: can't get xlated program\n");
>   		result = false;
>   		goto out;
>
Eduard Zingerman June 12, 2023, 3:05 p.m. UTC | #2
On Mon, 2023-06-12 at 17:00 +0200, Daniel Borkmann wrote:
> On 6/10/23 12:16 AM, Eduard Zingerman wrote:
> > Dan Carpenter reported invalid check for calloc() result in
> > test_verifier.c:get_xlated_program():
> > 
> >    ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program()
> >    warn: variable dereferenced before check 'buf' (see line 1364)
> > 
> >    ./tools/testing/selftests/bpf/test_verifier.c
> >      1363		*cnt = xlated_prog_len / buf_element_size;
> >      1364		*buf = calloc(*cnt, buf_element_size);
> >      1365		if (!buf) {
> > 
> >    This should be if (!*buf) {
> > 
> >      1366			perror("can't allocate xlated program buffer");
> >      1367			return -ENOMEM;
> > 
> > This commit refactors the get_xlated_program() to avoid using double
> > pointer type.
> 
> Isn't the small reported fix above sufficient? (Either is fine with me though.)

I think it is less prone to mechanical mistakes without double pointers
(in case if this function would be modified sometimes in the future).
But I can rollback to a small fix if you insist.

> 
> > Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> > Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/
> > Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests")
> > Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
> > ---
> >   tools/testing/selftests/bpf/test_verifier.c | 26 ++++++++++++---------
> >   1 file changed, 15 insertions(+), 11 deletions(-)
> > 
> > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
> > index 71704a38cac3..c6bc9e26d333 100644
> > --- a/tools/testing/selftests/bpf/test_verifier.c
> > +++ b/tools/testing/selftests/bpf/test_verifier.c
> > @@ -1341,45 +1341,48 @@ static bool cmp_str_seq(const char *log, const char *exp)
> >   	return true;
> >   }
> >   
> > -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt)
> > +static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt)
> >   {
> >   	struct bpf_prog_info info = {};
> >   	__u32 info_len = sizeof(info);
> > +	__u32 buf_element_size;
> >   	__u32 xlated_prog_len;
> > -	__u32 buf_element_size = sizeof(struct bpf_insn);
> > +	struct bpf_insn *buf;
> > +
> > +	buf_element_size = sizeof(struct bpf_insn);
> 
> Just small nit: the `__u32 buf_element_size = sizeof(struct bpf_insn);` could have
> stayed as is.

Moved it to have "inverse Christmas tree" for declarations,
can send V2 undoing this.

> 
> >   	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
> >   		perror("bpf_prog_get_info_by_fd failed");
> > -		return -1;
> > +		return NULL;
> >   	}
> >   
> >   	xlated_prog_len = info.xlated_prog_len;
> >   	if (xlated_prog_len % buf_element_size) {
> >   		printf("Program length %d is not multiple of %d\n",
> >   		       xlated_prog_len, buf_element_size);
> > -		return -1;
> > +		return NULL;
> >   	}
> >   
> >   	*cnt = xlated_prog_len / buf_element_size;
> > -	*buf = calloc(*cnt, buf_element_size);
> > +	buf = calloc(*cnt, buf_element_size);
> >   	if (!buf) {
> >   		perror("can't allocate xlated program buffer");
> > -		return -ENOMEM;
> > +		return NULL;
> >   	}
> >   
> >   	bzero(&info, sizeof(info));
> >   	info.xlated_prog_len = xlated_prog_len;
> > -	info.xlated_prog_insns = (__u64)(unsigned long)*buf;
> > +	info.xlated_prog_insns = (__u64)(unsigned long)buf;
> >   	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
> >   		perror("second bpf_prog_get_info_by_fd failed");
> >   		goto out_free_buf;
> >   	}
> >   
> > -	return 0;
> > +	return buf;
> >   
> >   out_free_buf:
> > -	free(*buf);
> > -	return -1;
> > +	free(buf);
> > +	return NULL;
> >   }
> >   
> >   static bool is_null_insn(struct bpf_insn *insn)
> > @@ -1512,7 +1515,8 @@ static bool check_xlated_program(struct bpf_test *test, int fd_prog)
> >   	if (!check_expected && !check_unexpected)
> >   		goto out;
> >   
> > -	if (get_xlated_program(fd_prog, &buf, &cnt)) {
> > +	buf = get_xlated_program(fd_prog, &cnt);
> > +	if (!buf) {
> >   		printf("FAIL: can't get xlated program\n");
> >   		result = false;
> >   		goto out;
> > 
>
Daniel Borkmann June 12, 2023, 3:13 p.m. UTC | #3
On 6/12/23 5:05 PM, Eduard Zingerman wrote:
> On Mon, 2023-06-12 at 17:00 +0200, Daniel Borkmann wrote:
>> On 6/10/23 12:16 AM, Eduard Zingerman wrote:
>>> Dan Carpenter reported invalid check for calloc() result in
>>> test_verifier.c:get_xlated_program():
>>>
>>>     ./tools/testing/selftests/bpf/test_verifier.c:1365 get_xlated_program()
>>>     warn: variable dereferenced before check 'buf' (see line 1364)
>>>
>>>     ./tools/testing/selftests/bpf/test_verifier.c
>>>       1363		*cnt = xlated_prog_len / buf_element_size;
>>>       1364		*buf = calloc(*cnt, buf_element_size);
>>>       1365		if (!buf) {
>>>
>>>     This should be if (!*buf) {
>>>
>>>       1366			perror("can't allocate xlated program buffer");
>>>       1367			return -ENOMEM;
>>>
>>> This commit refactors the get_xlated_program() to avoid using double
>>> pointer type.
>>
>> Isn't the small reported fix above sufficient? (Either is fine with me though.)
> 
> I think it is less prone to mechanical mistakes without double pointers
> (in case if this function would be modified sometimes in the future).

Ok.

> But I can rollback to a small fix if you insist.
> 
>>> Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
>>> Closes: https://lore.kernel.org/bpf/ZH7u0hEGVB4MjGZq@moroto/
>>> Fixes: 933ff53191eb ("selftests/bpf: specify expected instructions in test_verifier tests")
>>> Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
>>> ---
>>>    tools/testing/selftests/bpf/test_verifier.c | 26 ++++++++++++---------
>>>    1 file changed, 15 insertions(+), 11 deletions(-)
>>>
>>> diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
>>> index 71704a38cac3..c6bc9e26d333 100644
>>> --- a/tools/testing/selftests/bpf/test_verifier.c
>>> +++ b/tools/testing/selftests/bpf/test_verifier.c
>>> @@ -1341,45 +1341,48 @@ static bool cmp_str_seq(const char *log, const char *exp)
>>>    	return true;
>>>    }
>>>    
>>> -static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt)
>>> +static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt)
>>>    {
>>>    	struct bpf_prog_info info = {};
>>>    	__u32 info_len = sizeof(info);
>>> +	__u32 buf_element_size;
>>>    	__u32 xlated_prog_len;
>>> -	__u32 buf_element_size = sizeof(struct bpf_insn);
>>> +	struct bpf_insn *buf;
>>> +
>>> +	buf_element_size = sizeof(struct bpf_insn);
>>
>> Just small nit: the `__u32 buf_element_size = sizeof(struct bpf_insn);` could have
>> stayed as is.
> 
> Moved it to have "inverse Christmas tree" for declarations,
> can send V2 undoing this.

Nah, it's fine. Fixed up while applying. Thanks!
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c
index 71704a38cac3..c6bc9e26d333 100644
--- a/tools/testing/selftests/bpf/test_verifier.c
+++ b/tools/testing/selftests/bpf/test_verifier.c
@@ -1341,45 +1341,48 @@  static bool cmp_str_seq(const char *log, const char *exp)
 	return true;
 }
 
-static int get_xlated_program(int fd_prog, struct bpf_insn **buf, int *cnt)
+static struct bpf_insn *get_xlated_program(int fd_prog, int *cnt)
 {
 	struct bpf_prog_info info = {};
 	__u32 info_len = sizeof(info);
+	__u32 buf_element_size;
 	__u32 xlated_prog_len;
-	__u32 buf_element_size = sizeof(struct bpf_insn);
+	struct bpf_insn *buf;
+
+	buf_element_size = sizeof(struct bpf_insn);
 
 	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
 		perror("bpf_prog_get_info_by_fd failed");
-		return -1;
+		return NULL;
 	}
 
 	xlated_prog_len = info.xlated_prog_len;
 	if (xlated_prog_len % buf_element_size) {
 		printf("Program length %d is not multiple of %d\n",
 		       xlated_prog_len, buf_element_size);
-		return -1;
+		return NULL;
 	}
 
 	*cnt = xlated_prog_len / buf_element_size;
-	*buf = calloc(*cnt, buf_element_size);
+	buf = calloc(*cnt, buf_element_size);
 	if (!buf) {
 		perror("can't allocate xlated program buffer");
-		return -ENOMEM;
+		return NULL;
 	}
 
 	bzero(&info, sizeof(info));
 	info.xlated_prog_len = xlated_prog_len;
-	info.xlated_prog_insns = (__u64)(unsigned long)*buf;
+	info.xlated_prog_insns = (__u64)(unsigned long)buf;
 	if (bpf_prog_get_info_by_fd(fd_prog, &info, &info_len)) {
 		perror("second bpf_prog_get_info_by_fd failed");
 		goto out_free_buf;
 	}
 
-	return 0;
+	return buf;
 
 out_free_buf:
-	free(*buf);
-	return -1;
+	free(buf);
+	return NULL;
 }
 
 static bool is_null_insn(struct bpf_insn *insn)
@@ -1512,7 +1515,8 @@  static bool check_xlated_program(struct bpf_test *test, int fd_prog)
 	if (!check_expected && !check_unexpected)
 		goto out;
 
-	if (get_xlated_program(fd_prog, &buf, &cnt)) {
+	buf = get_xlated_program(fd_prog, &cnt);
+	if (!buf) {
 		printf("FAIL: can't get xlated program\n");
 		result = false;
 		goto out;