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 #include <fcntl.h> 24 25 #include "../kselftest.h" 26 27 #define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__) 28 #define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__) 29 #define skip(fmt, ...) ksft_test_result_skip(fmt, ##__VA_ARGS__) 30 31 #ifdef __NR_memfd_secret 32 33 #define PATTERN 0x55 34 35 static const int prot = PROT_READ | PROT_WRITE; 36 static const int mode = MAP_SHARED; 37 38 static unsigned long page_size; 39 static unsigned long mlock_limit_cur; 40 static unsigned long mlock_limit_max; 41 42 static int memfd_secret(unsigned int flags) 43 { 44 return syscall(__NR_memfd_secret, flags); 45 } 46 47 static void test_file_apis(int fd) 48 { 49 char buf[64]; 50 51 if ((read(fd, buf, sizeof(buf)) >= 0) || 52 (write(fd, buf, sizeof(buf)) >= 0) || 53 (pread(fd, buf, sizeof(buf), 0) >= 0) || 54 (pwrite(fd, buf, sizeof(buf), 0) >= 0)) 55 fail("unexpected file IO\n"); 56 else 57 pass("file IO is blocked as expected\n"); 58 } 59 60 static void test_mlock_limit(int fd) 61 { 62 size_t len; 63 char *mem; 64 65 len = mlock_limit_cur; 66 if (len % page_size != 0) 67 len = (len/page_size) * page_size; 68 69 mem = mmap(NULL, len, prot, mode, fd, 0); 70 if (mem == MAP_FAILED) { 71 fail("unable to mmap secret memory\n"); 72 return; 73 } 74 munmap(mem, len); 75 76 len = mlock_limit_max * 2; 77 mem = mmap(NULL, len, prot, mode, fd, 0); 78 if (mem != MAP_FAILED) { 79 fail("unexpected mlock limit violation\n"); 80 munmap(mem, len); 81 return; 82 } 83 84 pass("mlock limit is respected\n"); 85 } 86 87 static void test_vmsplice(int fd, const char *desc) 88 { 89 ssize_t transferred; 90 struct iovec iov; 91 int pipefd[2]; 92 char *mem; 93 94 if (pipe(pipefd)) { 95 fail("pipe failed: %s\n", strerror(errno)); 96 return; 97 } 98 99 mem = mmap(NULL, page_size, prot, mode, fd, 0); 100 if (mem == MAP_FAILED) { 101 fail("Unable to mmap secret memory\n"); 102 goto close_pipe; 103 } 104 105 /* 106 * vmsplice() may use GUP-fast, which must also fail. Prefault the 107 * page table, so GUP-fast could find it. 108 */ 109 memset(mem, PATTERN, page_size); 110 111 iov.iov_base = mem; 112 iov.iov_len = page_size; 113 transferred = vmsplice(pipefd[1], &iov, 1, 0); 114 115 if (transferred < 0 && errno == EFAULT) 116 pass("vmsplice is blocked as expected with %s\n", desc); 117 else 118 fail("vmsplice: unexpected memory access with %s\n", desc); 119 120 munmap(mem, page_size); 121 close_pipe: 122 close(pipefd[0]); 123 close(pipefd[1]); 124 } 125 126 static void try_process_vm_read(int fd, int pipefd[2]) 127 { 128 struct iovec liov, riov; 129 char buf[64]; 130 char *mem; 131 132 if (read(pipefd[0], &mem, sizeof(mem)) < 0) { 133 fail("pipe write: %s\n", strerror(errno)); 134 exit(KSFT_FAIL); 135 } 136 137 liov.iov_len = riov.iov_len = sizeof(buf); 138 liov.iov_base = buf; 139 riov.iov_base = mem; 140 141 if (process_vm_readv(getppid(), &liov, 1, &riov, 1, 0) < 0) { 142 if (errno == ENOSYS) 143 exit(KSFT_SKIP); 144 exit(KSFT_PASS); 145 } 146 147 exit(KSFT_FAIL); 148 } 149 150 static void try_ptrace(int fd, int pipefd[2]) 151 { 152 pid_t ppid = getppid(); 153 int status; 154 char *mem; 155 long ret; 156 157 if (read(pipefd[0], &mem, sizeof(mem)) < 0) { 158 perror("pipe write"); 159 exit(KSFT_FAIL); 160 } 161 162 ret = ptrace(PTRACE_ATTACH, ppid, 0, 0); 163 if (ret) { 164 perror("ptrace_attach"); 165 exit(KSFT_FAIL); 166 } 167 168 ret = waitpid(ppid, &status, WUNTRACED); 169 if ((ret != ppid) || !(WIFSTOPPED(status))) { 170 fprintf(stderr, "weird waitppid result %ld stat %x\n", 171 ret, status); 172 exit(KSFT_FAIL); 173 } 174 175 if (ptrace(PTRACE_PEEKDATA, ppid, mem, 0)) 176 exit(KSFT_PASS); 177 178 exit(KSFT_FAIL); 179 } 180 181 static void check_child_status(pid_t pid, const char *name) 182 { 183 int status; 184 185 waitpid(pid, &status, 0); 186 187 if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) { 188 skip("%s is not supported\n", name); 189 return; 190 } 191 192 if ((WIFEXITED(status) && WEXITSTATUS(status) == KSFT_PASS) || 193 WIFSIGNALED(status)) { 194 pass("%s is blocked as expected\n", name); 195 return; 196 } 197 198 fail("%s: unexpected memory access\n", name); 199 } 200 201 static void test_remote_access(int fd, const char *name, 202 void (*func)(int fd, int pipefd[2])) 203 { 204 int pipefd[2]; 205 pid_t pid; 206 char *mem; 207 208 if (pipe(pipefd)) { 209 fail("pipe failed: %s\n", strerror(errno)); 210 return; 211 } 212 213 pid = fork(); 214 if (pid < 0) { 215 fail("fork failed: %s\n", strerror(errno)); 216 return; 217 } 218 219 if (pid == 0) { 220 func(fd, pipefd); 221 return; 222 } 223 224 mem = mmap(NULL, page_size, prot, mode, fd, 0); 225 if (mem == MAP_FAILED) { 226 fail("Unable to mmap secret memory\n"); 227 return; 228 } 229 230 memset(mem, PATTERN, page_size); 231 232 if (write(pipefd[1], &mem, sizeof(mem)) < 0) { 233 fail("pipe write: %s\n", strerror(errno)); 234 return; 235 } 236 237 check_child_status(pid, name); 238 } 239 240 static void test_process_vm_read(int fd) 241 { 242 test_remote_access(fd, "process_vm_read", try_process_vm_read); 243 } 244 245 static void test_ptrace(int fd) 246 { 247 test_remote_access(fd, "ptrace", try_ptrace); 248 } 249 250 static int set_cap_limits(rlim_t max) 251 { 252 struct rlimit new; 253 cap_t cap = cap_init(); 254 255 new.rlim_cur = max; 256 new.rlim_max = max; 257 if (setrlimit(RLIMIT_MEMLOCK, &new)) { 258 perror("setrlimit() returns error"); 259 return -1; 260 } 261 262 /* drop capabilities including CAP_IPC_LOCK */ 263 if (cap_set_proc(cap)) { 264 perror("cap_set_proc() returns error"); 265 return -2; 266 } 267 268 return 0; 269 } 270 271 static void prepare(void) 272 { 273 struct rlimit rlim; 274 275 page_size = sysconf(_SC_PAGE_SIZE); 276 if (!page_size) 277 ksft_exit_fail_msg("Failed to get page size %s\n", 278 strerror(errno)); 279 280 if (getrlimit(RLIMIT_MEMLOCK, &rlim)) 281 ksft_exit_fail_msg("Unable to detect mlock limit: %s\n", 282 strerror(errno)); 283 284 mlock_limit_cur = rlim.rlim_cur; 285 mlock_limit_max = rlim.rlim_max; 286 287 printf("page_size: %ld, mlock.soft: %ld, mlock.hard: %ld\n", 288 page_size, mlock_limit_cur, mlock_limit_max); 289 290 if (page_size > mlock_limit_cur) 291 mlock_limit_cur = page_size; 292 if (page_size > mlock_limit_max) 293 mlock_limit_max = page_size; 294 295 if (set_cap_limits(mlock_limit_max)) 296 ksft_exit_fail_msg("Unable to set mlock limit: %s\n", 297 strerror(errno)); 298 } 299 300 #define NUM_TESTS 6 301 302 int main(int argc, char *argv[]) 303 { 304 int fd; 305 306 prepare(); 307 308 ksft_print_header(); 309 ksft_set_plan(NUM_TESTS); 310 311 fd = memfd_secret(0); 312 if (fd < 0) { 313 if (errno == ENOSYS) 314 ksft_exit_skip("memfd_secret is not supported\n"); 315 else 316 ksft_exit_fail_msg("memfd_secret failed: %s\n", 317 strerror(errno)); 318 } 319 if (ftruncate(fd, page_size)) 320 ksft_exit_fail_msg("ftruncate failed: %s\n", strerror(errno)); 321 322 test_mlock_limit(fd); 323 test_file_apis(fd); 324 /* 325 * We have to run the first vmsplice test before any secretmem page was 326 * allocated for this fd. 327 */ 328 test_vmsplice(fd, "fresh page"); 329 test_vmsplice(fd, "existing page"); 330 test_process_vm_read(fd); 331 test_ptrace(fd); 332 333 close(fd); 334 335 ksft_finished(); 336 } 337 338 #else /* __NR_memfd_secret */ 339 340 int main(int argc, char *argv[]) 341 { 342 printf("skip: skipping memfd_secret test (missing __NR_memfd_secret)\n"); 343 return KSFT_SKIP; 344 } 345 346 #endif /* __NR_memfd_secret */ 347