Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: fix null dereference when computing changes_pkt_data of prog w/o subprogs

bpf_prog_aux->func field might be NULL if program does not have
subprograms except for main sub-program. The fixed commit does
bpf_prog_aux->func access unconditionally, which might lead to null
pointer dereference.

The bug could be triggered by replacing the following BPF program:

SEC("tc")
int main_changes(struct __sk_buff *sk)
{
bpf_skb_pull_data(sk, 0);
return 0;
}

With the following BPF program:

SEC("freplace")
long changes_pkt_data(struct __sk_buff *sk)
{
return bpf_skb_pull_data(sk, 0);
}

bpf_prog_aux instance itself represents the main sub-program,
use this property to fix the bug.

Fixes: 81f6d0530ba0 ("bpf: check changes_pkt_data property for extension programs")
Reported-by: kernel test robot <lkp@intel.com>
Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/202412111822.qGw6tOyB-lkp@intel.com/
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20241212070711.427443-1-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
ac6542ad 7d0d6736

+5 -2
+5 -2
kernel/bpf/verifier.c
··· 22193 22193 } 22194 22194 if (tgt_prog) { 22195 22195 struct bpf_prog_aux *aux = tgt_prog->aux; 22196 + bool tgt_changes_pkt_data; 22196 22197 22197 22198 if (bpf_prog_is_dev_bound(prog->aux) && 22198 22199 !bpf_prog_dev_bound_match(prog, tgt_prog)) { ··· 22228 22227 "Extension programs should be JITed\n"); 22229 22228 return -EINVAL; 22230 22229 } 22231 - if (prog->aux->changes_pkt_data && 22232 - !aux->func[subprog]->aux->changes_pkt_data) { 22230 + tgt_changes_pkt_data = aux->func 22231 + ? aux->func[subprog]->aux->changes_pkt_data 22232 + : aux->changes_pkt_data; 22233 + if (prog->aux->changes_pkt_data && !tgt_changes_pkt_data) { 22233 22234 bpf_log(log, 22234 22235 "Extension program changes packet data, while original does not\n"); 22235 22236 return -EINVAL;