1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright IBM Corporation, 2021 4 * 5 * Author: Mike Rapoport <rppt@linux.ibm.com> 6 */ 7 8 #define _GNU_SOURCE 9 #include <sys/uio.h> 10 #include <sys/mman.h> 11 #include <sys/wait.h> 12 #include <sys/types.h> 13 #include <sys/ptrace.h> 14 #include <sys/syscall.h> 15 #include <sys/resource.h> 16 #include <sys/capability.h> 17 18 #include <stdlib.h> 19 #include <string.h> 20 #include <unistd.h> 21 #include <errno.h> 22 #include <stdio.h> 23 24 #include "../kselftest.h" 25 26 #define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__) 27 #define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__) 28 #define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__) 29 30 #ifdef __NR_memfd_secret 31 32 #define PATTERN 0x55 33 34 static const int prot = PROT_READ | PROT_WRITE; 35 static const int mode = MAP_SHARED; 36 37 static unsigned long page_size; 38 static unsigned long mlock_limit_cur; 39 static unsigned long mlock_limit_max; 40 41 static int memfd_secret(unsigned int flags) 42 { 43 return syscall(__NR_memfd_secret, flags); 44 } 45 46 static void test_file_apis(int fd) 47 { 48 char buf[64]; 49 50 if ((read(fd, buf, sizeof(buf)) >= 0) || 51 (write(fd, buf, sizeof(buf)) >= 0) || 52 (pread(fd, buf, sizeof(buf), 0) >= 0) || 53 (pwrite(fd, buf, sizeof(buf), 0) >= 0)) 54 fail("unexpected file IO\n"); 55 else 56 pass("file IO is blocked as expected\n"); 57 } 58 59 static void test_mlock_limit(int fd) 60 { 61 size_t len; 62 char *mem; 63 64 len = mlock_limit_cur; 65 if (len % page_size != 0) 66 len = (len/page_size) * page_size; 67 68 mem = mmap(NULL, len, prot, mode, fd, 0); 69 if (mem == MAP_FAILED) { 70 fail("unable to mmap secret memory\n"); 71 return; 72 } 73 munmap(mem, len); 74 75 len = mlock_limit_max * 2; 76 mem = mmap(NULL, len, prot, mode, fd, 0); 77 if (mem != MAP_FAILED) { 78 fail("unexpected mlock limit violation\n"); 79 munmap(mem, len); 80 return; 81 } 82 83 pass("mlock limit is respected\n"); 84 } 85 86 static void try_process_vm_read(int fd, int pipefd[2]) 87 { 88 struct iovec liov, riov; 89 char buf[64]; 90 char *mem; 91 92 if (read(pipefd[0], &mem, sizeof(mem)) < 0) { 93 fail("pipe write: %s\n", strerror(errno)); 94 exit(KSFT_FAIL); 95 } 96 97 liov.iov_len = riov.iov_len = sizeof(buf); 98 liov.iov_base = buf; 99 riov.iov_base = mem; 100 101 if (process_vm_readv(getppid(), &liov, 1, &riov, 1, 0) < 0) { 102 if (errno == ENOSYS) 103 exit(KSFT_SKIP); 104 exit(KSFT_PASS); 105 } 106 107 exit(KSFT_FAIL); 108 } 109 110 static void try_ptrace(int fd, int pipefd[2]) 111 { 112 pid_t ppid = getppid(); 113 int status; 114 char *mem; 115 long ret; 116 117 if (read(pipefd[0], &mem, sizeof(mem)) < 0) { 118 perror("pipe write"); 119 exit(KSFT_FAIL); 120 } 121 122 ret = ptrace(PTRACE_ATTACH, ppid, 0, 0); 123 if (ret) { 124 perror("ptrace_attach"); 125 exit(KSFT_FAIL); 126 } 127 128 ret = waitpid(ppid, &status, WUNTRACED); 129 if ((ret != ppid) || !(WIFSTOPPED(status))) { 130 fprintf(stderr, "weird waitppid result %ld stat %x\n", 131 ret, status); 132 exit(KSFT_FAIL); 133 } 134 135 if (ptrace(PTRACE_PEEKDATA, ppid, mem, 0)) 136 exit(KSFT_PASS); 137 138 exit(KSFT_FAIL); 139 } 140 141 static void check_child_status(pid_t pid, const char *name) 142 { 143 int status; 144 145 waitpid(pid, &status, 0); 146 147 if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) { 148 skip("%s is not supported\n", name); 149 return; 150 } 151 152 if ((WIFEXITED(status) && WEXITSTATUS(status) == KSFT_PASS) || 153 WIFSIGNALED(status)) { 154 pass("%s is blocked as expected\n", name); 155 return; 156 } 157 158 fail("%s: unexpected memory access\n", name); 159 } 160 161 static void test_remote_access(int fd, const char *name, 162 void (*func)(int fd, int pipefd[2])) 163 { 164 int pipefd[2]; 165 pid_t pid; 166 char *mem; 167 168 if (pipe(pipefd)) { 169 fail("pipe failed: %s\n", strerror(errno)); 170 return; 171 } 172 173 pid = fork(); 174 if (pid < 0) { 175 fail("fork failed: %s\n", strerror(errno)); 176 return; 177 } 178 179 if (pid == 0) { 180 func(fd, pipefd); 181 return; 182 } 183 184 mem = mmap(NULL, page_size, prot, mode, fd, 0); 185 if (mem == MAP_FAILED) { 186 fail("Unable to mmap secret memory\n"); 187 return; 188 } 189 190 ftruncate(fd, page_size); 191 memset(mem, PATTERN, page_size); 192 193 if (write(pipefd[1], &mem, sizeof(mem)) < 0) { 194 fail("pipe write: %s\n", strerror(errno)); 195 return; 196 } 197 198 check_child_status(pid, name); 199 } 200 201 static void test_process_vm_read(int fd) 202 { 203 test_remote_access(fd, "process_vm_read", try_process_vm_read); 204 } 205 206 static void test_ptrace(int fd) 207 { 208 test_remote_access(fd, "ptrace", try_ptrace); 209 } 210 211 static int set_cap_limits(rlim_t max) 212 { 213 struct rlimit new; 214 cap_t cap = cap_init(); 215 216 new.rlim_cur = max; 217 new.rlim_max = max; 218 if (setrlimit(RLIMIT_MEMLOCK, &new)) { 219 perror("setrlimit() returns error"); 220 return -1; 221 } 222 223 /* drop capabilities including CAP_IPC_LOCK */ 224 if (cap_set_proc(cap)) { 225 perror("cap_set_proc() returns error"); 226 return -2; 227 } 228 229 return 0; 230 } 231 232 static void prepare(void) 233 { 234 struct rlimit rlim; 235 236 page_size = sysconf(_SC_PAGE_SIZE); 237 if (!page_size) 238 ksft_exit_fail_msg("Failed to get page size %s\n", 239 strerror(errno)); 240 241 if (getrlimit(RLIMIT_MEMLOCK, &rlim)) 242 ksft_exit_fail_msg("Unable to detect mlock limit: %s\n", 243 strerror(errno)); 244 245 mlock_limit_cur = rlim.rlim_cur; 246 mlock_limit_max = rlim.rlim_max; 247 248 printf("page_size: %ld, mlock.soft: %ld, mlock.hard: %ld\n", 249 page_size, mlock_limit_cur, mlock_limit_max); 250 251 if (page_size > mlock_limit_cur) 252 mlock_limit_cur = page_size; 253 if (page_size > mlock_limit_max) 254 mlock_limit_max = page_size; 255 256 if (set_cap_limits(mlock_limit_max)) 257 ksft_exit_fail_msg("Unable to set mlock limit: %s\n", 258 strerror(errno)); 259 } 260 261 #define NUM_TESTS 4 262 263 int main(int argc, char *argv[]) 264 { 265 int fd; 266 267 prepare(); 268 269 ksft_print_header(); 270 ksft_set_plan(NUM_TESTS); 271 272 fd = memfd_secret(0); 273 if (fd < 0) { 274 if (errno == ENOSYS) 275 ksft_exit_skip("memfd_secret is not supported\n"); 276 else 277 ksft_exit_fail_msg("memfd_secret failed: %s\n", 278 strerror(errno)); 279 } 280 281 test_mlock_limit(fd); 282 test_file_apis(fd); 283 test_process_vm_read(fd); 284 test_ptrace(fd); 285 286 close(fd); 287 288 ksft_finished(); 289 } 290 291 #else /* __NR_memfd_secret */ 292 293 int main(int argc, char *argv[]) 294 { 295 printf("skip: skipping memfd_secret test (missing __NR_memfd_secret)\n"); 296 return KSFT_SKIP; 297 } 298 299 #endif /* __NR_memfd_secret */ 300