Skip to content

Commit 18f3d6b

Browse files
yonghong-songdavem330
authored andcommitted
selftests/bpf: Add test cases to test narrower ctx field loads
Add test cases in test_verifier and test_progs. Negative tests are added in test_verifier as well. The test in test_progs will compare the value of narrower ctx field load result vs. the masked value of normal full-field load result, and will fail if they are not the same. Acked-by: Daniel Borkmann <[email protected]> Signed-off-by: Yonghong Song <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 31fd858 commit 18f3d6b

File tree

4 files changed

+234
-1
lines changed

4 files changed

+234
-1
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ LDLIBS += -lcap -lelf
1414
TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
1515
test_align
1616

17-
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o
17+
TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \
18+
test_pkt_md_access.o
1819

1920
TEST_PROGS := test_kmod.sh
2021

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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 <string.h>
9+
#include <linux/bpf.h>
10+
#include <linux/pkt_cls.h>
11+
#include "bpf_helpers.h"
12+
13+
int _version SEC("version") = 1;
14+
15+
#define TEST_FIELD(TYPE, FIELD, MASK) \
16+
{ \
17+
TYPE tmp = *(volatile TYPE *)&skb->FIELD; \
18+
if (tmp != ((*(volatile __u32 *)&skb->FIELD) & MASK)) \
19+
return TC_ACT_SHOT; \
20+
}
21+
22+
SEC("test1")
23+
int process(struct __sk_buff *skb)
24+
{
25+
TEST_FIELD(__u8, len, 0xFF);
26+
TEST_FIELD(__u16, len, 0xFFFF);
27+
TEST_FIELD(__u32, len, 0xFFFFFFFF);
28+
TEST_FIELD(__u16, protocol, 0xFFFF);
29+
TEST_FIELD(__u32, protocol, 0xFFFFFFFF);
30+
TEST_FIELD(__u8, hash, 0xFF);
31+
TEST_FIELD(__u16, hash, 0xFFFF);
32+
TEST_FIELD(__u32, hash, 0xFFFFFFFF);
33+
34+
return TC_ACT_OK;
35+
}

tools/testing/selftests/bpf/test_progs.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,26 @@ static void test_bpf_obj_id(void)
484484
bpf_object__close(objs[i]);
485485
}
486486

487+
static void test_pkt_md_access(void)
488+
{
489+
const char *file = "./test_pkt_md_access.o";
490+
struct bpf_object *obj;
491+
__u32 duration, retval;
492+
int err, prog_fd;
493+
494+
err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
495+
if (err)
496+
return;
497+
498+
err = bpf_prog_test_run(prog_fd, 10, &pkt_v4, sizeof(pkt_v4),
499+
NULL, NULL, &retval, &duration);
500+
CHECK(err || retval, "",
501+
"err %d errno %d retval %d duration %d\n",
502+
err, errno, retval, duration);
503+
504+
bpf_object__close(obj);
505+
}
506+
487507
int main(void)
488508
{
489509
struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
@@ -495,6 +515,7 @@ int main(void)
495515
test_l4lb();
496516
test_tcp_estats();
497517
test_bpf_obj_id();
518+
test_pkt_md_access();
498519

499520
printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt);
500521
return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS;

