Signed-off-by: Thomas Graf <tg...@suug.ch>
---
 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

Reply via email to