Signed-off-by: Thomas Graf <[email protected]>
---
net/core/lwtunnel.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c
index 554d901..6363d0b 100644
--- a/net/core/lwtunnel.c
+++ b/net/core/lwtunnel.c
@@ -231,6 +231,10 @@ int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct
lwtunnel_state *b)
}
EXPORT_SYMBOL(lwtunnel_cmp_encap);
+/* Per CPU recursion counter for dst_output() redirections via LWT */
+#define DST_RECURSION_LIMIT 5
+DEFINE_PER_CPU(int, dst_recursion);
+
int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
@@ -246,11 +250,19 @@ int lwtunnel_output(struct net *net, struct sock *sk,
struct sk_buff *skb)
lwtstate->type > LWTUNNEL_ENCAP_MAX)
return 0;
+ if (unlikely(__this_cpu_read(dst_recursion) > DST_RECURSION_LIMIT)) {
+ net_crit_ratelimited("lwt: recursion limit reached of
redirected dst_output calls\n");
+ return -EFAULT;
+ }
+
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
- if (likely(ops && ops->output))
+ if (likely(ops && ops->output)) {
+ __this_cpu_inc(dst_recursion);
ret = ops->output(net, sk, skb);
+ __this_cpu_dec(dst_recursion);
+ }
rcu_read_unlock();
if (ret == -EOPNOTSUPP)
--
2.7.4