Commit 29b22bad authored by Yan Zhai's avatar Yan Zhai Committed by Daniel Borkmann

lwt: Fix return values of BPF xmit ops

BPF encap ops can return different types of positive values, such like
NET_RX_DROP, NET_XMIT_CN, NETDEV_TX_BUSY, and so on, from function
skb_do_redirect and bpf_lwt_xmit_reroute. At the xmit hook, such return
values would be treated implicitly as LWTUNNEL_XMIT_CONTINUE in
ip(6)_finish_output2. When this happens, skbs that have been freed would
continue to the neighbor subsystem, causing use-after-free bug and
kernel crashes.

To fix the incorrect behavior, skb_do_redirect return values can be
simply discarded, the same as tc-egress behavior. On the other hand,
bpf_lwt_xmit_reroute returns useful errors to local senders, e.g. PMTU
information. Thus convert its return values to avoid the conflict with
LWTUNNEL_XMIT_CONTINUE.

Fixes: 3a0af8fd ("bpf: BPF for lightweight tunnel infrastructure")
Reported-by: default avatarJordan Griege <jgriege@cloudflare.com>
Suggested-by: default avatarMartin KaFai Lau <martin.lau@linux.dev>
Suggested-by: default avatarStanislav Fomichev <sdf@google.com>
Signed-off-by: default avatarYan Zhai <yan@cloudflare.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/0d2b878186cfe215fec6b45769c1cd0591d3628d.1692326837.git.yan@cloudflare.com
parent 5f6395fd
...@@ -60,9 +60,8 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt, ...@@ -60,9 +60,8 @@ static int run_lwt_bpf(struct sk_buff *skb, struct bpf_lwt_prog *lwt,
ret = BPF_OK; ret = BPF_OK;
} else { } else {
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
ret = skb_do_redirect(skb); skb_do_redirect(skb);
if (ret == 0) ret = BPF_REDIRECT;
ret = BPF_REDIRECT;
} }
break; break;
...@@ -255,7 +254,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb) ...@@ -255,7 +254,7 @@ static int bpf_lwt_xmit_reroute(struct sk_buff *skb)
err = dst_output(dev_net(skb_dst(skb)->dev), skb->sk, skb); err = dst_output(dev_net(skb_dst(skb)->dev), skb->sk, skb);
if (unlikely(err)) if (unlikely(err))
return err; return net_xmit_errno(err);
/* ip[6]_finish_output2 understand LWTUNNEL_XMIT_DONE */ /* ip[6]_finish_output2 understand LWTUNNEL_XMIT_DONE */
return LWTUNNEL_XMIT_DONE; return LWTUNNEL_XMIT_DONE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment