memfd_secret.c 5.8 KB

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