Memory leak while using NFQUEUE to delegate the decision on TCP packets to userspace processes
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
linux (Ubuntu) |
Fix Committed
|
Undecided
|
Chengen Du | ||
Bionic |
Fix Released
|
Undecided
|
Chengen Du |
Bug Description
[Impact]
Environment: v4.15.0-177-generic Xenial ESM
Using NFQUEUE to delegate the decision on TCP packets to userspace processes will cause memory leak.
The symptom is that TCP slab objects will accumulate and eventually cause OOM.
[Fix]
There is a discrepancy between backport and upstream commit.
[Upstream Commit c3873070247d9e3
diff --git a/include/
index 9eed51e920e8.
--- a/include/
+++ b/include/
@@ -37,7 +37,7 @@ void nf_register_
void nf_unregister_
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
-void nf_queue_
+bool nf_queue_
void nf_queue_
static inline void init_hashrandom(u32 *jhash_initval)
diff --git a/net/netfilter
index 5ab0680db445.
--- a/net/netfilter
+++ b/net/netfilter
@@ -96,19 +96,21 @@ static void __nf_queue_
}
/* Bump dev refs so they don't vanish while packet is out */
-void nf_queue_
+bool nf_queue_
{
struct nf_hook_state *state = &entry->state;
+ if (state->sk && !refcount_
+ return false;
+
dev_hold(
dev_hold(
- if (state->sk)
- sock_hold(
#if IS_ENABLED(
dev_hold(
dev_hold(
#endif
+ return true;
}
EXPORT_
@@ -196,7 +198,10 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
__nf_
- nf_queue_
+ if (!nf_queue_
+ kfree(entry);
+ return -ENOTCONN;
+ }
switch (entry->state.pf) {
case AF_INET:
diff --git a/net/netfilter
index ea2d9c2a44cf.
--- a/net/netfilter
+++ b/net/netfilter
@@ -710,9 +710,15 @@ static struct nf_queue_entry *
nf_queue_
{
struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
- if (entry)
- nf_queue_
- return entry;
+
+ if (!entry)
+ return NULL;
+
+ if (nf_queue_
+ return entry;
+
+ kfree(entry);
+ return NULL;
}
#if IS_ENABLED(
[Backport Commit 4d032d60432327f
diff --git a/include/
index 814058d0f167.
--- a/include/
+++ b/include/
@@ -32,7 +32,7 @@ void nf_register_
void nf_unregister_
void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
-void nf_queue_
+bool nf_queue_
void nf_queue_
static inline void init_hashrandom(u32 *jhash_initval)
diff --git a/net/netfilter
index 59340b3ef7ef.
--- a/net/netfilter
+++ b/net/netfilter
@@ -80,10 +80,13 @@ void nf_queue_
EXPORT_
/* Bump dev refs so they don't vanish while packet is out */
-void nf_queue_
+bool nf_queue_
{
struct nf_hook_state *state = &entry->state;
+ if (state->sk && !refcount_
+ return false;
+
if (state->in)
dev_
if (state->out)
@@ -102,6 +105,7 @@ void nf_queue_
dev_
}
#endif
+ return true;
}
EXPORT_
@@ -159,7 +163,11 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
.size = sizeof(*entry) + afinfo-
};
- nf_queue_
+ if (!nf_queue_
+ kfree(entry);
+ return -ENOTCONN;
+ }
+
afinfo-
status = qh->outfn(entry, queuenum);
diff --git a/net/netfilter
index 48ed30e1b405.
--- a/net/netfilter
+++ b/net/netfilter
@@ -693,9 +693,15 @@ static struct nf_queue_entry *
nf_queue_
{
struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
- if (entry)
- nf_queue_
- return entry;
+
+ if (!entry)
+ return NULL;
+
+ if (nf_queue_
+ return entry;
+
+ kfree(entry);
+ return NULL;
}
#if IS_ENABLED(
[Difference between Commits]
50,57c57,62
< dev_hold(
< dev_hold(
< - if (state->sk)
< - sock_hold(
<
< #if IS_ENABLED(
< dev_hold(
< dev_hold(
---
> if (state->in)
> dev_hold(
> if (state->out)
> @@ -102,6 +105,7 @@ void nf_queue_
> dev_hold(physdev);
> }
The sock_hold() logic still remains in the backport commit, which will affect the reference count and result in memory leak.
The fix aligns the logic with the upstream commit.
[Test Plan]
1. Prepare a VM and run a TCP server on host.
2. Enter into the VM and set up a iptables rule.
iptables -I OUTPUT -p tcp --dst <-TCP_SERVER_IP-> -j NFQUEUE --queue-num=1 --queue-bypass
3. Run a nfnetlink client (should listen on NF queue 1) on VM.
4. Keep connecting the TCP server from VM.
while true; do netcat <-TCP_SERVER_IP-> 8080; done
5. The VM's TCP slab objects will accumulate and eventually encounter OOM situation.
cat /proc/slabinfo | grep TCP
[Where problems could occur]
The fix just aligns the logic with the upstream commit, so the regression can be considered as low.
CVE References
description: | updated |
Changed in linux (Ubuntu Bionic): | |
assignee: | nobody → ChengEn, Du (chengendu) |
Changed in linux (Ubuntu): | |
assignee: | nobody → ChengEn, Du (chengendu) |
status: | Incomplete → In Progress |
Changed in linux (Ubuntu Bionic): | |
status: | New → In Progress |
tags: | added: bionic sts |
Changed in linux (Ubuntu Bionic): | |
status: | In Progress → Fix Committed |
Changed in linux (Ubuntu): | |
status: | In Progress → Fix Committed |
This bug is missing log files that will aid in diagnosing the problem. While running an Ubuntu kernel (not a mainline or third-party kernel) please enter the following command in a terminal window:
apport-collect 1991774
and then change the status of the bug to 'Confirmed'.
If, due to the nature of the issue you have encountered, you are unable to run this command, please add a comment stating that fact and change the bug status to 'Confirmed'.
This change has been made by an automated script, maintained by the Ubuntu Kernel Team.