tools/testing/selftests/bpf/test_verifier.c

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,59 @@ static struct bpf_test tests[] = {
10941094
.errstr = "invalid bpf_context access",
10951095
.result = REJECT,
10961096
},
1097+
{
1098+
"check skb->hash byte load permitted",
1099+
.insns = {
1100+
BPF_MOV64_IMM(BPF_REG_0, 0),
1101+
#ifdef __LITTLE_ENDIAN
1102+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1103+
offsetof(struct __sk_buff, hash)),
1104+
#else
1105+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1106+
offsetof(struct __sk_buff, hash) + 3),
1107+
#endif
1108+
BPF_EXIT_INSN(),
1109+
},
1110+
.result = ACCEPT,
1111+
},
1112+
{
1113+
"check skb->hash byte load not permitted 1",
1114+
.insns = {
1115+
BPF_MOV64_IMM(BPF_REG_0, 0),
1116+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1117+
offsetof(struct __sk_buff, hash) + 1),
1118+
BPF_EXIT_INSN(),
1119+
},
1120+
.errstr = "invalid bpf_context access",
1121+
.result = REJECT,
1122+
},
1123+
{
1124+
"check skb->hash byte load not permitted 2",
1125+
.insns = {
1126+
BPF_MOV64_IMM(BPF_REG_0, 0),
1127+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1128+
offsetof(struct __sk_buff, hash) + 2),
1129+
BPF_EXIT_INSN(),
1130+
},
1131+
.errstr = "invalid bpf_context access",
1132+
.result = REJECT,
1133+
},
1134+
{
1135+
"check skb->hash byte load not permitted 3",
1136+
.insns = {
1137+
BPF_MOV64_IMM(BPF_REG_0, 0),
1138+
#ifdef __LITTLE_ENDIAN
1139+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1140+
offsetof(struct __sk_buff, hash) + 3),
1141+
#else
1142+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
1143+
offsetof(struct __sk_buff, hash)),
1144+
#endif
1145+
BPF_EXIT_INSN(),
1146+
},
1147+
.errstr = "invalid bpf_context access",
1148+
.result = REJECT,
1149+
},
10971150
{
10981151
"check cb access: byte, wrong type",
10991152
.insns = {
@@ -1187,6 +1240,37 @@ static struct bpf_test tests[] = {
11871240
.errstr = "invalid bpf_context access",
11881241
.result = REJECT,
11891242
},
1243+
{
1244+
"check skb->hash half load permitted",
1245+
.insns = {
1246+
BPF_MOV64_IMM(BPF_REG_0, 0),
1247+
#ifdef __LITTLE_ENDIAN
1248+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
1249+
offsetof(struct __sk_buff, hash)),
1250+
#else
1251+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
1252+
offsetof(struct __sk_buff, hash) + 2),
1253+
#endif
1254+
BPF_EXIT_INSN(),
1255+
},
1256+
.result = ACCEPT,
1257+
},
1258+
{
1259+
"check skb->hash half load not permitted",
1260+
.insns = {
1261+
BPF_MOV64_IMM(BPF_REG_0, 0),
1262+
#ifdef __LITTLE_ENDIAN
1263+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
1264+
offsetof(struct __sk_buff, hash) + 2),
1265+
#else
1266+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
1267+
offsetof(struct __sk_buff, hash)),
1268+
#endif
1269+
BPF_EXIT_INSN(),
1270+
},
1271+
.errstr = "invalid bpf_context access",
1272+
.result = REJECT,
1273+
},
11901274
{
11911275
"check cb access: half, wrong type",
11921276
.insns = {
@@ -5103,6 +5187,98 @@ static struct bpf_test tests[] = {
51035187
},
51045188
.result = ACCEPT,
51055189
},
5190+
{
5191+
"check bpf_perf_event_data->sample_period byte load permitted",
5192+
.insns = {
5193+
BPF_MOV64_IMM(BPF_REG_0, 0),
5194+
#ifdef __LITTLE_ENDIAN
5195+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
5196+
offsetof(struct bpf_perf_event_data, sample_period)),
5197+
#else
5198+
BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_1,
5199+
offsetof(struct bpf_perf_event_data, sample_period) + 7),
5200+
#endif
5201+
BPF_EXIT_INSN(),
5202+
},
5203+
.result = ACCEPT,
5204+
.prog_type = BPF_PROG_TYPE_PERF_EVENT,
5205+
},
5206+
{
5207+
"check bpf_perf_event_data->sample_period half load permitted",
5208+
.insns = {
5209+
BPF_MOV64_IMM(BPF_REG_0, 0),
5210+
#ifdef __LITTLE_ENDIAN
5211+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5212+
offsetof(struct bpf_perf_event_data, sample_period)),
5213+
#else
5214+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5215+
offsetof(struct bpf_perf_event_data, sample_period) + 6),
5216+
#endif
5217+
BPF_EXIT_INSN(),
5218+
},
5219+
.result = ACCEPT,
5220+
.prog_type = BPF_PROG_TYPE_PERF_EVENT,
5221+
},
5222+
{
5223+
"check bpf_perf_event_data->sample_period word load permitted",
5224+
.insns = {
5225+
BPF_MOV64_IMM(BPF_REG_0, 0),
5226+
#ifdef __LITTLE_ENDIAN
5227+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
5228+
offsetof(struct bpf_perf_event_data, sample_period)),
5229+
#else
5230+
BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1,
5231+
offsetof(struct bpf_perf_event_data, sample_period) + 4),
5232+
#endif
5233+
BPF_EXIT_INSN(),
5234+
},
5235+
.result = ACCEPT,
5236+
.prog_type = BPF_PROG_TYPE_PERF_EVENT,
5237+
},
5238+
{
5239+
"check bpf_perf_event_data->sample_period dword load permitted",
5240+
.insns = {
5241+
BPF_MOV64_IMM(BPF_REG_0, 0),
5242+
BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1,
5243+
offsetof(struct bpf_perf_event_data, sample_period)),
5244+
BPF_EXIT_INSN(),
5245+
},
5246+
.result = ACCEPT,
5247+
.prog_type = BPF_PROG_TYPE_PERF_EVENT,
5248+
},
5249+
{
5250+
"check skb->data half load not permitted",
5251+
.insns = {
5252+
BPF_MOV64_IMM(BPF_REG_0, 0),
5253+
#ifdef __LITTLE_ENDIAN
5254+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5255+
offsetof(struct __sk_buff, data)),
5256+
#else
5257+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5258+
offsetof(struct __sk_buff, data) + 2),
5259+
#endif
5260+
BPF_EXIT_INSN(),
5261+
},
5262+
.result = REJECT,
5263+
.errstr = "invalid bpf_context access",
5264+
},
5265+
{
5266+
"check skb->tc_classid half load not permitted for lwt prog",
5267+
.insns = {
5268+
BPF_MOV64_IMM(BPF_REG_0, 0),
5269+
#ifdef __LITTLE_ENDIAN
5270+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5271+
offsetof(struct __sk_buff, tc_classid)),
5272+
#else
5273+
BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_1,
5274+
offsetof(struct __sk_buff, tc_classid) + 2),
5275+
#endif
5276+
BPF_EXIT_INSN(),
5277+
},
5278+
.result = REJECT,
5279+
.errstr = "invalid bpf_context access",
5280+
.prog_type = BPF_PROG_TYPE_LWT_IN,
5281+
},
51065282
};
51075283

51085284
static int probe_filter_length(const struct bpf_insn *fp)

0 commit comments

Comments
 (0)