1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 
4 static void test_global_data_number(struct bpf_object *obj, __u32 duration)
5 {
6 	int i, err, map_fd;
7 	uint64_t num;
8 
9 	map_fd = bpf_find_map(__func__, obj, "result_number");
10 	if (CHECK_FAIL(map_fd < 0))
11 		return;
12 
13 	struct {
14 		char *name;
15 		uint32_t key;
16 		uint64_t num;
17 	} tests[] = {
18 		{ "relocate .bss reference",     0, 0 },
19 		{ "relocate .data reference",    1, 42 },
20 		{ "relocate .rodata reference",  2, 24 },
21 		{ "relocate .bss reference",     3, 0 },
22 		{ "relocate .data reference",    4, 0xffeeff },
23 		{ "relocate .rodata reference",  5, 0xabab },
24 		{ "relocate .bss reference",     6, 1234 },
25 		{ "relocate .bss reference",     7, 0 },
26 		{ "relocate .rodata reference",  8, 0xab },
27 		{ "relocate .rodata reference",  9, 0x1111111111111111 },
28 		{ "relocate .rodata reference", 10, ~0 },
29 	};
30 
31 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
32 		err = bpf_map_lookup_elem(map_fd, &tests[i].key, &num);
33 		CHECK(err || num != tests[i].num, tests[i].name,
34 		      "err %d result %lx expected %lx\n",
35 		      err, num, tests[i].num);
36 	}
37 }
38 
39 static void test_global_data_string(struct bpf_object *obj, __u32 duration)
40 {
41 	int i, err, map_fd;
42 	char str[32];
43 
44 	map_fd = bpf_find_map(__func__, obj, "result_string");
45 	if (CHECK_FAIL(map_fd < 0))
46 		return;
47 
48 	struct {
49 		char *name;
50 		uint32_t key;
51 		char str[32];
52 	} tests[] = {
53 		{ "relocate .rodata reference", 0, "abcdefghijklmnopqrstuvwxyz" },
54 		{ "relocate .data reference",   1, "abcdefghijklmnopqrstuvwxyz" },
55 		{ "relocate .bss reference",    2, "" },
56 		{ "relocate .data reference",   3, "abcdexghijklmnopqrstuvwxyz" },
57 		{ "relocate .bss reference",    4, "\0\0hello" },
58 	};
59 
60 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
61 		err = bpf_map_lookup_elem(map_fd, &tests[i].key, str);
62 		CHECK(err || memcmp(str, tests[i].str, sizeof(str)),
63 		      tests[i].name, "err %d result \'%s\' expected \'%s\'\n",
64 		      err, str, tests[i].str);
65 	}
66 }
67 
68 struct foo {
69 	__u8  a;
70 	__u32 b;
71 	__u64 c;
72 };
73 
74 static void test_global_data_struct(struct bpf_object *obj, __u32 duration)
75 {
76 	int i, err, map_fd;
77 	struct foo val;
78 
79 	map_fd = bpf_find_map(__func__, obj, "result_struct");
80 	if (CHECK_FAIL(map_fd < 0))
81 		return;
82 
83 	struct {
84 		char *name;
85 		uint32_t key;
86 		struct foo val;
87 	} tests[] = {
88 		{ "relocate .rodata reference", 0, { 42, 0xfefeefef, 0x1111111111111111ULL, } },
89 		{ "relocate .bss reference",    1, { } },
90 		{ "relocate .rodata reference", 2, { } },
91 		{ "relocate .data reference",   3, { 41, 0xeeeeefef, 0x2111111111111111ULL, } },
92 	};
93 
94 	for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
95 		err = bpf_map_lookup_elem(map_fd, &tests[i].key, &val);
96 		CHECK(err || memcmp(&val, &tests[i].val, sizeof(val)),
97 		      tests[i].name, "err %d result { %u, %u, %llu } expected { %u, %u, %llu }\n",
98 		      err, val.a, val.b, val.c, tests[i].val.a, tests[i].val.b, tests[i].val.c);
99 	}
100 }
101 
102 static void test_global_data_rdonly(struct bpf_object *obj, __u32 duration)
103 {
104 	int err = -ENOMEM, map_fd, zero = 0;
105 	struct bpf_map *map;
106 	__u8 *buff;
107 
108 	map = bpf_object__find_map_by_name(obj, "test_glo.rodata");
109 	if (CHECK_FAIL(!map || !bpf_map__is_internal(map)))
110 		return;
111 
112 	map_fd = bpf_map__fd(map);
113 	if (CHECK_FAIL(map_fd < 0))
114 		return;
115 
116 	buff = malloc(bpf_map__def(map)->value_size);
117 	if (buff)
118 		err = bpf_map_update_elem(map_fd, &zero, buff, 0);
119 	free(buff);
120 	CHECK(!err || errno != EPERM, "test .rodata read-only map",
121 	      "err %d errno %d\n", err, errno);
122 }
123 
124 void test_global_data(void)
125 {
126 	const char *file = "./test_global_data.o";
127 	__u32 duration = 0, retval;
128 	struct bpf_object *obj;
129 	int err, prog_fd;
130 
131 	err = bpf_prog_load(file, BPF_PROG_TYPE_SCHED_CLS, &obj, &prog_fd);
132 	if (CHECK(err, "load program", "error %d loading %s\n", err, file))
133 		return;
134 
135 	err = bpf_prog_test_run(prog_fd, 1, &pkt_v4, sizeof(pkt_v4),
136 				NULL, NULL, &retval, &duration);
137 	CHECK(err || retval, "pass global data run",
138 	      "err %d errno %d retval %d duration %d\n",
139 	      err, errno, retval, duration);
140 
141 	test_global_data_number(obj, duration);
142 	test_global_data_string(obj, duration);
143 	test_global_data_struct(obj, duration);
144 	test_global_data_rdonly(obj, duration);
145 
146 	bpf_object__close(obj);
147 }
148