mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
netfilter: nft_fwd_netdev: use recursion counter in neigh egress path
nft_fwd_neigh can be used in egress chains (NF_NETDEV_EGRESS). When the
forwarding rule targets the same device or two devices forward to each
other, neigh_xmit() triggers dev_queue_xmit() which re-enters
nf_hook_egress(), causing infinite recursion and stack overflow.
Move the nf_get_nf_dup_skb_recursion() accessor and NF_RECURSION_LIMIT
to the shared header nf_dup_netdev.h as a static inline, so that
nft_fwd_netdev can use the recursion counter directly without exported
function call overhead. Guard neigh_xmit() with the same recursion
limit already used in nf_do_netdev_egress().
[ Updated to cache the nf_get_nf_dup_skb_recursion pointer. --pablo ]
Fixes: f87b9464d1 ("netfilter: nft_fwd_netdev: Support egress hook")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Weiming Shi <bestswngs@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
0a0b35f0bf
commit
1d47b55b36
|
|
@ -3,10 +3,23 @@
|
||||||
#define _NF_DUP_NETDEV_H_
|
#define _NF_DUP_NETDEV_H_
|
||||||
|
|
||||||
#include <net/netfilter/nf_tables.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_dup_netdev_egress(const struct nft_pktinfo *pkt, int oif);
|
||||||
void nf_fwd_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_offload_ctx;
|
||||||
struct nft_flow_rule;
|
struct nft_flow_rule;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,6 @@
|
||||||
#include <net/netfilter/nf_tables_offload.h>
|
#include <net/netfilter/nf_tables_offload.h>
|
||||||
#include <net/netfilter/nf_dup_netdev.h>
|
#include <net/netfilter/nf_dup_netdev.h>
|
||||||
|
|
||||||
#define NF_RECURSION_LIMIT 2
|
|
||||||
|
|
||||||
#ifndef CONFIG_PREEMPT_RT
|
|
||||||
static u8 *nf_get_nf_dup_skb_recursion(void)
|
|
||||||
{
|
|
||||||
return this_cpu_ptr(&softnet_data.xmit.nf_dup_skb_recursion);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
static u8 *nf_get_nf_dup_skb_recursion(void)
|
|
||||||
{
|
|
||||||
return ¤t->net_xmit.nf_dup_skb_recursion;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
static void nf_do_netdev_egress(struct sk_buff *skb, struct net_device *dev,
|
||||||
enum nf_dev_hooks hook)
|
enum nf_dev_hooks hook)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,7 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
||||||
struct nft_regs *regs,
|
struct nft_regs *regs,
|
||||||
const struct nft_pktinfo *pkt)
|
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);
|
struct nft_fwd_neigh *priv = nft_expr_priv(expr);
|
||||||
void *addr = ®s->data[priv->sreg_addr];
|
void *addr = ®s->data[priv->sreg_addr];
|
||||||
int oif = regs->data[priv->sreg_dev];
|
int oif = regs->data[priv->sreg_dev];
|
||||||
|
|
@ -153,6 +154,11 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (*nf_dup_skb_recursion > NF_RECURSION_LIMIT) {
|
||||||
|
verdict = NF_DROP;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
dev = dev_get_by_index_rcu(nft_net(pkt), oif);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
verdict = NF_DROP;
|
verdict = NF_DROP;
|
||||||
|
|
@ -170,7 +176,9 @@ static void nft_fwd_neigh_eval(const struct nft_expr *expr,
|
||||||
|
|
||||||
skb->dev = dev;
|
skb->dev = dev;
|
||||||
skb_clear_tstamp(skb);
|
skb_clear_tstamp(skb);
|
||||||
|
(*nf_dup_skb_recursion)++;
|
||||||
neigh_xmit(neigh_table, dev, addr, skb);
|
neigh_xmit(neigh_table, dev, addr, skb);
|
||||||
|
(*nf_dup_skb_recursion)--;
|
||||||
out:
|
out:
|
||||||
regs->verdict.code = verdict;
|
regs->verdict.code = verdict;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user