Skip to content

Commit 6882804

Browse files
4astdavem330
authored andcommitted
selftests/bpf: add a test for overlapping packet range checks
add simple C test case for llvm and verifier range check fix from commit b197768 ("bpf: improve verifier packet range checks") Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent dd26b7f commit 6882804

File tree

3 files changed

+215
-4
lines changed

3 files changed

+215
-4
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
LIBDIR := ../../../lib
22
BPFDIR := $(LIBDIR)/bpf
33

4-
CFLAGS += -Wall -O2 -I../../../include/uapi -I$(LIBDIR)
5-
LDLIBS += -lcap
4+
CFLAGS += -Wall -O2 -I../../../include/uapi -I$(LIBDIR) -I../../../include
5+
LDLIBS += -lcap -lelf
66

7-
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map
7+
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs
8+
9+
TEST_GEN_FILES = test_pkt_access.o
810

911
TEST_PROGS := test_kmod.sh
1012

1113
include ../lib.mk
1214

13-
BPFOBJ := $(OUTPUT)/bpf.o
15+
BPFOBJ := $(OUTPUT)/libbpf.a
1416

1517
$(TEST_GEN_PROGS): $(BPFOBJ)
1618

@@ -21,3 +23,10 @@ force:
2123

2224
$(BPFOBJ): force
2325
$(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/
26+
27+
CLANG ?= clang
28+
29+
%.o: %.c
30+
$(CLANG) -I../../../include/uapi -I../../../../samples/bpf/ \
31+
-D__x86_64__ -Wno-compare-distinct-pointer-types \
32+
-O2 -target bpf -c $< -o $@
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* Copyright (c) 2017 Facebook
2+
*
3+
* This program is free software; you can redistribute it and/or
4+
* modify it under the terms of version 2 of the GNU General Public
5+
* License as published by the Free Software Foundation.
6+
*/
7+
#include <stddef.h>
8+
#include <linux/bpf.h>
9+
#include <linux/if_ether.h>
10+
#include <linux/if_packet.h>
11+
#include <linux/ip.h>
12+
#include <linux/ipv6.h>
13+
#include <linux/in.h>
14+
#include <linux/tcp.h>
15+
#include <linux/pkt_cls.h>
16+
#include "bpf_helpers.h"
17+
18+
#define _htons __builtin_bswap16
19+
#define barrier() __asm__ __volatile__("": : :"memory")
20+
int _version SEC("version") = 1;
21+
22+
SEC("test1")
23+
int process(struct __sk_buff *skb)
24+
{
25+
void *data_end = (void *)(long)skb->data_end;
26+
void *data = (void *)(long)skb->data;
27+
struct ethhdr *eth = (struct ethhdr *)(data);
28+
struct tcphdr *tcp = NULL;
29+
__u8 proto = 255;
30+
__u64 ihl_len;
31+
32+
if (eth + 1 > data_end)
33+
return TC_ACT_SHOT;
34+
35+
if (eth->h_proto == _htons(ETH_P_IP)) {
36+
struct iphdr *iph = (struct iphdr *)(eth + 1);
37+
38+
if (iph + 1 > data_end)
39+
return TC_ACT_SHOT;
40+
ihl_len = iph->ihl * 4;
41+
proto = iph->protocol;
42+
tcp = (struct tcphdr *)((void *)(iph) + ihl_len);
43+
} else if (eth->h_proto == _htons(ETH_P_IPV6)) {
44+
struct ipv6hdr *ip6h = (struct ipv6hdr *)(eth + 1);
45+
46+
if (ip6h + 1 > data_end)
47+
return TC_ACT_SHOT;
48+
ihl_len = sizeof(*ip6h);
49+
proto = ip6h->nexthdr;
50+
tcp = (struct tcphdr *)((void *)(ip6h) + ihl_len);
51+
}
52+
53+
if (tcp) {
54+
if (((void *)(tcp) + 20) > data_end || proto != 6)
55+
return TC_ACT_SHOT;
56+
barrier(); /* to force ordering of checks */
57+
if (((void *)(tcp) + 18) > data_end)
58+
return TC_ACT_SHOT;
59+
if (tcp->urg_ptr == 123)
60+
return TC_ACT_OK;
61+
}
62+
63+
return TC_ACT_UNSPEC;
64+
}
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/* Copyright (c) 2017 Facebook
2+
*
3+
* This program is free software; you can redistribute it and/or
4+
* modify it under the terms of version 2 of the GNU General Public
5+
* License as published by the Free Software Foundation.
6+
*/
7+
#include <stdio.h>
8+
#include <unistd.h>
9+
#include <errno.h>
10+
#include <string.h>
11+
#include <assert.h>
12+
#include <stdlib.h>
13+
14+
#include <linux/types.h>
15+
typedef __u16 __sum16;
16+
#include <arpa/inet.h>
17+
#include <linux/if_ether.h>
18+
#include <linux/if_packet.h>
19+
#include <linux/ip.h>
20+
#include <linux/ipv6.h>
21+
#include <linux/tcp.h>
22+
23+
#include <sys/wait.h>
24+
#include <sys/resource.h>
25+
26+
#include <linux/bpf.h>
27+
#include <linux/err.h>
28+
#include <bpf/bpf.h>
29+
#include <bpf/libbpf.h>
30+
31+
#define _htons __builtin_bswap16
32+
33+
static int error_cnt, pass_cnt;
34+
35+
/* ipv4 test vector */
36+
static struct {
37+
struct ethhdr eth;
38+
struct iphdr iph;
39+
struct tcphdr tcp;
40+
} __packed pkt_v4 = {
41+
.eth.h_proto = _htons(ETH_P_IP),
42+
.iph.ihl = 5,
43+
.iph.protocol = 6,
44+
.tcp.urg_ptr = 123,
45+
};
46+
47+
/* ipv6 test vector */
48+
static struct {
49+
struct ethhdr eth;
50+
struct ipv6hdr iph;
51+
struct tcphdr tcp;
52+
} __packed pkt_v6 = {
53+
.eth.h_proto = _htons(ETH_P_IPV6),
54+
.iph.nexthdr = 6,
55+
.tcp.urg_ptr = 123,
56+
};
57+
58+
#define CHECK(condition, tag, format...) ({ \
59+
int __ret = !!(condition); \
60+
if (__ret) { \
61+
error_cnt++; \
62+
printf("%s:FAIL:%s ", __func__, tag); \
63+
printf(format); \
64+
} else { \
65+
pass_cnt++; \
66+
printf("%s:PASS:%s %d nsec\n", __func__, tag, duration);\
67+
} \
68+
})
69+
70+
static int bpf_prog_load(const char *file, enum bpf_prog_type type,
71+
struct bpf_object **pobj, int *prog_fd)
72+
{
73+
struct bpf_program *prog;
74+
struct bpf_object *obj;
75+
int err;
76+
77+
obj = bpf_object__open(file);
78+
if (IS_ERR(obj)) {
79+
error_cnt++;
80+
return -ENOENT;
81+
}
82+
83+
prog = bpf_program__next(NULL, obj);
84+
if (!prog) {
85+
bpf_object__close(obj);
86+
error_cnt++;
87+
return -ENOENT;
88+
}
89+
90+
bpf_program__set_type(prog, type);
91+
err = bpf_object__load(obj);
92+
if (err) {
93+
bpf_object__close(obj);
94+
error_cnt++;
95+
return -EINVAL;
96+
}
97+
98+
*pobj = obj;
99+
*prog_fd = bpf_program__fd(prog);
100+
return 0;
101+
}
102+
103+
static void test_pkt_access(void)
104+
{
105+
const char *file = "./test_pkt_access.o";
106+
struct bpf_object *obj;
107+
__u32 duration, retval;
108+
int err, prog_fd;
109+
110+
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
111+
if (err)
112+
return;
113+
114+
err = bpf_prog_test_run(prog_fd, 100000, &pkt_v4, sizeof(pkt_v4),
115+
NULL, NULL, &retval, &duration);
116+
CHECK(err || errno || retval, "ipv4",
117+
"err %d errno %d retval %d duration %d\n",
118+
err, errno, retval, duration);
119+
120+
err = bpf_prog_test_run(prog_fd, 100000, &pkt_v6, sizeof(pkt_v6),
121+
NULL, NULL, &retval, &duration);
122+
CHECK(err || errno || retval, "ipv6",
123+
"err %d errno %d retval %d duration %d\n",
124+
err, errno, retval, duration);
125+
bpf_object__close(obj);
126+
}
127+
128+
int main(void)
129+
{
130+
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
131+
132+
setrlimit(RLIMIT_MEMLOCK, &rinf);
133+
134+
test_pkt_access();
135+
136+
printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
137+
return 0;
138+
}

0 commit comments

Comments
 (0)