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