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

selftests/bpf: Test task storage when local_storage->smap is NULL

The current sk storage test ensures the memory free works when
the local_storage->smap is NULL.

This patch adds a task storage test to ensure the memory free
code path works when local_storage->smap is NULL.

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

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
d8db84d7 6ae9d5e9

+46 -17
+4 -3
tools/testing/selftests/bpf/prog_tests/test_local_storage.c
··· 23 23 /* Fork and exec the provided rm binary and return the exit code of the 24 24 * forked process and its pid. 25 25 */ 26 - static int run_self_unlink(int *monitored_pid, const char *rm_path) 26 + static int run_self_unlink(struct local_storage *skel, const char *rm_path) 27 27 { 28 28 int child_pid, child_status, ret; 29 29 int null_fd; ··· 35 35 dup2(null_fd, STDERR_FILENO); 36 36 close(null_fd); 37 37 38 - *monitored_pid = getpid(); 38 + skel->bss->monitored_pid = getpid(); 39 39 /* Use the copied /usr/bin/rm to delete itself 40 40 * /tmp/copy_of_rm /tmp/copy_of_rm. 41 41 */ ··· 44 44 exit(errno); 45 45 } else if (child_pid > 0) { 46 46 waitpid(child_pid, &child_status, 0); 47 + ASSERT_EQ(skel->data->task_storage_result, 0, "task_storage_result"); 47 48 return WEXITSTATUS(child_status); 48 49 } 49 50 ··· 134 133 * unlink its executable. This operation should be denied by the loaded 135 134 * LSM program. 136 135 */ 137 - err = run_self_unlink(&skel->bss->monitored_pid, tmp_exec_path); 136 + err = run_self_unlink(skel, tmp_exec_path); 138 137 if (!ASSERT_EQ(err, EPERM, "run_self_unlink")) 139 138 goto close_prog_rmdir; 140 139
+42 -14
tools/testing/selftests/bpf/progs/local_storage.c
··· 16 16 int monitored_pid = 0; 17 17 int inode_storage_result = -1; 18 18 int sk_storage_result = -1; 19 + int task_storage_result = -1; 19 20 20 21 struct local_storage { 21 22 struct inode *exec_inode; ··· 51 50 __type(value, struct local_storage); 52 51 } task_storage_map SEC(".maps"); 53 52 53 + struct { 54 + __uint(type, BPF_MAP_TYPE_TASK_STORAGE); 55 + __uint(map_flags, BPF_F_NO_PREALLOC); 56 + __type(key, int); 57 + __type(value, struct local_storage); 58 + } task_storage_map2 SEC(".maps"); 59 + 54 60 SEC("lsm/inode_unlink") 55 61 int BPF_PROG(unlink_hook, struct inode *dir, struct dentry *victim) 56 62 { 57 63 __u32 pid = bpf_get_current_pid_tgid() >> 32; 64 + struct bpf_local_storage *local_storage; 58 65 struct local_storage *storage; 66 + struct task_struct *task; 59 67 bool is_self_unlink; 60 68 61 69 if (pid != monitored_pid) 62 70 return 0; 63 71 64 - storage = bpf_task_storage_get(&task_storage_map, 65 - bpf_get_current_task_btf(), 0, 0); 66 - if (storage) { 67 - /* Don't let an executable delete itself */ 68 - is_self_unlink = storage->exec_inode == victim->d_inode; 69 - if (is_self_unlink) 70 - return -EPERM; 71 - } 72 + task = bpf_get_current_task_btf(); 73 + if (!task) 74 + return 0; 72 75 73 - return 0; 76 + task_storage_result = -1; 77 + 78 + storage = bpf_task_storage_get(&task_storage_map, task, 0, 0); 79 + if (!storage) 80 + return 0; 81 + 82 + /* Don't let an executable delete itself */ 83 + is_self_unlink = storage->exec_inode == victim->d_inode; 84 + 85 + storage = bpf_task_storage_get(&task_storage_map2, task, 0, 86 + BPF_LOCAL_STORAGE_GET_F_CREATE); 87 + if (!storage || storage->value) 88 + return 0; 89 + 90 + if (bpf_task_storage_delete(&task_storage_map, task)) 91 + return 0; 92 + 93 + /* Ensure that the task_storage_map is disconnected from the storage. 94 + * The storage memory should not be freed back to the 95 + * bpf_mem_alloc. 96 + */ 97 + local_storage = task->bpf_storage; 98 + if (!local_storage || local_storage->smap) 99 + return 0; 100 + 101 + task_storage_result = 0; 102 + 103 + return is_self_unlink ? -EPERM : 0; 74 104 } 75 105 76 106 SEC("lsm.s/inode_rename") ··· 171 139 if (bpf_sk_storage_delete(&sk_storage_map, sock->sk)) 172 140 return 0; 173 141 174 - /* Ensure that the sk_storage_map is disconnected from the storage. 175 - * The storage memory should not be freed back to the 176 - * bpf_mem_alloc of the sk_bpf_storage_map because 177 - * sk_bpf_storage_map may have been gone. 178 - */ 142 + /* Ensure that the sk_storage_map is disconnected from the storage. */ 179 143 if (!sock->sk->sk_bpf_storage || sock->sk->sk_bpf_storage->smap) 180 144 return 0; 181 145