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 if (ptrace(PTRACE_PEEKDATA, ppid, mem, 0)) 149 exit(KSFT_PASS); 150 151 exit(KSFT_FAIL); 152 } 153 154 static void check_child_status(pid_t pid, const char *name) 155 { 156 int status; 157 158 waitpid(pid, &status, 0); 159 160 if (WIFEXITED(status) && WEXITSTATUS(status) == KSFT_SKIP) { 161 skip("%s is not supported\n", name); 162 return; 163 } 164 165 if ((WIFEXITED(status) && WEXITSTATUS(status) == KSFT_PASS) || 166 WIFSIGNALED(status)) { 167 pass("%s is blocked as expected\n", name); 168 return; 169 } 170 171 fail("%s: unexpected memory access\n", name); 172 } 173 174 static void test_remote_access(int fd, const char *name, 175 void (*func)(int fd, int pipefd[2])) 176 { 177 int pipefd[2]; 178 pid_t pid; 179 char *mem; 180 181 if (pipe(pipefd)) { 182 fail("pipe failed: %s\n", strerror(errno)); 183 return; 184 } 185 186 pid = fork(); 187 if (pid < 0) { 188 fail("fork failed: %s\n", strerror(errno)); 189 return; 190 } 191 192 if (pid == 0) { 193 func(fd, pipefd); 194 return; 195 } 196 197 mem = mmap(NULL, page_size, prot, mode, fd, 0); 198 if (mem == MAP_FAILED) { 199 fail("Unable to mmap secret memory\n"); 200 return; 201 } 202 203 memset(mem, PATTERN, page_size); 204 205 if (write(pipefd[1], &mem, sizeof(mem)) < 0) { 206 fail("pipe write: %s\n", strerror(errno)); 207 return; 208 } 209 210 check_child_status(pid, name); 211 } 212 213 static void test_process_vm_read(int fd) 214 { 215 test_remote_access(fd, "process_vm_read", try_process_vm_read); 216 } 217 218 static void test_ptrace(int fd) 219 { 220 test_remote_access(fd, "ptrace", try_ptrace); 221 } 222 223 static int set_cap_limits(rlim_t max) 224 { 225 struct rlimit new; 226 cap_t cap = cap_init(); 227 228 new.rlim_cur = max; 229 new.rlim_max = max; 230 if (setrlimit(RLIMIT_MEMLOCK, &new)) { 231 perror("setrlimit() returns error"); 232 return -1; 233 } 234 235 /* drop capabilities including CAP_IPC_LOCK */ 236 if (cap_set_proc(cap)) { 237 perror("cap_set_proc() returns error"); 238 return -2; 239 } 240 241 return 0; 242 } 243 244 static void prepare(void) 245 { 246 struct rlimit rlim; 247 248 page_size = sysconf(_SC_PAGE_SIZE); 249 if (!page_size) 250 ksft_exit_fail_msg("Failed to get page size %s\n", 251 strerror(errno)); 252 253 if (getrlimit(RLIMIT_MEMLOCK, &rlim)) 254 ksft_exit_fail_msg("Unable to detect mlock limit: %s\n", 255 strerror(errno)); 256 257 mlock_limit_cur = rlim.rlim_cur; 258 mlock_limit_max = rlim.rlim_max; 259 260 printf("page_size: %ld, mlock.soft: %ld, mlock.hard: %ld\n", 261 page_size, mlock_limit_cur, mlock_limit_max); 262 263 if (page_size > mlock_limit_cur) 264 mlock_limit_cur = page_size; 265 if (page_size > mlock_limit_max) 266 mlock_limit_max = page_size; 267 268 if (set_cap_limits(mlock_limit_max)) 269 ksft_exit_fail_msg("Unable to set mlock limit: %s\n", 270 strerror(errno)); 271 } 272 273 #define NUM_TESTS 5 274 275 int main(int argc, char *argv[]) 276 { 277 int fd; 278 279 prepare(); 280 281 ksft_print_header(); 282 ksft_set_plan(NUM_TESTS); 283 284 fd = memfd_secret(0); 285 if (fd < 0) { 286 if (errno == ENOSYS) 287 ksft_exit_skip("memfd_secret is not supported\n"); 288 else 289 ksft_exit_fail_msg("memfd_secret failed: %s\n", 290 strerror(errno)); 291 } 292 if (ftruncate(fd, page_size)) 293 ksft_exit_fail_msg("ftruncate failed: %s\n", strerror(errno)); 294 295 test_file_apis(fd); 296 /* 297 * We have to run the first vmsplice test before any secretmem page was 298 * allocated for this fd. 299 */ 300 test_vmsplice(fd, "fresh page"); 301 test_vmsplice(fd, "existing page"); 302 test_process_vm_read(fd); 303 test_ptrace(fd); 304 305 close(fd); 306 307 ksft_finished(); 308 } 309 310 #else /* __NR_memfd_secret */ 311 312 int main(int argc, char *argv[]) 313 { 314 printf("skip: skipping memfd_secret test (missing __NR_memfd_secret)\n"); 315 return KSFT_SKIP; 316 } 317 318 #endif /* __NR_memfd_secret */ 319