mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
net: lwtunnel: fix recursion loops
This patch acts as a parachute, catch all solution, by detecting recursion loops in lwtunnel users and taking care of them (e.g., a loop between routes, a loop within the same route, etc). In general, such loops are the consequence of pathological configurations. Each lwtunnel user is still free to catch such loops early and do whatever they want with them. It will be the case in a separate patch for, e.g., seg6 and seg6_local, in order to provide drop reasons and update statistics. Another example of a lwtunnel user taking care of loops is ioam6, which has valid use cases that include loops (e.g., inline mode), and which is addressed by the next patch in this series. Overall, this patch acts as a last resort to catch loops and drop packets, since we don't want to leak something unintentionally because of a pathological configuration in lwtunnels. The solution in this patch reuses dev_xmit_recursion(), dev_xmit_recursion_inc(), and dev_xmit_recursion_dec(), which seems fine considering the context. Closes: https://lore.kernel.org/netdev/2bc9e2079e864a9290561894d2a602d6@akamai.com/ Closes: https://lore.kernel.org/netdev/Z7NKYMY7fJT5cYWu@shredder/ Fixes:ffce41962e
("lwtunnel: support dst output redirect function") Fixes:2536862311
("lwt: Add support to redirect dst.input") Fixes:14972cbd34
("net: lwtunnel: Handle fragmentation") Signed-off-by: Justin Iurman <justin.iurman@uliege.be> Link: https://patch.msgid.link/20250314120048.12569-2-justin.iurman@uliege.be Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
parent
47a9b5e52a
commit
986ffb3a57
1 changed files with 53 additions and 12 deletions
|
@ -23,6 +23,8 @@
|
|||
#include <net/ip6_fib.h>
|
||||
#include <net/rtnh.h>
|
||||
|
||||
#include "dev.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
|
||||
EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_enabled);
|
||||
|
||||
|
@ -325,13 +327,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);
|
|||
|
||||
int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
|
||||
|
@ -341,8 +353,11 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->output))
|
||||
if (likely(ops && ops->output)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->output(net, sk, skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
|
@ -359,13 +374,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_output);
|
|||
|
||||
int lwtunnel_xmit(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
|
@ -376,8 +401,11 @@ int lwtunnel_xmit(struct sk_buff *skb)
|
|||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->xmit))
|
||||
if (likely(ops && ops->xmit)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->xmit(skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
|
@ -394,13 +422,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_xmit);
|
|||
|
||||
int lwtunnel_input(struct sk_buff *skb)
|
||||
{
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
const struct lwtunnel_encap_ops *ops;
|
||||
struct lwtunnel_state *lwtstate;
|
||||
int ret = -EINVAL;
|
||||
struct dst_entry *dst;
|
||||
int ret;
|
||||
|
||||
if (!dst)
|
||||
if (dev_xmit_recursion()) {
|
||||
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
|
||||
__func__);
|
||||
ret = -ENETDOWN;
|
||||
goto drop;
|
||||
}
|
||||
|
||||
dst = skb_dst(skb);
|
||||
if (!dst) {
|
||||
ret = -EINVAL;
|
||||
goto drop;
|
||||
}
|
||||
lwtstate = dst->lwtstate;
|
||||
|
||||
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
|
||||
|
@ -410,8 +448,11 @@ int lwtunnel_input(struct sk_buff *skb)
|
|||
ret = -EOPNOTSUPP;
|
||||
rcu_read_lock();
|
||||
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
|
||||
if (likely(ops && ops->input))
|
||||
if (likely(ops && ops->input)) {
|
||||
dev_xmit_recursion_inc();
|
||||
ret = ops->input(skb);
|
||||
dev_xmit_recursion_dec();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret == -EOPNOTSUPP)
|
||||
|
|
Loading…
Add table
Reference in a new issue