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