mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
bpf: Reject redirect helpers without a bpf_net_context
The bpf_redirect*() helpers and skb_do_redirect() obtain the per-task
bpf_redirect_info via bpf_net_ctx_get_ri(), which dereferences the
current->bpf_net_context unconditionally. That context is established
on the paths that run tc BPF such as sch_handle_{ingress,egress}(),
*except* for the case where {cls,act}_bpf was attached to a proper
qdisc. A program running from there reaches the NULL deref in two ways:
* It calls bpf_redirect() directly, which dereferences the context at
the top of the helper:
tc qdisc add dev eth0 root handle 1: red limit 1MB min 10KB max 20KB \
avpkt 1000 burst 100 qevent early_drop block 10
tc filter add block 10 pref 1 bpf obj redirect.o
* It simply returns TC_ACT_REDIRECT without helper call: tcf_qevent_handle()
then dispatches to skb_do_redirect(), which dereferences the context
Rather than extending bpf_net_context management into the qdisc path,
make the redirect helpers refuse to operate when no context exists, and
have tcf_qevent_handle() drop a TC_ACT_REDIRECT verdict instead of
calling skb_do_redirect(). Previous behaviour was a crash, so nothing
regresses by not supporting it.
Fixes: 401cb7dae8 ("net: Reference bpf_redirect_info via task_struct on PREEMPT_RT.")
Fixes: 3625750f05 ("net: sched: Introduce helpers for qevent blocks")
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/20260706185609.330006-2-daniel@iogearbox.net
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
50aff80475
commit
3f4920d165
|
|
@ -2552,11 +2552,13 @@ int skb_do_redirect(struct sk_buff *skb)
|
|||
|
||||
BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
struct bpf_redirect_info *ri;
|
||||
|
||||
if (unlikely(flags & (~(BPF_F_INGRESS) | BPF_F_REDIRECT_INTERNAL)))
|
||||
if (unlikely(!bpf_net_ctx_get() ||
|
||||
(flags & (~(BPF_F_INGRESS) | BPF_F_REDIRECT_INTERNAL))))
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
ri = bpf_net_ctx_get_ri();
|
||||
ri->flags = flags;
|
||||
ri->tgt_index = ifindex;
|
||||
|
||||
|
|
@ -2573,11 +2575,12 @@ static const struct bpf_func_proto bpf_redirect_proto = {
|
|||
|
||||
BPF_CALL_2(bpf_redirect_peer, u32, ifindex, u64, flags)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
struct bpf_redirect_info *ri;
|
||||
|
||||
if (unlikely(flags))
|
||||
if (unlikely(!bpf_net_ctx_get() || flags))
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
ri = bpf_net_ctx_get_ri();
|
||||
ri->flags = BPF_F_PEER;
|
||||
ri->tgt_index = ifindex;
|
||||
|
||||
|
|
@ -2595,11 +2598,13 @@ static const struct bpf_func_proto bpf_redirect_peer_proto = {
|
|||
BPF_CALL_4(bpf_redirect_neigh, u32, ifindex, struct bpf_redir_neigh *, params,
|
||||
int, plen, u64, flags)
|
||||
{
|
||||
struct bpf_redirect_info *ri = bpf_net_ctx_get_ri();
|
||||
struct bpf_redirect_info *ri;
|
||||
|
||||
if (unlikely((plen && plen < sizeof(*params)) || flags))
|
||||
if (unlikely((plen && plen < sizeof(*params)) ||
|
||||
!bpf_net_ctx_get() || flags))
|
||||
return TC_ACT_SHOT;
|
||||
|
||||
ri = bpf_net_ctx_get_ri();
|
||||
ri->flags = BPF_F_NEIGH | (plen ? BPF_F_NEXTHOP : 0);
|
||||
ri->tgt_index = ifindex;
|
||||
|
||||
|
|
|
|||
|
|
@ -4046,6 +4046,8 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru
|
|||
fl = rcu_dereference_bh(qe->filter_chain);
|
||||
|
||||
switch (tcf_classify(skb, NULL, fl, &cl_res, false)) {
|
||||
case TC_ACT_REDIRECT:
|
||||
fallthrough;
|
||||
case TC_ACT_SHOT:
|
||||
qdisc_qstats_drop(sch);
|
||||
__qdisc_drop(skb, to_free);
|
||||
|
|
@ -4057,10 +4059,6 @@ struct sk_buff *tcf_qevent_handle(struct tcf_qevent *qe, struct Qdisc *sch, stru
|
|||
__qdisc_drop(skb, to_free);
|
||||
*ret = __NET_XMIT_STOLEN;
|
||||
return NULL;
|
||||
case TC_ACT_REDIRECT:
|
||||
skb_do_redirect(skb);
|
||||
*ret = __NET_XMIT_STOLEN;
|
||||
return NULL;
|
||||
case TC_ACT_CONSUMED:
|
||||
*ret = __NET_XMIT_STOLEN;
|
||||
return NULL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user