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