Skip to content

Commit 4a49024

Browse files
author
Martin KaFai Lau
committed
Merge branch 'Avoid dummy bpf_offload_netdev in __bpf_prog_dev_bound_init'
Eduard Zingerman says: ==================== For a device bound BPF program with flag BPF_F_XDP_DEV_BOUND_ONLY, in case if device does not support offload, __bpf_prog_dev_bound_init() creates a dummy bpf_offload_netdev struct with .offdev field set to NULL. This dummy struct might be reused for programs without this flag bound to the same device. However, bpf_prog_offload_verifier_prep() that uses bpf_offload_netdev assumes that .offdev field cannot be NULL. This bug was reported by syzbot in [1]. [1] https://lore.kernel.org/bpf/000000000000d97f3c060479c4f8@google.com/ ==================== Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
2 parents a34a9f1 + e4c3116 commit 4a49024

2 files changed

Lines changed: 68 additions & 5 deletions

File tree

kernel/bpf/offload.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,14 @@ static int __bpf_prog_dev_bound_init(struct bpf_prog *prog, struct net_device *n
199199
offload->netdev = netdev;
200200

201201
ondev = bpf_offload_find_netdev(offload->netdev);
202+
/* When program is offloaded require presence of "true"
203+
* bpf_offload_netdev, avoid the one created for !ondev case below.
204+
*/
205+
if (bpf_prog_is_offloaded(prog->aux) && (!ondev || !ondev->offdev)) {
206+
err = -EINVAL;
207+
goto err_free;
208+
}
202209
if (!ondev) {
203-
if (bpf_prog_is_offloaded(prog->aux)) {
204-
err = -EINVAL;
205-
goto err_free;
206-
}
207-
208210
/* When only binding to the device, explicitly
209211
* create an entry in the hashtable.
210212
*/
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <net/if.h>
3+
#include <test_progs.h>
4+
#include <network_helpers.h>
5+
6+
#define LOCAL_NETNS "xdp_dev_bound_only_netns"
7+
8+
static int load_dummy_prog(char *name, __u32 ifindex, __u32 flags)
9+
{
10+
struct bpf_insn insns[] = { BPF_MOV64_IMM(BPF_REG_0, 0), BPF_EXIT_INSN() };
11+
LIBBPF_OPTS(bpf_prog_load_opts, opts);
12+
13+
opts.prog_flags = flags;
14+
opts.prog_ifindex = ifindex;
15+
return bpf_prog_load(BPF_PROG_TYPE_XDP, name, "GPL", insns, ARRAY_SIZE(insns), &opts);
16+
}
17+
18+
/* A test case for bpf_offload_netdev->offload handling bug:
19+
* - create a veth device (does not support offload);
20+
* - create a device bound XDP program with BPF_F_XDP_DEV_BOUND_ONLY flag
21+
* (such programs are not offloaded);
22+
* - create a device bound XDP program without flags (such programs are offloaded).
23+
* This might lead to 'BUG: kernel NULL pointer dereference'.
24+
*/
25+
void test_xdp_dev_bound_only_offdev(void)
26+
{
27+
struct nstoken *tok = NULL;
28+
__u32 ifindex;
29+
int fd1 = -1;
30+
int fd2 = -1;
31+
32+
SYS(out, "ip netns add " LOCAL_NETNS);
33+
tok = open_netns(LOCAL_NETNS);
34+
if (!ASSERT_OK_PTR(tok, "open_netns"))
35+
goto out;
36+
SYS(out, "ip link add eth42 type veth");
37+
ifindex = if_nametoindex("eth42");
38+
if (!ASSERT_NEQ(ifindex, 0, "if_nametoindex")) {
39+
perror("if_nametoindex");
40+
goto out;
41+
}
42+
fd1 = load_dummy_prog("dummy1", ifindex, BPF_F_XDP_DEV_BOUND_ONLY);
43+
if (!ASSERT_GE(fd1, 0, "load_dummy_prog #1")) {
44+
perror("load_dummy_prog #1");
45+
goto out;
46+
}
47+
/* Program with ifindex is considered offloaded, however veth
48+
* does not support offload => error should be reported.
49+
*/
50+
fd2 = load_dummy_prog("dummy2", ifindex, 0);
51+
ASSERT_EQ(fd2, -EINVAL, "load_dummy_prog #2 (offloaded)");
52+
53+
out:
54+
close(fd1);
55+
close(fd2);
56+
close_netns(tok);
57+
/* eth42 was added inside netns, removing the netns will
58+
* also remove eth42 veth pair.
59+
*/
60+
SYS_NOFAIL("ip netns del " LOCAL_NETNS);
61+
}

0 commit comments

Comments
 (0)