All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 nf 0/2] netfilter: nf_queue: be more careful with sk refcounts
@ 2022-03-01  0:21 Florian Westphal
  2022-03-01  0:21 ` [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free Florian Westphal
  2022-03-01  0:21 ` [PATCH v2 nf 2/2] netfilter: nf_queue: handle socket prefetch Florian Westphal
  0 siblings, 2 replies; 4+ messages in thread
From: Florian Westphal @ 2022-03-01  0:21 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal

This is a resend of v1 patch, split into two distinct patches
to ease backport work.

Florian Westphal (2):
  netfilter: nf_queue: fix possible use-after-free
  netfilter: nf_queue: handle socket prefetch

 include/net/netfilter/nf_queue.h |  2 +-
 net/netfilter/nf_queue.c         | 25 +++++++++++++++++++++----
 net/netfilter/nfnetlink_queue.c  | 12 +++++++++---
 3 files changed, 31 insertions(+), 8 deletions(-)

-- 
2.34.1


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

* [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free
  2022-03-01  0:21 [PATCH v2 nf 0/2] netfilter: nf_queue: be more careful with sk refcounts Florian Westphal
@ 2022-03-01  0:21 ` Florian Westphal
  2022-03-01  1:34   ` Eric Dumazet
  2022-03-01  0:21 ` [PATCH v2 nf 2/2] netfilter: nf_queue: handle socket prefetch Florian Westphal
  1 sibling, 1 reply; 4+ messages in thread
From: Florian Westphal @ 2022-03-01  0:21 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal, Eric Dumazet

Eric Dumazet says:
  The sock_hold() side seems suspect, because there is no guarantee
  that sk_refcnt is not already 0.

On failure, we cannot queue the packet and need to indicate an
error.  The packet will be dropped by the caller.

v2: split skb prefetch hunk into separate change

Fixes: 271b72c7fa82c ("udp: RCU handling for Unicast packets.")
Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 include/net/netfilter/nf_queue.h |  2 +-
 net/netfilter/nf_queue.c         | 13 +++++++++----
 net/netfilter/nfnetlink_queue.c  | 12 +++++++++---
 3 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index 9eed51e920e8..980daa6e1e3a 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -37,7 +37,7 @@ void nf_register_queue_handler(const struct nf_queue_handler *qh);
 void nf_unregister_queue_handler(void);
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
 
-void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry);
 void nf_queue_entry_free(struct nf_queue_entry *entry);
 
 static inline void init_hashrandom(u32 *jhash_initval)
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 5ab0680db445..e39549c55945 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -96,19 +96,21 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
 }
 
 /* Bump dev refs so they don't vanish while packet is out */
-void nf_queue_entry_get_refs(struct nf_queue_entry *entry)
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
 {
 	struct nf_hook_state *state = &entry->state;
 
+	if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
+		return false;
+
 	dev_hold(state->in);
 	dev_hold(state->out);
-	if (state->sk)
-		sock_hold(state->sk);
 
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
 	dev_hold(entry->physin);
 	dev_hold(entry->physout);
 #endif
+	return true;
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
 
@@ -196,7 +198,10 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
 
 	__nf_queue_entry_init_physdevs(entry);
 
-	nf_queue_entry_get_refs(entry);
+	if (!nf_queue_entry_get_refs(entry)) {
+		kfree(entry);
+		return -ENOTCONN;
+	}
 
 	switch (entry->state.pf) {
 	case AF_INET:
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index ea2d9c2a44cf..64a6acb6aeae 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -710,9 +710,15 @@ static struct nf_queue_entry *
 nf_queue_entry_dup(struct nf_queue_entry *e)
 {
 	struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
-	if (entry)
-		nf_queue_entry_get_refs(entry);
-	return entry;
+
+	if (!entry)
+		return NULL;
+
+	if (nf_queue_entry_get_refs(entry))
+		return entry;
+
+	kfree(entry);
+	return NULL;
 }
 
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
-- 
2.34.1


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

* [PATCH v2 nf 2/2] netfilter: nf_queue: handle socket prefetch
  2022-03-01  0:21 [PATCH v2 nf 0/2] netfilter: nf_queue: be more careful with sk refcounts Florian Westphal
  2022-03-01  0:21 ` [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free Florian Westphal
@ 2022-03-01  0:21 ` Florian Westphal
  1 sibling, 0 replies; 4+ messages in thread
From: Florian Westphal @ 2022-03-01  0:21 UTC (permalink / raw)
  To: netfilter-devel; +Cc: Florian Westphal, Joe Stringer

In case someone combines bpf socket assign and nf_queue, then we will
queue an skb who references a struct sock that did not have its
reference count incremented.

As we leave rcu protection, there is no guarantee that skb->sk is still
valid.

For refcount-less skb->sk case, try to increment the reference count
and then override the destructor.

In case of failure we have two choices: orphan the skb and 'delete'
preselect or let nf_queue() drop the packet.

Do the latter, it should not happen during normal operation.

Fixes: cf7fbe660f2d ("bpf: Add socket assign support")
Acked-by: Joe Stringer <joe@cilium.io>
Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/netfilter/nf_queue.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index e39549c55945..63d1516816b1 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -180,6 +180,18 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
 		break;
 	}
 
+	if (skb_sk_is_prefetched(skb)) {
+		struct sock *sk = skb->sk;
+
+		if (!sk_is_refcounted(sk)) {
+			if (!refcount_inc_not_zero(&sk->sk_refcnt))
+				return -ENOTCONN;
+
+			/* drop refcount on skb_orphan */
+			skb->destructor = sock_edemux;
+		}
+	}
+
 	entry = kmalloc(sizeof(*entry) + route_key_size, GFP_ATOMIC);
 	if (!entry)
 		return -ENOMEM;
-- 
2.34.1


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

* Re: [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free
  2022-03-01  0:21 ` [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free Florian Westphal
@ 2022-03-01  1:34   ` Eric Dumazet
  0 siblings, 0 replies; 4+ messages in thread
From: Eric Dumazet @ 2022-03-01  1:34 UTC (permalink / raw)
  To: Florian Westphal, netfilter-devel


On 2/28/22 16:21, Florian Westphal wrote:
> Eric Dumazet says:
>    The sock_hold() side seems suspect, because there is no guarantee
>    that sk_refcnt is not already 0.
>
> On failure, we cannot queue the packet and need to indicate an
> error.  The packet will be dropped by the caller.
>
> v2: split skb prefetch hunk into separate change
>
> Fixes: 271b72c7fa82c ("udp: RCU handling for Unicast packets.")
> Reported-by: Eric Dumazet <eric.dumazet@gmail.com>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---


SGTM, thanks !

Reviewed-by: Eric Dumazet <edumazet@google.com>



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

end of thread, other threads:[~2022-03-01  1:34 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-01  0:21 [PATCH v2 nf 0/2] netfilter: nf_queue: be more careful with sk refcounts Florian Westphal
2022-03-01  0:21 ` [PATCH v2 nf 1/2] netfilter: nf_queue: fix possible use-after-free Florian Westphal
2022-03-01  1:34   ` Eric Dumazet
2022-03-01  0:21 ` [PATCH v2 nf 2/2] netfilter: nf_queue: handle socket prefetch Florian Westphal

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.