netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net] bpf: fix states equal logic for varlen access
@ 2016-11-28 19:44 Josef Bacik
  2016-11-29  3:04 ` Alexei Starovoitov
  0 siblings, 1 reply; 5+ messages in thread
From: Josef Bacik @ 2016-11-28 19:44 UTC (permalink / raw)
  To: davem, netdev, daniel, ast, jannh

If we have a branch that looks something like this

int foo = map->value;
if (condition) {
  foo += blah;
} else {
  foo = bar;
}
map->array[foo] = baz;

We will incorrectly assume that the !condition branch is equal to the condition
branch as the register for foo will be UNKNOWN_VALUE in both cases.  We need to
adjust this logic to only do this if we didn't do a varlen access after we
processed the !condition branch, otherwise we have different ranges and need to
check the other branch as well.

Signed-off-by: Josef Bacik <jbacik@fb.com>
---
 kernel/bpf/verifier.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 89f787c..2c8a688 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2478,6 +2478,7 @@ static bool states_equal(struct bpf_verifier_env *env,
 {
 	struct bpf_reg_state *rold, *rcur;
 	int i;
+	bool map_access = env->varlen_map_value_access;
 
 	for (i = 0; i < MAX_BPF_REG; i++) {
 		rold = &old->regs[i];
@@ -2489,12 +2490,17 @@ static bool states_equal(struct bpf_verifier_env *env,
 		/* If the ranges were not the same, but everything else was and
 		 * we didn't do a variable access into a map then we are a-ok.
 		 */
-		if (!env->varlen_map_value_access &&
+		if (!map_access &&
 		    rold->type == rcur->type && rold->imm == rcur->imm)
 			continue;
 
+		/* If we didn't map access then again we don't care about the
+		 * mismatched range values and it's ok if our old type was
+		 * UNKNOWN and we didn't go to a NOT_INIT'ed reg.
+		 */
 		if (rold->type == NOT_INIT ||
-		    (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT))
+		    (!map_access && (rold->type == UNKNOWN_VALUE &&
+				     rcur->type != NOT_INIT)))
 			continue;
 
 		if (rold->type == PTR_TO_PACKET && rcur->type == PTR_TO_PACKET &&
-- 
2.7.4

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

* Re: [PATCH net] bpf: fix states equal logic for varlen access
  2016-11-28 19:44 [PATCH net] bpf: fix states equal logic for varlen access Josef Bacik
@ 2016-11-29  3:04 ` Alexei Starovoitov
  2016-11-29  9:33   ` Daniel Borkmann
  2016-11-29 14:45   ` Josef Bacik
  0 siblings, 2 replies; 5+ messages in thread
From: Alexei Starovoitov @ 2016-11-29  3:04 UTC (permalink / raw)
  To: Josef Bacik; +Cc: davem, netdev, daniel, ast, jannh

