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

selftests/bpf: Add update_elem failure test for task storage uptr

This patch test the following failures in syscall update_elem
1. The first update_elem(BPF_F_LOCK) should be EOPNOTSUPP. syscall.c takes
care of unpinning the uptr.
2. The second update_elem(BPF_EXIST) fails. syscall.c takes care of
unpinning the uptr.
3. The forth update_elem(BPF_NOEXIST) fails. bpf_local_storage_update
takes care of unpinning the uptr.

Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20241023234759.860539-11-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
cbf9f849 51fff408

+92
+45
tools/testing/selftests/bpf/prog_tests/task_local_storage.c
··· 17 17 #include "task_storage_nodeadlock.skel.h" 18 18 #include "uptr_test_common.h" 19 19 #include "task_ls_uptr.skel.h" 20 + #include "uptr_update_failure.skel.h" 20 21 21 22 static void test_sys_enter_exit(void) 22 23 { ··· 409 408 munmap(mem, page_size * 2); 410 409 } 411 410 411 + static void test_uptr_update_failure(void) 412 + { 413 + struct value_lock_type value = {}; 414 + struct uptr_update_failure *skel; 415 + int err, task_fd, map_fd; 416 + 417 + task_fd = sys_pidfd_open(getpid(), 0); 418 + if (!ASSERT_OK_FD(task_fd, "task_fd")) 419 + return; 420 + 421 + skel = uptr_update_failure__open_and_load(); 422 + if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 423 + goto out; 424 + 425 + map_fd = bpf_map__fd(skel->maps.datamap); 426 + 427 + value.udata = &udata; 428 + err = bpf_map_update_elem(map_fd, &task_fd, &value, BPF_F_LOCK); 429 + if (!ASSERT_ERR(err, "update_elem(udata, BPF_F_LOCK)")) 430 + goto out; 431 + ASSERT_EQ(errno, EOPNOTSUPP, "errno"); 432 + 433 + err = bpf_map_update_elem(map_fd, &task_fd, &value, BPF_EXIST); 434 + if (!ASSERT_ERR(err, "update_elem(udata, BPF_EXIST)")) 435 + goto out; 436 + ASSERT_EQ(errno, ENOENT, "errno"); 437 + 438 + err = bpf_map_update_elem(map_fd, &task_fd, &value, BPF_NOEXIST); 439 + if (!ASSERT_OK(err, "update_elem(udata, BPF_NOEXIST)")) 440 + goto out; 441 + 442 + value.udata = &udata2; 443 + err = bpf_map_update_elem(map_fd, &task_fd, &value, BPF_NOEXIST); 444 + if (!ASSERT_ERR(err, "update_elem(udata2, BPF_NOEXIST)")) 445 + goto out; 446 + ASSERT_EQ(errno, EEXIST, "errno"); 447 + 448 + out: 449 + uptr_update_failure__destroy(skel); 450 + close(task_fd); 451 + } 452 + 412 453 void test_task_local_storage(void) 413 454 { 414 455 if (test__start_subtest("sys_enter_exit")) ··· 465 422 test_uptr_basic(); 466 423 if (test__start_subtest("uptr_across_pages")) 467 424 test_uptr_across_pages(); 425 + if (test__start_subtest("uptr_update_failure")) 426 + test_uptr_update_failure(); 468 427 }
+42
tools/testing/selftests/bpf/progs/uptr_update_failure.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <vmlinux.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include "uptr_test_common.h" 7 + 8 + struct { 9 + __uint(type, BPF_MAP_TYPE_TASK_STORAGE); 10 + __uint(map_flags, BPF_F_NO_PREALLOC); 11 + __type(key, int); 12 + __type(value, struct value_lock_type); 13 + } datamap SEC(".maps"); 14 + 15 + /* load test only. not used */ 16 + SEC("syscall") 17 + int not_used(void *ctx) 18 + { 19 + struct value_lock_type *ptr; 20 + struct task_struct *task; 21 + struct user_data *udata; 22 + 23 + task = bpf_get_current_task_btf(); 24 + ptr = bpf_task_storage_get(&datamap, task, 0, 0); 25 + if (!ptr) 26 + return 0; 27 + 28 + bpf_spin_lock(&ptr->lock); 29 + 30 + udata = ptr->udata; 31 + if (!udata) { 32 + bpf_spin_unlock(&ptr->lock); 33 + return 0; 34 + } 35 + udata->result = MAGIC_VALUE + udata->a + udata->b; 36 + 37 + bpf_spin_unlock(&ptr->lock); 38 + 39 + return 0; 40 + } 41 + 42 + char _license[] SEC("license") = "GPL";
+5
tools/testing/selftests/bpf/uptr_test_common.h
··· 32 32 struct nested_udata nested; 33 33 }; 34 34 35 + struct value_lock_type { 36 + struct user_data __uptr *udata; 37 + struct bpf_spin_lock lock; 38 + }; 39 + 35 40 #endif