Use AlmaLinux OS secure boot cert
Enable Btrfs support for all kernel variants
af_unix: set gc_in_progress to true in unix_gc() {CVE-2026-53361}
hpsa: bring back deprecated PCI ids #CFHack #CFHack2024
mptsas: bring back deprecated PCI ids #CFHack #CFHack2024
megaraid_sas: bring back deprecated PCI ids #CFHack #CFHack2024
qla2xxx: bring back deprecated PCI ids #CFHack #CFHack2024
qla4xxx: bring back deprecated PCI ids
be2iscsi: bring back deprecated PCI ids
kernel/rh_messages.h: enable all disabled pci devices by moving to unmaintained
gve: update QPL page registration logic to honor max_registered_pages (backport from upstream)
gve: enable reading max ring size from the device in DQO-QPL mode (backport from upstream)
186 lines
5.3 KiB
Diff
186 lines
5.3 KiB
Diff
From 2354e975932dabb06fad239f07a3b68fd1809737 Mon Sep 17 00:00:00 2001
|
|
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
Date: Wed, 10 Jun 2026 00:03:19 +0200
|
|
Subject: [PATCH] netfilter: nf_dup_netdev: add nf_dev_xmit_recursion*()
|
|
helpers and use them
|
|
|
|
Update nft_dup and nft_fwd to use the nf_dev_xmit_recursion() helpers.
|
|
This patch also disables BH when transmitting the skb to address a
|
|
possible migration to different CPU leading to imbalanced decrementation
|
|
of the recursion counters.
|
|
|
|
This is modeled after Florian Westphal's dev_xmit_recursion*() API
|
|
available since commit 97cdcf37b57e ("net: place xmit recursion in
|
|
softnet data") according to its current state in the tree.
|
|
|
|
Fixes: 1d47b55b36d2 ("netfilter: nft_fwd_netdev: use recursion counter in neigh egress path")
|
|
Fixes: f37ad9127039 ("netfilter: nf_dup_netdev: Move the recursion counter struct netdev_xmit")
|
|
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
|
|
|
diff --git a/include/net/netfilter/nf_dup_netdev.h b/include/net/netfilter/nf_dup_netdev.h
|
|
index 609bcf4..b175d27 100644
|
|
--- a/include/net/netfilter/nf_dup_netdev.h
|
|
+++ b/include/net/netfilter/nf_dup_netdev.h
|
|
@@ -3,23 +3,10 @@
|
|
#define _NF_DUP_NETDEV_H_
|
|
|
|
#include <net/netfilter/nf_tables.h>
|
|
-#include <linux/netdevice.h>
|
|
-#include <linux/sched.h>
|
|
|
|
void nf_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
|
void nf_fwd_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
|
|
|
-#define NF_RECURSION_LIMIT 2
|
|
-
|
|
-static inline u8 *nf_get_nf_dup_skb_recursion(void)
|
|
-{
|
|
-#ifndef CONFIG_PREEMPT_RT
|
|
- return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion);
|
|
-#else
|
|
- return ¤t->net_xmit.nf_dup_skb_recursion;
|
|
-#endif
|
|
-}
|
|
-
|
|
struct nft_offload_ctx;
|
|
struct nft_flow_rule;
|
|
|
|
diff --git a/net/netfilter/nf_dup_netdev.c b/net/netfilter/nf_dup_netdev.c
|
|
index 516bcf4..ab39733 100644
|
|
--- a/net/netfilter/nf_dup_netdev.c
|
|
+++ b/net/netfilter/nf_dup_netdev.c
|
|
@@ -17,28 +17,24 @@
|
|
|
|
static DEFINE_PER_CPU(u8, nf_dup_skb_recursion);
|
|
|
|
-#define NF_RECURSION_LIMIT 2
|
|
-
|
|
-#ifndef CONFIG_PREEMPT_RT
|
|
-static u8 *nf_get_nf_dup_skb_recursion(void)
|
|
+static bool nf_dev_xmit_recursion(void)
|
|
{
|
|
- return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion);
|
|
+ return unlikely(__this_cpu_read(nf_dup_skb_recursion) > NF_RECURSION_LIMIT);
|
|
}
|
|
-#else
|
|
|
|
-static u8 *nf_get_nf_dup_skb_recursion(void)
|
|
+static void nf_dev_xmit_recursion_inc(void)
|
|
{
|
|
- return ¤t->net_xmit.nf_dup_skb_recursion;
|
|
+ __this_cpu_inc(nf_dup_skb_recursion);
|
|
}
|
|
|
|
-#endif
|
|
+static void nf_dev_xmit_recursion_dec(void)
|
|
+{
|
|
+ __this_cpu_dec(nf_dup_skb_recursion);
|
|
+}
|
|
|
|
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
|
enum nf_dev_hooks hook)
|
|
{
|
|
- if (__this_cpu_read(nf_dup_skb_recursion) > NF_RECURSION_LIMIT)
|
|
- goto err;
|
|
-
|
|
if (hook == NF_NETDEV_INGRESS && skb_mac_header_was_set(skb)) {
|
|
if (skb_cow_head(skb, skb->mac_len))
|
|
goto err;
|
|
@@ -48,9 +44,15 @@ static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
|
|
|
skb->dev = dev;
|
|
skb_clear_tstamp(skb);
|
|
- __this_cpu_inc(nf_dup_skb_recursion);
|
|
+ local_bh_disable();
|
|
+ if (nf_dev_xmit_recursion()) {
|
|
+ local_bh_enable();
|
|
+ goto err;
|
|
+ }
|
|
+ nf_dev_xmit_recursion_inc();
|
|
dev_queue_xmit(skb);
|
|
- __this_cpu_dec(nf_dup_skb_recursion);
|
|
+ nf_dev_xmit_recursion_dec();
|
|
+ local_bh_enable();
|
|
return;
|
|
err:
|
|
kfree_skb(skb);
|
|
diff --git a/net/netfilter/nft_fwd_netdev.c b/net/netfilter/nft_fwd_netdev.c
|
|
index a9743a1..8b0de2d 100644
|
|
--- a/net/netfilter/nft_fwd_netdev.c
|
|
+++ b/net/netfilter/nft_fwd_netdev.c
|
|
@@ -21,6 +21,25 @@ struct nft_fwd_netdev {
|
|
u8 sreg_dev;
|
|
};
|
|
|
|
+
|
|
+#define NF_RECURSION_LIMIT 2
|
|
+static DEFINE_PER_CPU(u8, nf_dup_skb_recursion);
|
|
+
|
|
+static bool nf_dev_xmit_recursion(void)
|
|
+{
|
|
+ return unlikely(__this_cpu_read(nf_dup_skb_recursion) > NF_RECURSION_LIMIT);
|
|
+}
|
|
+
|
|
+static void nf_dev_xmit_recursion_inc(void)
|
|
+{
|
|
+ __this_cpu_inc(nf_dup_skb_recursion);
|
|
+}
|
|
+
|
|
+static void nf_dev_xmit_recursion_dec(void)
|
|
+{
|
|
+ __this_cpu_dec(nf_dup_skb_recursion);
|
|
+}
|
|
+
|
|
static void nft_fwd_netdev_eval(const struct nft_expr *expr,
|
|
struct nft_regs *regs,
|
|
const struct nft_pktinfo *pkt)
|
|
@@ -95,7 +114,6 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|
struct nft_regs *regs,
|
|
const struct nft_pktinfo *pkt)
|
|
{
|
|
- u8 *nf_dup_skb_recursion = nf_get_nf_dup_skb_recursion();
|
|
struct nft_fwd_neigh *priv = nft_expr_priv(expr);
|
|
void *addr = ®s->data[priv->sreg_addr];
|
|
int oif = regs->data[priv->sreg_dev];
|
|
@@ -144,13 +162,15 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|
goto out;
|
|
}
|
|
|
|
- if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT) {
|
|
+ dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
|
+ if (!dev) {
|
|
verdict = NF_DROP;
|
|
goto out;
|
|
}
|
|
|
|
- dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
|
- if (dev == NULL) {
|
|
+ local_bh_disable();
|
|
+ if (nf_dev_xmit_recursion()) {
|
|
+ local_bh_enable();
|
|
verdict = NF_DROP;
|
|
goto out;
|
|
}
|
|
@@ -159,16 +179,18 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
|
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
|
|
skb = skb_expand_head(skb, hh_len);
|
|
if (!skb) {
|
|
- verdict = NF_STOLEN;
|
|
+ local_bh_enable();
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
skb->dev = dev;
|
|
skb_clear_tstamp(skb);
|
|
- (*nf_dup_skb_recursion)++;
|
|
+
|
|
+ nf_dev_xmit_recursion_inc();
|
|
neigh_xmit(neigh_table, dev, addr, skb);
|
|
- (*nf_dup_skb_recursion)--;
|
|
+ nf_dev_xmit_recursion_dec();
|
|
+ local_bh_enable();
|
|
out:
|
|
regs->verdict.code = verdict;
|
|
}
|