On Mon, Nov 28, 2016 at 02:44:10PM -0500, Josef Bacik wrote:
> If we have a branch that looks something like this
> 
> int foo = map->value;
> if (condition) {
>   foo += blah;
> } else {
>   foo = bar;
> }
> map->array[foo] = baz;
> 
> We will incorrectly assume that the !condition branch is equal to the condition
> branch as the register for foo will be UNKNOWN_VALUE in both cases.  We need to
> adjust this logic to only do this if we didn't do a varlen access after we
> processed the !condition branch, otherwise we have different ranges and need to
> check the other branch as well.
> 
> Signed-off-by: Josef Bacik <jbacik@fb.com>
> ---
>  kernel/bpf/verifier.c | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 89f787c..2c8a688 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -2478,6 +2478,7 @@ static bool states_equal(struct bpf_verifier_env *env,
>  {
>  	struct bpf_reg_state *rold, *rcur;
>  	int i;
> +	bool map_access = env->varlen_map_value_access;

that's a bit misleading name for the variable.
Pls call it varlen_map_access.

>  	for (i = 0; i < MAX_BPF_REG; i++) {
>  		rold = &old->regs[i];
> @@ -2489,12 +2490,17 @@ static bool states_equal(struct bpf_verifier_env *env,
>  		/* If the ranges were not the same, but everything else was and
>  		 * we didn't do a variable access into a map then we are a-ok.
>  		 */
> -		if (!env->varlen_map_value_access &&
> +		if (!map_access &&
>  		    rold->type == rcur->type && rold->imm == rcur->imm)

just noticed that this one is missing comparing rold->id == rcur->id

>  			continue;
>  
> +		/* If we didn't map access then again we don't care about the
> +		 * mismatched range values and it's ok if our old type was
> +		 * UNKNOWN and we didn't go to a NOT_INIT'ed reg.
> +		 */
>  		if (rold->type == NOT_INIT ||
> -		    (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT))
> +		    (!map_access && (rold->type == UNKNOWN_VALUE &&
> +				     rcur->type != NOT_INIT)))

please drop unnecessary ( )

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

* Re: [PATCH net] bpf: fix states equal logic for varlen access
  2016-11-29  3:04 ` Alexei Starovoitov
@ 2016-11-29  9:33   ` Daniel Borkmann
  2016-11-29 14:45   ` Josef Bacik
  1 sibling, 0 replies; 5+ messages in thread
From: Daniel Borkmann @ 2016-11-29  9:33 UTC (permalink / raw)
  To: Alexei Starovoitov, Josef Bacik; +Cc: davem, netdev, ast, jannh

On 11/29/2016 04:04 AM, Alexei Starovoitov wrote:
> On Mon, Nov 28, 2016 at 02:44:10PM -0500, Josef Bacik wrote:
>> If we have a branch that looks something like this
>>
>> int foo = map->value;
>> if (condition) {
>>    foo += blah;
>> } else {
>>    foo = bar;
>> }
>> map->array[foo] = baz;
>>
>> We will incorrectly assume that the !condition branch is equal to the condition
>> branch as the register for foo will be UNKNOWN_VALUE in both cases.  We need to
>> adjust this logic to only do this if we didn't do a varlen access after we
>> processed the !condition branch, otherwise we have different ranges and need to
>> check the other branch as well.

Fixes: 484611357c19 ("bpf: allow access into map value arrays")
Reported-by: Jann Horn <jannh@google.com>

>> Signed-off-by: Josef Bacik <jbacik@fb.com>

Please also add a test case to tools/testing/selftests/bpf/test_verifier.c for
net-next tree, so we can make sure we catch this in future. Test could look
like that after this fix it fails by the verifier, but before it doesn't due
to false state pruning.

>>   kernel/bpf/verifier.c | 10 ++++++++--
>>   1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 89f787c..2c8a688 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -2478,6 +2478,7 @@ static bool states_equal(struct bpf_verifier_env *env,
>>   {
>>   	struct bpf_reg_state *rold, *rcur;
>>   	int i;
>> +	bool map_access = env->varlen_map_value_access;
>
> that's a bit misleading name for the variable.
> Pls call it varlen_map_access.

Nit: while at it, please also move it up as first var (netdev has reverse
xmas tree style).

>>   	for (i = 0; i < MAX_BPF_REG; i++) {
>>   		rold = &old->regs[i];
>> @@ -2489,12 +2490,17 @@ static bool states_equal(struct bpf_verifier_env *env,
>>   		/* If the ranges were not the same, but everything else was and
>>   		 * we didn't do a variable access into a map then we are a-ok.
>>   		 */
>> -		if (!env->varlen_map_value_access &&
>> +		if (!map_access &&
>>   		    rold->type == rcur->type && rold->imm == rcur->imm)
>
> just noticed that this one is missing comparing rold->id == rcur->id
>
>>   			continue;
>>
>> +		/* If we didn't map access then again we don't care about the
>> +		 * mismatched range values and it's ok if our old type was
>> +		 * UNKNOWN and we didn't go to a NOT_INIT'ed reg.
>> +		 */
>>   		if (rold->type == NOT_INIT ||
>> -		    (rold->type == UNKNOWN_VALUE && rcur->type != NOT_INIT))
>> +		    (!map_access && (rold->type == UNKNOWN_VALUE &&
>> +				     rcur->type != NOT_INIT)))
>
> please drop unnecessary ( )

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

* Re: [PATCH net] bpf: fix states equal logic for varlen access
  2016-11-29  3:04 ` Alexei Starovoitov
  2016-11-29  9:33   ` Daniel Borkmann
@ 2016-11-29 14:45   ` Josef Bacik
  2016-11-29 16:49     ` Alexei Starovoitov
  1 sibling, 1 reply; 5+ messages in thread
From: Josef Bacik @ 2016-11-29 14:45 UTC (permalink / raw)
  To: Alexei Starovoitov; +Cc: davem, netdev, daniel, ast, jannh

On 11/28/2016 10:04 PM, Alexei Starovoitov wrote:
> On Mon, Nov 28, 2016 at 02:44:10PM -0500, Josef Bacik wrote:
>> If we have a branch that looks something like this
>>
>> int foo = map->value;
>> if (condition) {
>>   foo += blah;
>> } else {
>>   foo = bar;
>> }
>> map->array[foo] = baz;
>>
>> We will incorrectly assume that the !condition branch is equal to the condition
>> branch as the register for foo will be UNKNOWN_VALUE in both cases.  We need to
>> adjust this logic to only do this if we didn't do a varlen access after we
>> processed the !condition branch, otherwise we have different ranges and need to
>> check the other branch as well.
>>
>> Signed-off-by: Josef Bacik <jbacik@fb.com>
>> ---
>>  kernel/bpf/verifier.c | 10 ++++++++--
>>  1 file changed, 8 insertions(+), 2 deletions(-)
>>
>> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
>> index 89f787c..2c8a688 100644
>> --- a/kernel/bpf/verifier.c
>> +++ b/kernel/bpf/verifier.c
>> @@ -2478,6 +2478,7 @@ static bool states_equal(struct bpf_verifier_env *env,
>>  {
>>  	struct bpf_reg_state *rold, *rcur;
>>  	int i;
>> +	bool map_access = env->varlen_map_value_access;
>
> that's a bit misleading name for the variable.
> Pls call it varlen_map_access.
>
>>  	for (i = 0; i < MAX_BPF_REG; i++) {
>>  		rold = &old->regs[i];
>> @@ -2489,12 +2490,17 @@ static bool states_equal(struct bpf_verifier_env *env,
>>  		/* If the ranges were not the same, but everything else was and
>>  		 * we didn't do a variable access into a map then we are a-ok.
>>  		 */
>> -		if (!env->varlen_map_value_access &&
>> +		if (!map_access &&
>>  		    rold->type == rcur->type && rold->imm == rcur->imm)
>
> just noticed that this one is missing comparing rold->id == rcur->id
>

Do you want me to fix that here?  I'll fix up the rest of the stuff, and Daniels 
things as well.  Thanks,

Josef

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

* Re: [PATCH net] bpf: fix states equal logic for varlen access
  2016-11-29 14:45   ` Josef Bacik
@ 2016-11-29 16:49     ` Alexei Starovoitov
  0 siblings, 0 replies; 5+ messages in thread
From: Alexei Starovoitov @ 2016-11-29 16:49 UTC (permalink / raw)
  To: Josef Bacik; +Cc: davem, netdev, daniel, ast, jannh

On Tue, Nov 29, 2016 at 09:45:33AM -0500, Josef Bacik wrote:
> On 11/28/2016 10:04 PM, Alexei Starovoitov wrote:
> >On Mon, Nov 28, 2016 at 02:44:10PM -0500, Josef Bacik wrote:
> >>If we have a branch that looks something like this
> >>
> >>int foo = map->value;
> >>if (condition) {
> >>  foo += blah;
> >>} else {
> >>  foo = bar;
> >>}
> >>map->array[foo] = baz;
> >>
> >>We will incorrectly assume that the !condition branch is equal to the condition
> >>branch as the register for foo will be UNKNOWN_VALUE in both cases.  We need to
> >>adjust this logic to only do this if we didn't do a varlen access after we
> >>processed the !condition branch, otherwise we have different ranges and need to
> >>check the other branch as well.
> >>
> >>Signed-off-by: Josef Bacik <jbacik@fb.com>
> >>---
> >> kernel/bpf/verifier.c | 10 ++++++++--
> >> 1 file changed, 8 insertions(+), 2 deletions(-)
> >>
> >>diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> >>index 89f787c..2c8a688 100644
> >>--- a/kernel/bpf/verifier.c
> >>+++ b/kernel/bpf/verifier.c
> >>@@ -2478,6 +2478,7 @@ static bool states_equal(struct bpf_verifier_env *env,
> >> {
> >> 	struct bpf_reg_state *rold, *rcur;
> >> 	int i;
> >>+	bool map_access = env->varlen_map_value_access;
> >
> >that's a bit misleading name for the variable.
> >Pls call it varlen_map_access.
> >
> >> 	for (i = 0; i < MAX_BPF_REG; i++) {
> >> 		rold = &old->regs[i];
> >>@@ -2489,12 +2490,17 @@ static bool states_equal(struct bpf_verifier_env *env,
> >> 		/* If the ranges were not the same, but everything else was and
> >> 		 * we didn't do a variable access into a map then we are a-ok.
> >> 		 */
> >>-		if (!env->varlen_map_value_access &&
> >>+		if (!map_access &&
> >> 		    rold->type == rcur->type && rold->imm == rcur->imm)
> >
> >just noticed that this one is missing comparing rold->id == rcur->id
> >
> 
> Do you want me to fix that here?  I'll fix up the rest of the stuff, and
> Daniels things as well.  Thanks,

Nevermind. Comparing 'id' is not needed in net, only in net-next.

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

end of thread, other threads:[~2016-11-29 16:49 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-28 19:44 [PATCH net] bpf: fix states equal logic for varlen access Josef Bacik
2016-11-29  3:04 ` Alexei Starovoitov
2016-11-29  9:33   ` Daniel Borkmann
2016-11-29 14:45   ` Josef Bacik
2016-11-29 16:49     ` Alexei Starovoitov

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).