Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Unprivileged tests for test_loader.c

Extends test_loader.c:test_loader__run_subtests() by allowing to
execute tests in unprivileged mode, similar to test_verifier.c.

Adds the following new attributes controlling test_loader behavior:

__msg_unpriv
__success_unpriv
__failure_unpriv

* If any of these attributes is present the test would be loaded in
unprivileged mode.
* If only "privileged" attributes are present the test would be loaded
only in privileged mode.
* If both "privileged" and "unprivileged" attributes are present the
test would be loaded in both modes.
* If test has to be executed in both modes, __msg(text) is specified
and __msg_unpriv is not specified the behavior is the same as if
__msg_unpriv(text) is specified.
* For test filtering purposes the name of the program loaded in
unprivileged mode is derived from the usual program name by adding
`@unpriv' suffix.

Also adds attribute '__description'. This attribute specifies text to
be used instead of a program name for display and filtering purposes.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20230325025524.144043-4-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
1d56ade0 207b1ba3

+395 -101
+6 -4
tools/testing/selftests/bpf/Makefile
··· 231 231 232 232 $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(BPFOBJ) 233 233 234 - CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o 235 234 TESTING_HELPERS := $(OUTPUT)/testing_helpers.o 235 + CGROUP_HELPERS := $(OUTPUT)/cgroup_helpers.o 236 + UNPRIV_HELPERS := $(OUTPUT)/unpriv_helpers.o 236 237 TRACE_HELPERS := $(OUTPUT)/trace_helpers.o 237 238 JSON_WRITER := $(OUTPUT)/json_writer.o 238 239 CAP_HELPERS := $(OUTPUT)/cap_helpers.o ··· 253 252 $(OUTPUT)/xdping: $(TESTING_HELPERS) 254 253 $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS) 255 254 $(OUTPUT)/test_maps: $(TESTING_HELPERS) 256 - $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) 255 + $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS) 257 256 $(OUTPUT)/xsk.o: $(BPFOBJ) 258 257 259 258 BPFTOOL ?= $(DEFAULT_BPFTOOL) ··· 561 560 TRUNNER_EXTRA_SOURCES := test_progs.c cgroup_helpers.c trace_helpers.c \ 562 561 network_helpers.c testing_helpers.c \ 563 562 btf_helpers.c flow_dissector_load.h \ 564 - cap_helpers.c test_loader.c xsk.c disasm.c \ 565 - json_writer.c 563 + cap_helpers.c test_loader.c xsk.c disasm.c \ 564 + json_writer.c unpriv_helpers.c 565 + 566 566 TRUNNER_EXTRA_FILES := $(OUTPUT)/urandom_read $(OUTPUT)/bpf_testmod.ko \ 567 567 $(OUTPUT)/liburandom_read.so \ 568 568 $(OUTPUT)/xdp_synproxy \
+9
tools/testing/selftests/bpf/autoconf_helper.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #ifdef HAVE_GENHDR 4 + # include "autoconf.h" 5 + #else 6 + # if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__) 7 + # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 8 + # endif 9 + #endif
+25
tools/testing/selftests/bpf/progs/bpf_misc.h
··· 5 5 /* This set of attributes controls behavior of the 6 6 * test_loader.c:test_loader__run_subtests(). 7 7 * 8 + * The test_loader sequentially loads each program in a skeleton. 9 + * Programs could be loaded in privileged and unprivileged modes. 10 + * - __success, __failure, __msg imply privileged mode; 11 + * - __success_unpriv, __failure_unpriv, __msg_unpriv imply 12 + * unprivileged mode. 13 + * If combination of privileged and unprivileged attributes is present 14 + * both modes are used. If none are present privileged mode is implied. 15 + * 16 + * See test_loader.c:drop_capabilities() for exact set of capabilities 17 + * that differ between privileged and unprivileged modes. 18 + * 19 + * For test filtering purposes the name of the program loaded in 20 + * unprivileged mode is derived from the usual program name by adding 21 + * `@unpriv' suffix. 22 + * 8 23 * __msg Message expected to be found in the verifier log. 9 24 * Multiple __msg attributes could be specified. 25 + * __msg_unpriv Same as __msg but for unprivileged mode. 10 26 * 11 27 * __success Expect program load success in privileged mode. 28 + * __success_unpriv Expect program load success in unprivileged mode. 12 29 * 13 30 * __failure Expect program load failure in privileged mode. 31 + * __failure_unpriv Expect program load failure in unprivileged mode. 32 + * 33 + * __description Text to be used instead of a program name for display 34 + * and filtering purposes. 14 35 * 15 36 * __log_level Log level to use for the program, numeric value expected. 16 37 * ··· 48 27 #define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" msg))) 49 28 #define __failure __attribute__((btf_decl_tag("comment:test_expect_failure"))) 50 29 #define __success __attribute__((btf_decl_tag("comment:test_expect_success"))) 30 + #define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc))) 31 + #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" msg))) 32 + #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv"))) 33 + #define __success_unpriv __attribute__((btf_decl_tag("comment:test_expect_success_unpriv"))) 51 34 #define __log_level(lvl) __attribute__((btf_decl_tag("comment:test_log_level="#lvl))) 52 35 #define __flag(flag) __attribute__((btf_decl_tag("comment:test_prog_flags="#flag))) 53 36
+320 -74
tools/testing/selftests/bpf/test_loader.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0-only 2 2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 + #include <linux/capability.h> 3 4 #include <stdlib.h> 4 5 #include <test_progs.h> 5 6 #include <bpf/btf.h> 7 + 8 + #include "autoconf_helper.h" 9 + #include "unpriv_helpers.h" 10 + #include "cap_helpers.h" 6 11 7 12 #define str_has_pfx(str, pfx) \ 8 13 (strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0) ··· 17 12 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure" 18 13 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" 19 14 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg=" 15 + #define TEST_TAG_EXPECT_FAILURE_UNPRIV "comment:test_expect_failure_unpriv" 16 + #define TEST_TAG_EXPECT_SUCCESS_UNPRIV "comment:test_expect_success_unpriv" 17 + #define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "comment:test_expect_msg_unpriv=" 20 18 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level=" 21 19 #define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags=" 20 + #define TEST_TAG_DESCRIPTION_PFX "comment:test_description=" 22 21 23 - struct test_spec { 24 - const char *name; 22 + #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 23 + #define EFFICIENT_UNALIGNED_ACCESS 1 24 + #else 25 + #define EFFICIENT_UNALIGNED_ACCESS 0 26 + #endif 27 + 28 + static int sysctl_unpriv_disabled = -1; 29 + 30 + enum mode { 31 + PRIV = 1, 32 + UNPRIV = 2 33 + }; 34 + 35 + struct test_subspec { 36 + char *name; 25 37 bool expect_failure; 26 38 const char **expect_msgs; 27 39 size_t expect_msg_cnt; 40 + }; 41 + 42 + struct test_spec { 43 + const char *prog_name; 44 + struct test_subspec priv; 45 + struct test_subspec unpriv; 28 46 int log_level; 29 47 int prog_flags; 48 + int mode_mask; 30 49 }; 31 50 32 51 static int tester_init(struct test_loader *tester) ··· 73 44 free(tester->log_buf); 74 45 } 75 46 47 + static void free_test_spec(struct test_spec *spec) 48 + { 49 + free(spec->priv.name); 50 + free(spec->unpriv.name); 51 + free(spec->priv.expect_msgs); 52 + free(spec->unpriv.expect_msgs); 53 + } 54 + 55 + static int push_msg(const char *msg, struct test_subspec *subspec) 56 + { 57 + void *tmp; 58 + 59 + tmp = realloc(subspec->expect_msgs, (1 + subspec->expect_msg_cnt) * sizeof(void *)); 60 + if (!tmp) { 61 + ASSERT_FAIL("failed to realloc memory for messages\n"); 62 + return -ENOMEM; 63 + } 64 + subspec->expect_msgs = tmp; 65 + subspec->expect_msgs[subspec->expect_msg_cnt++] = msg; 66 + 67 + return 0; 68 + } 69 + 70 + /* Uses btf_decl_tag attributes to describe the expected test 71 + * behavior, see bpf_misc.h for detailed description of each attribute 72 + * and attribute combinations. 73 + */ 76 74 static int parse_test_spec(struct test_loader *tester, 77 75 struct bpf_object *obj, 78 76 struct bpf_program *prog, 79 77 struct test_spec *spec) 80 78 { 79 + const char *description = NULL; 80 + bool has_unpriv_result = false; 81 + int func_id, i, err = 0; 81 82 struct btf *btf; 82 - int func_id, i; 83 83 84 84 memset(spec, 0, sizeof(*spec)); 85 85 86 - spec->name = bpf_program__name(prog); 86 + spec->prog_name = bpf_program__name(prog); 87 87 88 88 btf = bpf_object__btf(obj); 89 89 if (!btf) { ··· 120 62 return -EINVAL; 121 63 } 122 64 123 - func_id = btf__find_by_name_kind(btf, spec->name, BTF_KIND_FUNC); 65 + func_id = btf__find_by_name_kind(btf, spec->prog_name, BTF_KIND_FUNC); 124 66 if (func_id < 0) { 125 - ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->name); 67 + ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->prog_name); 126 68 return -EINVAL; 127 69 } 128 70 129 71 for (i = 1; i < btf__type_cnt(btf); i++) { 72 + const char *s, *val, *msg; 130 73 const struct btf_type *t; 131 - const char *s, *val; 132 74 char *e; 133 75 134 76 t = btf__type_by_id(btf, i); ··· 139 81 continue; 140 82 141 83 s = btf__str_by_offset(btf, t->name_off); 142 - if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) { 143 - spec->expect_failure = true; 84 + if (str_has_pfx(s, TEST_TAG_DESCRIPTION_PFX)) { 85 + description = s + sizeof(TEST_TAG_DESCRIPTION_PFX) - 1; 86 + } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) { 87 + spec->priv.expect_failure = true; 88 + spec->mode_mask |= PRIV; 144 89 } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) { 145 - spec->expect_failure = false; 90 + spec->priv.expect_failure = false; 91 + spec->mode_mask |= PRIV; 92 + } else if (strcmp(s, TEST_TAG_EXPECT_FAILURE_UNPRIV) == 0) { 93 + spec->unpriv.expect_failure = true; 94 + spec->mode_mask |= UNPRIV; 95 + has_unpriv_result = true; 96 + } else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS_UNPRIV) == 0) { 97 + spec->unpriv.expect_failure = false; 98 + spec->mode_mask |= UNPRIV; 99 + has_unpriv_result = true; 146 100 } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) { 147 - void *tmp; 148 - const char **msg; 149 - 150 - tmp = realloc(spec->expect_msgs, 151 - (1 + spec->expect_msg_cnt) * sizeof(void *)); 152 - if (!tmp) { 153 - ASSERT_FAIL("failed to realloc memory for messages\n"); 154 - return -ENOMEM; 155 - } 156 - spec->expect_msgs = tmp; 157 - msg = &spec->expect_msgs[spec->expect_msg_cnt++]; 158 - *msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 101 + msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1; 102 + err = push_msg(msg, &spec->priv); 103 + if (err) 104 + goto cleanup; 105 + spec->mode_mask |= PRIV; 106 + } else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV)) { 107 + msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX_UNPRIV) - 1; 108 + err = push_msg(msg, &spec->unpriv); 109 + if (err) 110 + goto cleanup; 111 + spec->mode_mask |= UNPRIV; 159 112 } else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) { 160 113 val = s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1; 161 114 errno = 0; 162 115 spec->log_level = strtol(val, &e, 0); 163 116 if (errno || e[0] != '\0') { 164 - ASSERT_FAIL("failed to parse test log level from '%s'", s); 165 - return -EINVAL; 117 + PRINT_FAIL("failed to parse test log level from '%s'\n", s); 118 + err = -EINVAL; 119 + goto cleanup; 166 120 } 167 121 } else if (str_has_pfx(s, TEST_TAG_PROG_FLAGS_PFX)) { 168 122 val = s + sizeof(TEST_TAG_PROG_FLAGS_PFX) - 1; ··· 194 124 errno = 0; 195 125 spec->prog_flags |= strtol(val, &e, 0); 196 126 if (errno || e[0] != '\0') { 197 - ASSERT_FAIL("failed to parse test prog flags from '%s'", s); 198 - return -EINVAL; 127 + PRINT_FAIL("failed to parse test prog flags from '%s'\n", 128 + val); 129 + err = -EINVAL; 130 + goto cleanup; 199 131 } 200 132 } 201 133 } 202 134 } 203 135 136 + if (spec->mode_mask == 0) 137 + spec->mode_mask = PRIV; 138 + 139 + if (!description) 140 + description = spec->prog_name; 141 + 142 + if (spec->mode_mask & PRIV) { 143 + spec->priv.name = strdup(description); 144 + if (!spec->priv.name) { 145 + PRINT_FAIL("failed to allocate memory for priv.name\n"); 146 + err = -ENOMEM; 147 + goto cleanup; 148 + } 149 + } 150 + 151 + if (spec->mode_mask & UNPRIV) { 152 + int descr_len = strlen(description); 153 + const char *suffix = " @unpriv"; 154 + char *name; 155 + 156 + name = malloc(descr_len + strlen(suffix) + 1); 157 + if (!name) { 158 + PRINT_FAIL("failed to allocate memory for unpriv.name\n"); 159 + err = -ENOMEM; 160 + goto cleanup; 161 + } 162 + 163 + strcpy(name, description); 164 + strcpy(&name[descr_len], suffix); 165 + spec->unpriv.name = name; 166 + } 167 + 168 + if (spec->mode_mask & (PRIV | UNPRIV)) { 169 + if (!has_unpriv_result) 170 + spec->unpriv.expect_failure = spec->priv.expect_failure; 171 + 172 + if (!spec->unpriv.expect_msgs) { 173 + size_t sz = spec->priv.expect_msg_cnt * sizeof(void *); 174 + 175 + spec->unpriv.expect_msgs = malloc(sz); 176 + if (!spec->unpriv.expect_msgs) { 177 + PRINT_FAIL("failed to allocate memory for unpriv.expect_msgs\n"); 178 + err = -ENOMEM; 179 + goto cleanup; 180 + } 181 + memcpy(spec->unpriv.expect_msgs, spec->priv.expect_msgs, sz); 182 + spec->unpriv.expect_msg_cnt = spec->priv.expect_msg_cnt; 183 + } 184 + } 185 + 204 186 return 0; 187 + 188 + cleanup: 189 + free_test_spec(spec); 190 + return err; 205 191 } 206 192 207 193 static void prepare_case(struct test_loader *tester, ··· 274 148 275 149 bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz); 276 150 277 - /* Make sure we set at least minimal log level, unless test requirest 151 + /* Make sure we set at least minimal log level, unless test requires 278 152 * even higher level already. Make sure to preserve independent log 279 153 * level 4 (verifier stats), though. 280 154 */ ··· 298 172 } 299 173 300 174 static void validate_case(struct test_loader *tester, 301 - struct test_spec *spec, 175 + struct test_subspec *subspec, 302 176 struct bpf_object *obj, 303 177 struct bpf_program *prog, 304 178 int load_err) 305 179 { 306 180 int i, j; 307 181 308 - for (i = 0; i < spec->expect_msg_cnt; i++) { 182 + for (i = 0; i < subspec->expect_msg_cnt; i++) { 309 183 char *match; 310 184 const char *expect_msg; 311 185 312 - expect_msg = spec->expect_msgs[i]; 186 + expect_msg = subspec->expect_msgs[i]; 313 187 314 188 match = strstr(tester->log_buf + tester->next_match_pos, expect_msg); 315 189 if (!ASSERT_OK_PTR(match, "expect_msg")) { ··· 317 191 if (env.verbosity == VERBOSE_NONE) 318 192 emit_verifier_log(tester->log_buf, true /*force*/); 319 193 for (j = 0; j < i; j++) 320 - fprintf(stderr, "MATCHED MSG: '%s'\n", spec->expect_msgs[j]); 194 + fprintf(stderr, 195 + "MATCHED MSG: '%s'\n", subspec->expect_msgs[j]); 321 196 fprintf(stderr, "EXPECTED MSG: '%s'\n", expect_msg); 322 197 return; 323 198 } ··· 327 200 } 328 201 } 329 202 203 + struct cap_state { 204 + __u64 old_caps; 205 + bool initialized; 206 + }; 207 + 208 + static int drop_capabilities(struct cap_state *caps) 209 + { 210 + const __u64 caps_to_drop = (1ULL << CAP_SYS_ADMIN | 1ULL << CAP_NET_ADMIN | 211 + 1ULL << CAP_PERFMON | 1ULL << CAP_BPF); 212 + int err; 213 + 214 + err = cap_disable_effective(caps_to_drop, &caps->old_caps); 215 + if (err) { 216 + PRINT_FAIL("failed to drop capabilities: %i, %s\n", err, strerror(err)); 217 + return err; 218 + } 219 + 220 + caps->initialized = true; 221 + return 0; 222 + } 223 + 224 + static int restore_capabilities(struct cap_state *caps) 225 + { 226 + int err; 227 + 228 + if (!caps->initialized) 229 + return 0; 230 + 231 + err = cap_enable_effective(caps->old_caps, NULL); 232 + if (err) 233 + PRINT_FAIL("failed to restore capabilities: %i, %s\n", err, strerror(err)); 234 + caps->initialized = false; 235 + return err; 236 + } 237 + 238 + static bool can_execute_unpriv(struct test_loader *tester, struct test_spec *spec) 239 + { 240 + if (sysctl_unpriv_disabled < 0) 241 + sysctl_unpriv_disabled = get_unpriv_disabled() ? 1 : 0; 242 + if (sysctl_unpriv_disabled) 243 + return false; 244 + if ((spec->prog_flags & BPF_F_ANY_ALIGNMENT) && !EFFICIENT_UNALIGNED_ACCESS) 245 + return false; 246 + return true; 247 + } 248 + 249 + static bool is_unpriv_capable_map(struct bpf_map *map) 250 + { 251 + enum bpf_map_type type; 252 + __u32 flags; 253 + 254 + type = bpf_map__type(map); 255 + 256 + switch (type) { 257 + case BPF_MAP_TYPE_HASH: 258 + case BPF_MAP_TYPE_PERCPU_HASH: 259 + case BPF_MAP_TYPE_HASH_OF_MAPS: 260 + flags = bpf_map__map_flags(map); 261 + return !(flags & BPF_F_ZERO_SEED); 262 + case BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE: 263 + case BPF_MAP_TYPE_ARRAY: 264 + case BPF_MAP_TYPE_RINGBUF: 265 + case BPF_MAP_TYPE_PROG_ARRAY: 266 + case BPF_MAP_TYPE_CGROUP_ARRAY: 267 + case BPF_MAP_TYPE_PERCPU_ARRAY: 268 + case BPF_MAP_TYPE_USER_RINGBUF: 269 + case BPF_MAP_TYPE_ARRAY_OF_MAPS: 270 + case BPF_MAP_TYPE_CGROUP_STORAGE: 271 + case BPF_MAP_TYPE_PERF_EVENT_ARRAY: 272 + return true; 273 + default: 274 + return false; 275 + } 276 + } 277 + 330 278 /* this function is forced noinline and has short generic name to look better 331 279 * in test_progs output (in case of a failure) 332 280 */ 333 281 static noinline 334 282 void run_subtest(struct test_loader *tester, 335 - const char *skel_name, 336 - skel_elf_bytes_fn elf_bytes_factory) 283 + struct bpf_object_open_opts *open_opts, 284 + const void *obj_bytes, 285 + size_t obj_byte_cnt, 286 + struct test_spec *spec, 287 + bool unpriv) 288 + { 289 + struct test_subspec *subspec = unpriv ? &spec->unpriv : &spec->priv; 290 + struct cap_state caps = {}; 291 + struct bpf_program *tprog; 292 + struct bpf_object *tobj; 293 + struct bpf_map *map; 294 + int err; 295 + 296 + if (!test__start_subtest(subspec->name)) 297 + return; 298 + 299 + if (unpriv) { 300 + if (!can_execute_unpriv(tester, spec)) { 301 + test__skip(); 302 + test__end_subtest(); 303 + return; 304 + } 305 + if (drop_capabilities(&caps)) { 306 + test__end_subtest(); 307 + return; 308 + } 309 + } 310 + 311 + tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, open_opts); 312 + if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ 313 + goto subtest_cleanup; 314 + 315 + bpf_object__for_each_program(tprog, tobj) 316 + bpf_program__set_autoload(tprog, false); 317 + 318 + bpf_object__for_each_program(tprog, tobj) { 319 + /* only load specified program */ 320 + if (strcmp(bpf_program__name(tprog), spec->prog_name) == 0) { 321 + bpf_program__set_autoload(tprog, true); 322 + break; 323 + } 324 + } 325 + 326 + prepare_case(tester, spec, tobj, tprog); 327 + 328 + /* By default bpf_object__load() automatically creates all 329 + * maps declared in the skeleton. Some map types are only 330 + * allowed in priv mode. Disable autoload for such maps in 331 + * unpriv mode. 332 + */ 333 + bpf_object__for_each_map(map, tobj) 334 + bpf_map__set_autocreate(map, !unpriv || is_unpriv_capable_map(map)); 335 + 336 + err = bpf_object__load(tobj); 337 + if (subspec->expect_failure) { 338 + if (!ASSERT_ERR(err, "unexpected_load_success")) { 339 + emit_verifier_log(tester->log_buf, false /*force*/); 340 + goto tobj_cleanup; 341 + } 342 + } else { 343 + if (!ASSERT_OK(err, "unexpected_load_failure")) { 344 + emit_verifier_log(tester->log_buf, true /*force*/); 345 + goto tobj_cleanup; 346 + } 347 + } 348 + 349 + emit_verifier_log(tester->log_buf, false /*force*/); 350 + validate_case(tester, subspec, tobj, tprog, err); 351 + 352 + tobj_cleanup: 353 + bpf_object__close(tobj); 354 + subtest_cleanup: 355 + test__end_subtest(); 356 + restore_capabilities(&caps); 357 + } 358 + 359 + static void process_subtest(struct test_loader *tester, 360 + const char *skel_name, 361 + skel_elf_bytes_fn elf_bytes_factory) 337 362 { 338 363 LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name); 339 - struct bpf_object *obj = NULL, *tobj; 340 - struct bpf_program *prog, *tprog; 364 + struct bpf_object *obj = NULL; 365 + struct bpf_program *prog; 341 366 const void *obj_bytes; 342 367 size_t obj_byte_cnt; 343 368 int err; ··· 503 224 return; 504 225 505 226 bpf_object__for_each_program(prog, obj) { 506 - const char *prog_name = bpf_program__name(prog); 507 227 struct test_spec spec; 508 - 509 - if (!test__start_subtest(prog_name)) 510 - continue; 511 228 512 229 /* if we can't derive test specification, go to the next test */ 513 230 err = parse_test_spec(tester, obj, prog, &spec); ··· 513 238 continue; 514 239 } 515 240 516 - tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts); 517 - if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */ 518 - continue; 241 + if (spec.mode_mask & PRIV) 242 + run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, &spec, false); 243 + if (spec.mode_mask & UNPRIV) 244 + run_subtest(tester, &open_opts, obj_bytes, obj_byte_cnt, &spec, true); 519 245 520 - bpf_object__for_each_program(tprog, tobj) 521 - bpf_program__set_autoload(tprog, false); 522 - 523 - bpf_object__for_each_program(tprog, tobj) { 524 - /* only load specified program */ 525 - if (strcmp(bpf_program__name(tprog), prog_name) == 0) { 526 - bpf_program__set_autoload(tprog, true); 527 - break; 528 - } 529 - } 530 - 531 - prepare_case(tester, &spec, tobj, tprog); 532 - 533 - err = bpf_object__load(tobj); 534 - if (spec.expect_failure) { 535 - if (!ASSERT_ERR(err, "unexpected_load_success")) { 536 - emit_verifier_log(tester->log_buf, false /*force*/); 537 - goto tobj_cleanup; 538 - } 539 - } else { 540 - if (!ASSERT_OK(err, "unexpected_load_failure")) { 541 - emit_verifier_log(tester->log_buf, true /*force*/); 542 - goto tobj_cleanup; 543 - } 544 - } 545 - 546 - emit_verifier_log(tester->log_buf, false /*force*/); 547 - validate_case(tester, &spec, tobj, tprog, err); 548 - 549 - tobj_cleanup: 550 - bpf_object__close(tobj); 246 + free_test_spec(&spec); 551 247 } 552 248 553 249 bpf_object__close(obj); ··· 529 283 skel_elf_bytes_fn elf_bytes_factory) 530 284 { 531 285 /* see comment in run_subtest() for why we do this function nesting */ 532 - run_subtest(tester, skel_name, elf_bytes_factory); 286 + process_subtest(tester, skel_name, elf_bytes_factory); 533 287 }
+2 -23
tools/testing/selftests/bpf/test_verifier.c
··· 33 33 #include <bpf/bpf.h> 34 34 #include <bpf/libbpf.h> 35 35 36 - #ifdef HAVE_GENHDR 37 - # include "autoconf.h" 38 - #else 39 - # if defined(__i386) || defined(__x86_64) || defined(__s390x__) || defined(__aarch64__) 40 - # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 41 - # endif 42 - #endif 36 + #include "autoconf_helper.h" 37 + #include "unpriv_helpers.h" 43 38 #include "cap_helpers.h" 44 39 #include "bpf_rand.h" 45 40 #include "bpf_util.h" ··· 1658 1663 } 1659 1664 1660 1665 return (caps & ADMIN_CAPS) == ADMIN_CAPS; 1661 - } 1662 - 1663 - static void get_unpriv_disabled() 1664 - { 1665 - char buf[2]; 1666 - FILE *fd; 1667 - 1668 - fd = fopen("/proc/sys/"UNPRIV_SYSCTL, "r"); 1669 - if (!fd) { 1670 - perror("fopen /proc/sys/"UNPRIV_SYSCTL); 1671 - unpriv_disabled = true; 1672 - return; 1673 - } 1674 - if (fgets(buf, 2, fd) == buf && atoi(buf)) 1675 - unpriv_disabled = true; 1676 - fclose(fd); 1677 1666 } 1678 1667 1679 1668 static bool test_as_unpriv(struct bpf_test *test)
+26
tools/testing/selftests/bpf/unpriv_helpers.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <stdbool.h> 4 + #include <stdlib.h> 5 + #include <error.h> 6 + #include <stdio.h> 7 + 8 + #include "unpriv_helpers.h" 9 + 10 + bool get_unpriv_disabled(void) 11 + { 12 + bool disabled; 13 + char buf[2]; 14 + FILE *fd; 15 + 16 + fd = fopen("/proc/sys/" UNPRIV_SYSCTL, "r"); 17 + if (fd) { 18 + disabled = (fgets(buf, 2, fd) == buf && atoi(buf)); 19 + fclose(fd); 20 + } else { 21 + perror("fopen /proc/sys/" UNPRIV_SYSCTL); 22 + disabled = true; 23 + } 24 + 25 + return disabled; 26 + }
+7
tools/testing/selftests/bpf/unpriv_helpers.h
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #include <stdbool.h> 4 + 5 + #define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" 6 + 7 + bool get_unpriv_disabled(void);