memfd_secret.c 6.9 KB

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