All of lore.kernel.org
 help / color / mirror / Atom feed
* [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt
@ 2018-05-16 21:46 John Fastabend
  2018-05-16 21:46 ` [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update John Fastabend
  2018-05-17 16:15 ` [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt Martin KaFai Lau
  0 siblings, 2 replies; 6+ messages in thread
From: John Fastabend @ 2018-05-16 21:46 UTC (permalink / raw)
  To: ast, daniel; +Cc: netdev

If the user were to only attach one of the parse or verdict programs
then it is possible a subsequent sockmap update could incorrectly
decrement the refcnt on the program. This happens because in the
rollback logic, after an error, we have to decrement the program
reference count when its been incremented. However, we only increment
the program reference count if the user has both a verdict and a
parse program. The reason for this is because, at least at the
moment, both are required for any one to be meaningful. The problem
fixed here is in the rollback path we decrement the program refcnt
even if only one existing. But we never incremented the refcnt in
the first place creating an imbalance.

This patch fixes the error path to handle this case.

Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
Reported-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 kernel/bpf/sockmap.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index 098eca5..f03aaa8 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -1717,10 +1717,10 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
 	if (tx_msg) {
 		tx_msg = bpf_prog_inc_not_zero(stab->bpf_tx_msg);
 		if (IS_ERR(tx_msg)) {
-			if (verdict)
-				bpf_prog_put(verdict);
-			if (parse)
+			if (parse && verdict) {
 				bpf_prog_put(parse);
+				bpf_prog_put(verdict);
+			}
 			return PTR_ERR(tx_msg);
 		}
 	}
@@ -1805,10 +1805,10 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
 out_free:
 	smap_release_sock(psock, sock);
 out_progs:
-	if (verdict)
-		bpf_prog_put(verdict);
-	if (parse)
+	if (parse && verdict) {
 		bpf_prog_put(parse);
+		bpf_prog_put(verdict);
+	}
 	if (tx_msg)
 		bpf_prog_put(tx_msg);
 	write_unlock_bh(&sock->sk_callback_lock);

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

* [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update
  2018-05-16 21:46 [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt John Fastabend
@ 2018-05-16 21:46 ` John Fastabend
  2018-05-17 16:16   ` Martin KaFai Lau
  2018-05-17 20:31   ` Daniel Borkmann
  2018-05-17 16:15 ` [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt Martin KaFai Lau
  1 sibling, 2 replies; 6+ messages in thread
From: John Fastabend @ 2018-05-16 21:46 UTC (permalink / raw)
  To: ast, daniel; +Cc: netdev

In the sockmap design BPF programs (SK_SKB_STREAM_PARSER and
SK_SKB_STREAM_VERDICT) are attached to the sockmap map type and when
a sock is added to the map the programs are used by the socket.
However, sockmap updates from both userspace and BPF programs can
happen concurrently with the attach and detach of these programs.

To resolve this we use the bpf_prog_inc_not_zero and a READ_ONCE()
primitive to ensure the program pointer is not refeched and
possibly NULL'd before the refcnt increment. This happens inside
a RCU critical section so although the pointer reference in the map
object may be NULL (by a concurrent detach operation) the reference
from READ_ONCE will not be free'd until after grace period. This
ensures the object returned by READ_ONCE() is valid through the
RCU criticl section and safe to use as long as we "know" it may
be free'd shortly.

Daniel spotted a case in the sock update API where instead of using
the READ_ONCE() program reference we used the pointer from the
original map, stab->bpf_{verdict|parse}. The problem with this is
the logic checks the object returned from the READ_ONCE() is not
NULL and then tries to reference the object again but using the
above map pointer, which may have already been NULL'd by a parallel
detach operation. If this happened bpf_porg_inc_not_zero could
dereference a NULL pointer.

Fix this by using variable returned by READ_ONCE() that is checked
for NULL.

Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
Reported-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
 kernel/bpf/sockmap.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index f03aaa8..583c1eb 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -1703,11 +1703,11 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
 		 * we increment the refcnt. If this is the case abort with an
 		 * error.
 		 */
-		verdict = bpf_prog_inc_not_zero(stab->bpf_verdict);
+		verdict = bpf_prog_inc_not_zero(verdict);
 		if (IS_ERR(verdict))
 			return PTR_ERR(verdict);
 
-		parse = bpf_prog_inc_not_zero(stab->bpf_parse);
+		parse = bpf_prog_inc_not_zero(parse);
 		if (IS_ERR(parse)) {
 			bpf_prog_put(verdict);
 			return PTR_ERR(parse);

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

* Re: [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt
  2018-05-16 21:46 [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt John Fastabend
  2018-05-16 21:46 ` [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update John Fastabend
@ 2018-05-17 16:15 ` Martin KaFai Lau
  1 sibling, 0 replies; 6+ messages in thread
From: Martin KaFai Lau @ 2018-05-17 16:15 UTC (permalink / raw)
  To: John Fastabend; +Cc: ast, daniel, netdev

On Wed, May 16, 2018 at 02:46:51PM -0700, John Fastabend wrote:
> If the user were to only attach one of the parse or verdict programs
> then it is possible a subsequent sockmap update could incorrectly
> decrement the refcnt on the program. This happens because in the
> rollback logic, after an error, we have to decrement the program
> reference count when its been incremented. However, we only increment
> the program reference count if the user has both a verdict and a
> parse program. The reason for this is because, at least at the
> moment, both are required for any one to be meaningful. The problem
> fixed here is in the rollback path we decrement the program refcnt
> even if only one existing. But we never incremented the refcnt in
> the first place creating an imbalance.
> 
> This patch fixes the error path to handle this case.
> 
> Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
> Reported-by: Daniel Borkmann <daniel@iogearbox.net>
> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>

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

* Re: [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update
  2018-05-16 21:46 ` [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update John Fastabend
@ 2018-05-17 16:16   ` Martin KaFai Lau
  2018-05-17 20:31   ` Daniel Borkmann
  1 sibling, 0 replies; 6+ messages in thread
From: Martin KaFai Lau @ 2018-05-17 16:16 UTC (permalink / raw)
  To: John Fastabend; +Cc: ast, daniel, netdev

On Wed, May 16, 2018 at 02:46:56PM -0700, John Fastabend wrote:
> In the sockmap design BPF programs (SK_SKB_STREAM_PARSER and
> SK_SKB_STREAM_VERDICT) are attached to the sockmap map type and when
> a sock is added to the map the programs are used by the socket.
> However, sockmap updates from both userspace and BPF programs can
> happen concurrently with the attach and detach of these programs.
> 
> To resolve this we use the bpf_prog_inc_not_zero and a READ_ONCE()
> primitive to ensure the program pointer is not refeched and
> possibly NULL'd before the refcnt increment. This happens inside
> a RCU critical section so although the pointer reference in the map
> object may be NULL (by a concurrent detach operation) the reference
> from READ_ONCE will not be free'd until after grace period. This
> ensures the object returned by READ_ONCE() is valid through the
> RCU criticl section and safe to use as long as we "know" it may
> be free'd shortly.
> 
> Daniel spotted a case in the sock update API where instead of using
> the READ_ONCE() program reference we used the pointer from the
> original map, stab->bpf_{verdict|parse}. The problem with this is
> the logic checks the object returned from the READ_ONCE() is not
> NULL and then tries to reference the object again but using the
> above map pointer, which may have already been NULL'd by a parallel
> detach operation. If this happened bpf_porg_inc_not_zero could
> dereference a NULL pointer.
> 
> Fix this by using variable returned by READ_ONCE() that is checked
> for NULL.
> 
> Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
> Reported-by: Daniel Borkmann <daniel@iogearbox.net>
> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Acked-by: Martin KaFai Lau <kafai@fb.com>

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

* Re: [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update
  2018-05-16 21:46 ` [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update John Fastabend
  2018-05-17 16:16   ` Martin KaFai Lau
@ 2018-05-17 20:31   ` Daniel Borkmann
  2018-05-17 21:06     ` John Fastabend
  1 sibling, 1 reply; 6+ messages in thread
From: Daniel Borkmann @ 2018-05-17 20:31 UTC (permalink / raw)
  To: John Fastabend, ast; +Cc: netdev

On 05/16/2018 11:46 PM, John Fastabend wrote:
> In the sockmap design BPF programs (SK_SKB_STREAM_PARSER and
> SK_SKB_STREAM_VERDICT) are attached to the sockmap map type and when
> a sock is added to the map the programs are used by the socket.
> However, sockmap updates from both userspace and BPF programs can
> happen concurrently with the attach and detach of these programs.
> 
> To resolve this we use the bpf_prog_inc_not_zero and a READ_ONCE()
> primitive to ensure the program pointer is not refeched and
> possibly NULL'd before the refcnt increment. This happens inside
> a RCU critical section so although the pointer reference in the map
> object may be NULL (by a concurrent detach operation) the reference
> from READ_ONCE will not be free'd until after grace period. This
> ensures the object returned by READ_ONCE() is valid through the
> RCU criticl section and safe to use as long as we "know" it may
> be free'd shortly.
> 
> Daniel spotted a case in the sock update API where instead of using
> the READ_ONCE() program reference we used the pointer from the
> original map, stab->bpf_{verdict|parse}. The problem with this is
> the logic checks the object returned from the READ_ONCE() is not
> NULL and then tries to reference the object again but using the
> above map pointer, which may have already been NULL'd by a parallel
> detach operation. If this happened bpf_porg_inc_not_zero could
> dereference a NULL pointer.
> 
> Fix this by using variable returned by READ_ONCE() that is checked
> for NULL.
> 
> Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
> Reported-by: Daniel Borkmann <daniel@iogearbox.net>
> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
> ---
>  kernel/bpf/sockmap.c |    4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
> index f03aaa8..583c1eb 100644
> --- a/kernel/bpf/sockmap.c
> +++ b/kernel/bpf/sockmap.c
> @@ -1703,11 +1703,11 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
>  		 * we increment the refcnt. If this is the case abort with an
>  		 * error.
>  		 */
> -		verdict = bpf_prog_inc_not_zero(stab->bpf_verdict);
> +		verdict = bpf_prog_inc_not_zero(verdict);
>  		if (IS_ERR(verdict))
>  			return PTR_ERR(verdict);
>  
> -		parse = bpf_prog_inc_not_zero(stab->bpf_parse);
> +		parse = bpf_prog_inc_not_zero(parse);
>  		if (IS_ERR(parse)) {
>  			bpf_prog_put(verdict);
>  			return PTR_ERR(parse);

Isn't the same sort of behavior also possible with the bpf_prog_inc_not_zero(stab->bpf_tx_msg)?
Meaning, we now have verdict and parse covered with the patch, but the original tx_msg we
fetched earlier via READ_ONCE() where same would apply not (yet)?

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

* Re: [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update
  2018-05-17 20:31   ` Daniel Borkmann
@ 2018-05-17 21:06     ` John Fastabend
  0 siblings, 0 replies; 6+ messages in thread
From: John Fastabend @ 2018-05-17 21:06 UTC (permalink / raw)
  To: Daniel Borkmann, ast; +Cc: netdev

On 05/17/2018 01:31 PM, Daniel Borkmann wrote:
> On 05/16/2018 11:46 PM, John Fastabend wrote:
>> In the sockmap design BPF programs (SK_SKB_STREAM_PARSER and
>> SK_SKB_STREAM_VERDICT) are attached to the sockmap map type and when
>> a sock is added to the map the programs are used by the socket.
>> However, sockmap updates from both userspace and BPF programs can
>> happen concurrently with the attach and detach of these programs.
>>
>> To resolve this we use the bpf_prog_inc_not_zero and a READ_ONCE()
>> primitive to ensure the program pointer is not refeched and
>> possibly NULL'd before the refcnt increment. This happens inside
>> a RCU critical section so although the pointer reference in the map
>> object may be NULL (by a concurrent detach operation) the reference
>> from READ_ONCE will not be free'd until after grace period. This
>> ensures the object returned by READ_ONCE() is valid through the
>> RCU criticl section and safe to use as long as we "know" it may
>> be free'd shortly.
>>
>> Daniel spotted a case in the sock update API where instead of using
>> the READ_ONCE() program reference we used the pointer from the
>> original map, stab->bpf_{verdict|parse}. The problem with this is
>> the logic checks the object returned from the READ_ONCE() is not
>> NULL and then tries to reference the object again but using the
>> above map pointer, which may have already been NULL'd by a parallel
>> detach operation. If this happened bpf_porg_inc_not_zero could
>> dereference a NULL pointer.
>>
>> Fix this by using variable returned by READ_ONCE() that is checked
>> for NULL.
>>
>> Fixes: 2f857d04601a ("bpf: sockmap, remove STRPARSER map_flags and add multi-map support")
>> Reported-by: Daniel Borkmann <daniel@iogearbox.net>
>> Signed-off-by: John Fastabend <john.fastabend@gmail.com>
>> ---

[...]

> Isn't the same sort of behavior also possible with the bpf_prog_inc_not_zero(stab->bpf_tx_msg)?
> Meaning, we now have verdict and parse covered with the patch, but the original tx_msg we
> fetched earlier via READ_ONCE() where same would apply not (yet)?
> 

Yes, will send a v2 and fix both cases in one shot.

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

end of thread, other threads:[~2018-05-17 21:06 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-16 21:46 [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt John Fastabend
2018-05-16 21:46 ` [bpf PATCH 2/2] bpf: parse and verdict prog attach may race with bpf map update John Fastabend
2018-05-17 16:16   ` Martin KaFai Lau
2018-05-17 20:31   ` Daniel Borkmann
2018-05-17 21:06     ` John Fastabend
2018-05-17 16:15 ` [bpf PATCH 1/2] bpf: sockmap update rollback on error can incorrectly dec prog refcnt Martin KaFai Lau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.