Fix the lwtunnel_input() reentry loop and the lwtunnel_xmit() loop when the destination is the same after transformation. For xmit, we refuse BPF_LWT_REROUTE when dst_entry remains unchanged, since it's considered a buggy configuration and there is no other easy way to prevent the issue. Fixes: 3bd0b15281af ("bpf: add handling of BPF_LWT_REROUTE to lwt_bpf.c") Cc: bpf@xxxxxxxxxxxxxxx Cc: Guillaume Nault <gnault@xxxxxxxxxx> Cc: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> Cc: Menglong Dong <menglong8.dong@xxxxxxxxx> Cc: Peter Oskolkov <posk@xxxxxxxxxx> Cc: Ido Schimmel <idosch@xxxxxxxxxx> Signed-off-by: Justin Iurman <justin.iurman@xxxxxxxxx> --- net/core/lwt_bpf.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/net/core/lwt_bpf.c b/net/core/lwt_bpf.c index ae74634310a3..5ed849a0b23d 100644 --- a/net/core/lwt_bpf.c +++ b/net/core/lwt_bpf.c @@ -88,6 +88,7 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt, static int bpf_lwt_input_reroute(struct sk_buff *skb) { + struct lwtunnel_state *lwtst = skb_dst(skb)->lwtstate; enum skb_drop_reason reason; int err = -EINVAL; @@ -110,6 +111,13 @@ static int bpf_lwt_input_reroute(struct sk_buff *skb) if (err) goto err; + + /* avoid lwtunnel_input() reentry loop when destination is the same + * after transformation + */ + if (lwtst == skb_dst(skb)->lwtstate) + return lwtst->orig_input(skb); + return dst_input(skb); err: @@ -180,6 +188,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) struct net_device *l3mdev = l3mdev_master_dev_rcu(skb_dst(skb)->dev); int oif = l3mdev ? l3mdev->ifindex : 0; struct dst_entry *dst = NULL; + struct dst_entry *orig_dst; int err = -EAFNOSUPPORT; struct sock *sk; struct net *net; @@ -201,6 +210,8 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) net = dev_net(skb_dst(skb)->dev); } + orig_dst = skb_dst(skb); + if (ipv4) { struct iphdr *iph = ip_hdr(skb); struct flowi4 fl4 = {}; @@ -254,6 +265,16 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) if (unlikely(err)) goto err; + /* avoid lwtunnel_xmit() reentry loop when destination is the same + * after transformation (i.e., disallow BPF_LWT_REROUTE when dst_entry + * remains the same). + */ + if (orig_dst->lwtstate == dst->lwtstate) { + dst_release(dst); + err = -EINVAL; + goto err; + } + skb_dst_drop(skb); skb_dst_set(skb, dst); -- 2.34.1