summaryrefslogtreecommitdiff
path: root/net/netfilter/nfnetlink.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2018-06-11 13:20:35 +0200
committerPablo Neira Ayuso <pablo@netfilter.org>2018-06-12 19:28:18 +0200
commit71ad00c50d77e507138c792a9646b53c16f22e11 (patch)
treec1e02e45c573ae8003390fc95923e48cc70440b0 /net/netfilter/nfnetlink.c
parent215a31f19dedd4e92a67cf5a9717ee898d012b3a (diff)
netfilter: nf_tables: fix module unload race
We must first remove the nfnetlink protocol handler when nf_tables module is unloaded -- we don't want userspace to submit new change requests once we've started to tear down nft state. Furthermore, nfnetlink must not call any subsystem function after call_batch returned -EAGAIN. EAGAIN means the subsys mutex was dropped, so its unlikely but possible that nf_tables subsystem was removed due to 'rmmod nf_tables' on another cpu. Therefore, we must abort batch completely and not move on to next part of the batch. Last, we can't invoke ->abort unless we've checked that the subsystem is still registered. Change netns exit path of nf_tables to make sure any incompleted transaction gets removed on exit. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter/nfnetlink.c')
-rw-r--r--net/netfilter/nfnetlink.c10
1 files changed, 7 insertions, 3 deletions
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 4d0da7042aff..e1b6be29848d 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -429,7 +429,7 @@ replay:
*/
if (err == -EAGAIN) {
status |= NFNL_BATCH_REPLAY;
- goto next;
+ goto done;
}
}
ack:
@@ -456,7 +456,7 @@ ack:
if (err)
status |= NFNL_BATCH_FAILURE;
}
-next:
+
msglen = NLMSG_ALIGN(nlh->nlmsg_len);
if (msglen > skb->len)
msglen = skb->len;
@@ -464,7 +464,11 @@ next:
}
done:
if (status & NFNL_BATCH_REPLAY) {
- ss->abort(net, oskb);
+ const struct nfnetlink_subsystem *ss2;
+
+ ss2 = nfnl_dereference_protected(subsys_id);
+ if (ss2 == ss)
+ ss->abort(net, oskb);
nfnl_err_reset(&err_list);
nfnl_unlock(subsys_id);
kfree_skb(skb);