Skip to content

Commit 986ffb3

Browse files
IurmanJPaolo Abeni
authored andcommitted
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: ffce419 ("lwtunnel: support dst output redirect function") Fixes: 2536862 ("lwt: Add support to redirect dst.input") Fixes: 14972cb ("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>
1 parent 47a9b5e commit 986ffb3

File tree

1 file changed

+53
-12
lines changed

1 file changed

+53
-12
lines changed

net/core/lwtunnel.c

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include <net/ip6_fib.h>
2424
#include <net/rtnh.h>
2525

26+
#include "dev.h"
27+
2628
DEFINE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
2729
EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_enabled);
2830

@@ -325,13 +327,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);
325327

326328
int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
327329
{
328-
struct dst_entry *dst = skb_dst(skb);
329330
const struct lwtunnel_encap_ops *ops;
330331
struct lwtunnel_state *lwtstate;
331-
int ret = -EINVAL;
332+
struct dst_entry *dst;
333+
int ret;
334+
335+
if (dev_xmit_recursion()) {
336+
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
337+
__func__);
338+
ret = -ENETDOWN;
339+
goto drop;
340+
}
332341

333-
if (!dst)
342+
dst = skb_dst(skb);
343+
if (!dst) {
344+
ret = -EINVAL;
334345
goto drop;
346+
}
335347
lwtstate = dst->lwtstate;
336348

337349
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
@@ -341,8 +353,11 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
341353
ret = -EOPNOTSUPP;
342354
rcu_read_lock();
343355
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
344-
if (likely(ops && ops->output))
356+
if (likely(ops && ops->output)) {
357+
dev_xmit_recursion_inc();
345358
ret = ops->output(net, sk, skb);
359+
dev_xmit_recursion_dec();
360+
}
346361
rcu_read_unlock();
347362

348363
if (ret == -EOPNOTSUPP)
@@ -359,13 +374,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_output);
359374

360375
int lwtunnel_xmit(struct sk_buff *skb)
361376
{
362-
struct dst_entry *dst = skb_dst(skb);
363377
const struct lwtunnel_encap_ops *ops;
364378
struct lwtunnel_state *lwtstate;
365-
int ret = -EINVAL;
379+
struct dst_entry *dst;
380+
int ret;
381+
382+
if (dev_xmit_recursion()) {
383+
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
384+
__func__);
385+
ret = -ENETDOWN;
386+
goto drop;
387+
}
366388

367-
if (!dst)
389+
dst = skb_dst(skb);
390+
if (!dst) {
391+
ret = -EINVAL;
368392
goto drop;
393+
}
369394

370395
lwtstate = dst->lwtstate;
371396

@@ -376,8 +401,11 @@ int lwtunnel_xmit(struct sk_buff *skb)
376401
ret = -EOPNOTSUPP;
377402
rcu_read_lock();
378403
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
379-
if (likely(ops && ops->xmit))
404+
if (likely(ops && ops->xmit)) {
405+
dev_xmit_recursion_inc();
380406
ret = ops->xmit(skb);
407+
dev_xmit_recursion_dec();
408+
}
381409
rcu_read_unlock();
382410

383411
if (ret == -EOPNOTSUPP)
@@ -394,13 +422,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_xmit);
394422

395423
int lwtunnel_input(struct sk_buff *skb)
396424
{
397-
struct dst_entry *dst = skb_dst(skb);
398425
const struct lwtunnel_encap_ops *ops;
399426
struct lwtunnel_state *lwtstate;
400-
int ret = -EINVAL;
427+
struct dst_entry *dst;
428+
int ret;
401429

402-
if (!dst)
430+
if (dev_xmit_recursion()) {
431+
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
432+
__func__);
433+
ret = -ENETDOWN;
403434
goto drop;
435+
}
436+
437+
dst = skb_dst(skb);
438+
if (!dst) {
439+
ret = -EINVAL;
440+
goto drop;
441+
}
404442
lwtstate = dst->lwtstate;
405443

406444
if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
@@ -410,8 +448,11 @@ int lwtunnel_input(struct sk_buff *skb)
410448
ret = -EOPNOTSUPP;
411449
rcu_read_lock();
412450
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
413-
if (likely(ops && ops->input))
451+
if (likely(ops && ops->input)) {
452+
dev_xmit_recursion_inc();
414453
ret = ops->input(skb);
454+
dev_xmit_recursion_dec();
455+
}
415456
rcu_read_unlock();
416457

417458
if (ret == -EOPNOTSUPP)

0 commit comments

Comments
 (0)