1// SPDX-License-Identifier: GPL-2.0 2 3/* 4 * Copyright (C) 2020 Google LLC. 5 */ 6 7#include <asm-generic/errno-base.h> 8#include <sys/stat.h> 9#include <test_progs.h> 10#include <linux/limits.h> 11 12#include "local_storage.skel.h" 13#include "network_helpers.h" 14#include "task_local_storage_helpers.h" 15 16#define TEST_STORAGE_VALUE 0xbeefdead 17 18struct storage { 19 void *inode; 20 unsigned int value; 21}; 22 23/* Fork and exec the provided rm binary and return the exit code of the 24 * forked process and its pid. 25 */ 26static int run_self_unlink(struct local_storage *skel, const char *rm_path) 27{ 28 int child_pid, child_status, ret; 29 int null_fd; 30 31 child_pid = fork(); 32 if (child_pid == 0) { 33 null_fd = open("/dev/null", O_WRONLY); 34 dup2(null_fd, STDOUT_FILENO); 35 dup2(null_fd, STDERR_FILENO); 36 close(null_fd); 37 38 skel->bss->monitored_pid = getpid(); 39 /* Use the copied /usr/bin/rm to delete itself 40 * /tmp/copy_of_rm /tmp/copy_of_rm. 41 */ 42 ret = execlp(rm_path, rm_path, rm_path, NULL); 43 if (ret) 44 exit(errno); 45 } else if (child_pid > 0) { 46 waitpid(child_pid, &child_status, 0); 47 ASSERT_EQ(skel->data->task_storage_result, 0, "task_storage_result"); 48 return WEXITSTATUS(child_status); 49 } 50 51 return -EINVAL; 52} 53 54static bool check_syscall_operations(int map_fd, int obj_fd) 55{ 56 struct storage val = { .value = TEST_STORAGE_VALUE }, 57 lookup_val = { .value = 0 }; 58 int err; 59 60 /* Looking up an existing element should fail initially */ 61 err = bpf_map_lookup_elem_flags(map_fd, &obj_fd, &lookup_val, 0); 62 if (!ASSERT_EQ(err, -ENOENT, "bpf_map_lookup_elem")) 63 return false; 64 65 /* Create a new element */ 66 err = bpf_map_update_elem(map_fd, &obj_fd, &val, BPF_NOEXIST); 67 if (!ASSERT_OK(err, "bpf_map_update_elem")) 68 return false; 69 70 /* Lookup the newly created element */ 71 err = bpf_map_lookup_elem_flags(map_fd, &obj_fd, &lookup_val, 0); 72 if (!ASSERT_OK(err, "bpf_map_lookup_elem")) 73 return false; 74 75 /* Check the value of the newly created element */ 76 if (!ASSERT_EQ(lookup_val.value, val.value, "bpf_map_lookup_elem")) 77 return false; 78 79 err = bpf_map_delete_elem(map_fd, &obj_fd); 80 if (!ASSERT_OK(err, "bpf_map_delete_elem()")) 81 return false; 82 83 /* The lookup should fail, now that the element has been deleted */ 84 err = bpf_map_lookup_elem_flags(map_fd, &obj_fd, &lookup_val, 0); 85 if (!ASSERT_EQ(err, -ENOENT, "bpf_map_lookup_elem")) 86 return false; 87 88 return true; 89} 90 91void test_test_local_storage(void) 92{ 93 char tmp_dir_path[] = "/tmp/local_storageXXXXXX"; 94 int err, serv_sk = -1, task_fd = -1, rm_fd = -1; 95 struct local_storage *skel = NULL; 96 char tmp_exec_path[64]; 97 char cmd[256]; 98 99 skel = local_storage__open_and_load(); 100 if (!ASSERT_OK_PTR(skel, "skel_load")) 101 goto close_prog; 102 103 err = local_storage__attach(skel); 104 if (!ASSERT_OK(err, "attach")) 105 goto close_prog; 106 107 task_fd = sys_pidfd_open(getpid(), 0); 108 if (!ASSERT_GE(task_fd, 0, "pidfd_open")) 109 goto close_prog; 110 111 if (!check_syscall_operations(bpf_map__fd(skel->maps.task_storage_map), 112 task_fd)) 113 goto close_prog; 114 115 if (!ASSERT_OK_PTR(mkdtemp(tmp_dir_path), "mkdtemp")) 116 goto close_prog; 117 118 snprintf(tmp_exec_path, sizeof(tmp_exec_path), "%s/copy_of_rm", 119 tmp_dir_path); 120 snprintf(cmd, sizeof(cmd), "cp /bin/rm %s", tmp_exec_path); 121 if (!ASSERT_OK(system(cmd), "system(cp)")) 122 goto close_prog_rmdir; 123 124 rm_fd = open(tmp_exec_path, O_RDONLY); 125 if (!ASSERT_GE(rm_fd, 0, "open(tmp_exec_path)")) 126 goto close_prog_rmdir; 127 128 if (!check_syscall_operations(bpf_map__fd(skel->maps.inode_storage_map), 129 rm_fd)) 130 goto close_prog_rmdir; 131 132 /* Sets skel->bss->monitored_pid to the pid of the forked child 133 * forks a child process that executes tmp_exec_path and tries to 134 * unlink its executable. This operation should be denied by the loaded 135 * LSM program. 136 */ 137 err = run_self_unlink(skel, tmp_exec_path); 138 if (!ASSERT_EQ(err, EPERM, "run_self_unlink")) 139 goto close_prog_rmdir; 140 141 /* Set the process being monitored to be the current process */ 142 skel->bss->monitored_pid = getpid(); 143 144 /* Move copy_of_rm to a new location so that it triggers the 145 * inode_rename LSM hook with a new_dentry that has a NULL inode ptr. 146 */ 147 snprintf(cmd, sizeof(cmd), "mv %s/copy_of_rm %s/check_null_ptr", 148 tmp_dir_path, tmp_dir_path); 149 if (!ASSERT_OK(system(cmd), "system(mv)")) 150 goto close_prog_rmdir; 151 152 ASSERT_EQ(skel->data->inode_storage_result, 0, "inode_storage_result"); 153 154 serv_sk = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0); 155 if (!ASSERT_GE(serv_sk, 0, "start_server")) 156 goto close_prog_rmdir; 157 158 ASSERT_EQ(skel->data->sk_storage_result, 0, "sk_storage_result"); 159 160 if (!check_syscall_operations(bpf_map__fd(skel->maps.sk_storage_map), 161 serv_sk)) 162 goto close_prog_rmdir; 163 164close_prog_rmdir: 165 snprintf(cmd, sizeof(cmd), "rm -rf %s", tmp_dir_path); 166 system(cmd); 167close_prog: 168 close(serv_sk); 169 close(rm_fd); 170 close(task_fd); 171 local_storage__destroy(skel); 172} 173