memfd_test.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080
  1. // SPDX-License-Identifier: GPL-2.0
  2. #define _GNU_SOURCE
  3. #define __EXPORTED_HEADERS__
  4. #include <errno.h>
  5. #include <inttypes.h>
  6. #include <limits.h>
  7. #include <linux/falloc.h>
  8. #include <fcntl.h>
  9. #include <linux/memfd.h>
  10. #include <sched.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <signal.h>
  14. #include <string.h>
  15. #include <sys/mman.h>
  16. #include <sys/stat.h>
  17. #include <sys/syscall.h>
  18. #include <sys/wait.h>
  19. #include <unistd.h>
  20. #include "common.h"
  21. #define MEMFD_STR "memfd:"
  22. #define MEMFD_HUGE_STR "memfd-hugetlb:"
  23. #define SHARED_FT_STR "(shared file-table)"
  24. #define MFD_DEF_SIZE 8192
  25. #define STACK_SIZE 65536
  26. /*
  27. * Default is not to test hugetlbfs
  28. */
  29. static size_t mfd_def_size = MFD_DEF_SIZE;
  30. static const char *memfd_str = MEMFD_STR;
  31. static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags)
  32. {
  33. int r, fd;
  34. fd = sys_memfd_create(name, flags);
  35. if (fd < 0) {
  36. printf("memfd_create(\"%s\", %u) failed: %m\n",
  37. name, flags);
  38. abort();
  39. }
  40. r = ftruncate(fd, sz);
  41. if (r < 0) {
  42. printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz);
  43. abort();
  44. }
  45. return fd;
  46. }
  47. static int mfd_assert_reopen_fd(int fd_in)
  48. {
  49. int fd;
  50. char path[100];
  51. sprintf(path, "/proc/self/fd/%d", fd_in);
  52. fd = open(path, O_RDWR);
  53. if (fd < 0) {
  54. printf("re-open of existing fd %d failed\n", fd_in);
  55. abort();
  56. }
  57. return fd;
  58. }
  59. static void mfd_fail_new(const char *name, unsigned int flags)
  60. {
  61. int r;
  62. r = sys_memfd_create(name, flags);
  63. if (r >= 0) {
  64. printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n",
  65. name, flags);
  66. close(r);
  67. abort();
  68. }
  69. }
  70. static unsigned int mfd_assert_get_seals(int fd)
  71. {
  72. int r;
  73. r = fcntl(fd, F_GET_SEALS);
  74. if (r < 0) {
  75. printf("GET_SEALS(%d) failed: %m\n", fd);
  76. abort();
  77. }
  78. return (unsigned int)r;
  79. }
  80. static void mfd_assert_has_seals(int fd, unsigned int seals)
  81. {
  82. unsigned int s;
  83. s = mfd_assert_get_seals(fd);
  84. if (s != seals) {
  85. printf("%u != %u = GET_SEALS(%d)\n", seals, s, fd);
  86. abort();
  87. }
  88. }
  89. static void mfd_assert_add_seals(int fd, unsigned int seals)
  90. {
  91. int r;
  92. unsigned int s;
  93. s = mfd_assert_get_seals(fd);
  94. r = fcntl(fd, F_ADD_SEALS, seals);
  95. if (r < 0) {
  96. printf("ADD_SEALS(%d, %u -> %u) failed: %m\n", fd, s, seals);
  97. abort();
  98. }
  99. }
  100. static void mfd_fail_add_seals(int fd, unsigned int seals)
  101. {
  102. int r;
  103. unsigned int s;
  104. r = fcntl(fd, F_GET_SEALS);
  105. if (r < 0)
  106. s = 0;
  107. else
  108. s = (unsigned int)r;
  109. r = fcntl(fd, F_ADD_SEALS, seals);
  110. if (r >= 0) {
  111. printf("ADD_SEALS(%d, %u -> %u) didn't fail as expected\n",
  112. fd, s, seals);
  113. abort();
  114. }
  115. }
  116. static void mfd_assert_size(int fd, size_t size)
  117. {
  118. struct stat st;
  119. int r;
  120. r = fstat(fd, &st);
  121. if (r < 0) {
  122. printf("fstat(%d) failed: %m\n", fd);
  123. abort();
  124. } else if (st.st_size != size) {
  125. printf("wrong file size %lld, but expected %lld\n",
  126. (long long)st.st_size, (long long)size);
  127. abort();
  128. }
  129. }
  130. static int mfd_assert_dup(int fd)
  131. {
  132. int r;
  133. r = dup(fd);
  134. if (r < 0) {
  135. printf("dup(%d) failed: %m\n", fd);
  136. abort();
  137. }
  138. return r;
  139. }
  140. static void *mfd_assert_mmap_shared(int fd)
  141. {
  142. void *p;
  143. p = mmap(NULL,
  144. mfd_def_size,
  145. PROT_READ | PROT_WRITE,
  146. MAP_SHARED,
  147. fd,
  148. 0);
  149. if (p == MAP_FAILED) {
  150. printf("mmap() failed: %m\n");
  151. abort();
  152. }
  153. return p;
  154. }
  155. static void *mfd_assert_mmap_private(int fd)
  156. {
  157. void *p;
  158. p = mmap(NULL,
  159. mfd_def_size,
  160. PROT_READ,
  161. MAP_PRIVATE,
  162. fd,
  163. 0);
  164. if (p == MAP_FAILED) {
  165. printf("mmap() failed: %m\n");
  166. abort();
  167. }
  168. return p;
  169. }
  170. static int mfd_assert_open(int fd, int flags, mode_t mode)
  171. {
  172. char buf[512];
  173. int r;
  174. sprintf(buf, "/proc/self/fd/%d", fd);
  175. r = open(buf, flags, mode);
  176. if (r < 0) {
  177. printf("open(%s) failed: %m\n", buf);
  178. abort();
  179. }
  180. return r;
  181. }
  182. static void mfd_fail_open(int fd, int flags, mode_t mode)
  183. {
  184. char buf[512];
  185. int r;
  186. sprintf(buf, "/proc/self/fd/%d", fd);
  187. r = open(buf, flags, mode);
  188. if (r >= 0) {
  189. printf("open(%s) didn't fail as expected\n", buf);
  190. abort();
  191. }
  192. }
  193. static void mfd_assert_read(int fd)
  194. {
  195. char buf[16];
  196. void *p;
  197. ssize_t l;
  198. l = read(fd, buf, sizeof(buf));
  199. if (l != sizeof(buf)) {
  200. printf("read() failed: %m\n");
  201. abort();
  202. }
  203. /* verify PROT_READ *is* allowed */
  204. p = mmap(NULL,
  205. mfd_def_size,
  206. PROT_READ,
  207. MAP_PRIVATE,
  208. fd,
  209. 0);
  210. if (p == MAP_FAILED) {
  211. printf("mmap() failed: %m\n");
  212. abort();
  213. }
  214. munmap(p, mfd_def_size);
  215. /* verify MAP_PRIVATE is *always* allowed (even writable) */
  216. p = mmap(NULL,
  217. mfd_def_size,
  218. PROT_READ | PROT_WRITE,
  219. MAP_PRIVATE,
  220. fd,
  221. 0);
  222. if (p == MAP_FAILED) {
  223. printf("mmap() failed: %m\n");
  224. abort();
  225. }
  226. munmap(p, mfd_def_size);
  227. }
  228. /* Test that PROT_READ + MAP_SHARED mappings work. */
  229. static void mfd_assert_read_shared(int fd)
  230. {
  231. void *p;
  232. /* verify PROT_READ and MAP_SHARED *is* allowed */
  233. p = mmap(NULL,
  234. mfd_def_size,
  235. PROT_READ,
  236. MAP_SHARED,
  237. fd,
  238. 0);
  239. if (p == MAP_FAILED) {
  240. printf("mmap() failed: %m\n");
  241. abort();
  242. }
  243. munmap(p, mfd_def_size);
  244. }
  245. static void mfd_assert_fork_private_write(int fd)
  246. {
  247. int *p;
  248. pid_t pid;
  249. p = mmap(NULL,
  250. mfd_def_size,
  251. PROT_READ | PROT_WRITE,
  252. MAP_PRIVATE,
  253. fd,
  254. 0);
  255. if (p == MAP_FAILED) {
  256. printf("mmap() failed: %m\n");
  257. abort();
  258. }
  259. p[0] = 22;
  260. pid = fork();
  261. if (pid == 0) {
  262. p[0] = 33;
  263. exit(0);
  264. } else {
  265. waitpid(pid, NULL, 0);
  266. if (p[0] != 22) {
  267. printf("MAP_PRIVATE copy-on-write failed: %m\n");
  268. abort();
  269. }
  270. }
  271. munmap(p, mfd_def_size);
  272. }
  273. static void mfd_assert_write(int fd)
  274. {
  275. ssize_t l;
  276. void *p;
  277. int r;
  278. /*
  279. * huegtlbfs does not support write, but we want to
  280. * verify everything else here.
  281. */
  282. if (!hugetlbfs_test) {
  283. /* verify write() succeeds */
  284. l = write(fd, "\0\0\0\0", 4);
  285. if (l != 4) {
  286. printf("write() failed: %m\n");
  287. abort();
  288. }
  289. }
  290. /* verify PROT_READ | PROT_WRITE is allowed */
  291. p = mmap(NULL,
  292. mfd_def_size,
  293. PROT_READ | PROT_WRITE,
  294. MAP_SHARED,
  295. fd,
  296. 0);
  297. if (p == MAP_FAILED) {
  298. printf("mmap() failed: %m\n");
  299. abort();
  300. }
  301. *(char *)p = 0;
  302. munmap(p, mfd_def_size);
  303. /* verify PROT_WRITE is allowed */
  304. p = mmap(NULL,
  305. mfd_def_size,
  306. PROT_WRITE,
  307. MAP_SHARED,
  308. fd,
  309. 0);
  310. if (p == MAP_FAILED) {
  311. printf("mmap() failed: %m\n");
  312. abort();
  313. }
  314. *(char *)p = 0;
  315. munmap(p, mfd_def_size);
  316. /* verify PROT_READ with MAP_SHARED is allowed and a following
  317. * mprotect(PROT_WRITE) allows writing */
  318. p = mmap(NULL,
  319. mfd_def_size,
  320. PROT_READ,
  321. MAP_SHARED,
  322. fd,
  323. 0);
  324. if (p == MAP_FAILED) {
  325. printf("mmap() failed: %m\n");
  326. abort();
  327. }
  328. r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
  329. if (r < 0) {
  330. printf("mprotect() failed: %m\n");
  331. abort();
  332. }
  333. *(char *)p = 0;
  334. munmap(p, mfd_def_size);
  335. /* verify PUNCH_HOLE works */
  336. r = fallocate(fd,
  337. FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
  338. 0,
  339. mfd_def_size);
  340. if (r < 0) {
  341. printf("fallocate(PUNCH_HOLE) failed: %m\n");
  342. abort();
  343. }
  344. }
  345. static void mfd_fail_write(int fd)
  346. {
  347. ssize_t l;
  348. void *p;
  349. int r;
  350. /* verify write() fails */
  351. l = write(fd, "data", 4);
  352. if (l != -EPERM) {
  353. printf("expected EPERM on write(), but got %d: %m\n", (int)l);
  354. abort();
  355. }
  356. /* verify PROT_READ | PROT_WRITE is not allowed */
  357. p = mmap(NULL,
  358. mfd_def_size,
  359. PROT_READ | PROT_WRITE,
  360. MAP_SHARED,
  361. fd,
  362. 0);
  363. if (p != MAP_FAILED) {
  364. printf("mmap() didn't fail as expected\n");
  365. abort();
  366. }
  367. /* verify PROT_WRITE is not allowed */
  368. p = mmap(NULL,
  369. mfd_def_size,
  370. PROT_WRITE,
  371. MAP_SHARED,
  372. fd,
  373. 0);
  374. if (p != MAP_FAILED) {
  375. printf("mmap() didn't fail as expected\n");
  376. abort();
  377. }
  378. /* Verify PROT_READ with MAP_SHARED with a following mprotect is not
  379. * allowed. Note that for r/w the kernel already prevents the mmap. */
  380. p = mmap(NULL,
  381. mfd_def_size,
  382. PROT_READ,
  383. MAP_SHARED,
  384. fd,
  385. 0);
  386. if (p != MAP_FAILED) {
  387. r = mprotect(p, mfd_def_size, PROT_READ | PROT_WRITE);
  388. if (r >= 0) {
  389. printf("mmap()+mprotect() didn't fail as expected\n");
  390. abort();
  391. }
  392. munmap(p, mfd_def_size);
  393. }
  394. /* verify PUNCH_HOLE fails */
  395. r = fallocate(fd,
  396. FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
  397. 0,
  398. mfd_def_size);
  399. if (r >= 0) {
  400. printf("fallocate(PUNCH_HOLE) didn't fail as expected\n");
  401. abort();
  402. }
  403. }
  404. static void mfd_assert_shrink(int fd)
  405. {
  406. int r, fd2;
  407. r = ftruncate(fd, mfd_def_size / 2);
  408. if (r < 0) {
  409. printf("ftruncate(SHRINK) failed: %m\n");
  410. abort();
  411. }
  412. mfd_assert_size(fd, mfd_def_size / 2);
  413. fd2 = mfd_assert_open(fd,
  414. O_RDWR | O_CREAT | O_TRUNC,
  415. S_IRUSR | S_IWUSR);
  416. close(fd2);
  417. mfd_assert_size(fd, 0);
  418. }
  419. static void mfd_fail_shrink(int fd)
  420. {
  421. int r;
  422. r = ftruncate(fd, mfd_def_size / 2);
  423. if (r >= 0) {
  424. printf("ftruncate(SHRINK) didn't fail as expected\n");
  425. abort();
  426. }
  427. mfd_fail_open(fd,
  428. O_RDWR | O_CREAT | O_TRUNC,
  429. S_IRUSR | S_IWUSR);
  430. }
  431. static void mfd_assert_grow(int fd)
  432. {
  433. int r;
  434. r = ftruncate(fd, mfd_def_size * 2);
  435. if (r < 0) {
  436. printf("ftruncate(GROW) failed: %m\n");
  437. abort();
  438. }
  439. mfd_assert_size(fd, mfd_def_size * 2);
  440. r = fallocate(fd,
  441. 0,
  442. 0,
  443. mfd_def_size * 4);
  444. if (r < 0) {
  445. printf("fallocate(ALLOC) failed: %m\n");
  446. abort();
  447. }
  448. mfd_assert_size(fd, mfd_def_size * 4);
  449. }
  450. static void mfd_fail_grow(int fd)
  451. {
  452. int r;
  453. r = ftruncate(fd, mfd_def_size * 2);
  454. if (r >= 0) {
  455. printf("ftruncate(GROW) didn't fail as expected\n");
  456. abort();
  457. }
  458. r = fallocate(fd,
  459. 0,
  460. 0,
  461. mfd_def_size * 4);
  462. if (r >= 0) {
  463. printf("fallocate(ALLOC) didn't fail as expected\n");
  464. abort();
  465. }
  466. }
  467. static void mfd_assert_grow_write(int fd)
  468. {
  469. static char *buf;
  470. ssize_t l;
  471. /* hugetlbfs does not support write */
  472. if (hugetlbfs_test)
  473. return;
  474. buf = malloc(mfd_def_size * 8);
  475. if (!buf) {
  476. printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
  477. abort();
  478. }
  479. l = pwrite(fd, buf, mfd_def_size * 8, 0);
  480. if (l != (mfd_def_size * 8)) {
  481. printf("pwrite() failed: %m\n");
  482. abort();
  483. }
  484. mfd_assert_size(fd, mfd_def_size * 8);
  485. }
  486. static void mfd_fail_grow_write(int fd)
  487. {
  488. static char *buf;
  489. ssize_t l;
  490. /* hugetlbfs does not support write */
  491. if (hugetlbfs_test)
  492. return;
  493. buf = malloc(mfd_def_size * 8);
  494. if (!buf) {
  495. printf("malloc(%zu) failed: %m\n", mfd_def_size * 8);
  496. abort();
  497. }
  498. l = pwrite(fd, buf, mfd_def_size * 8, 0);
  499. if (l == (mfd_def_size * 8)) {
  500. printf("pwrite() didn't fail as expected\n");
  501. abort();
  502. }
  503. }
  504. static int idle_thread_fn(void *arg)
  505. {
  506. sigset_t set;
  507. int sig;
  508. /* dummy waiter; SIGTERM terminates us anyway */
  509. sigemptyset(&set);
  510. sigaddset(&set, SIGTERM);
  511. sigwait(&set, &sig);
  512. return 0;
  513. }
  514. static pid_t spawn_idle_thread(unsigned int flags)
  515. {
  516. uint8_t *stack;
  517. pid_t pid;
  518. stack = malloc(STACK_SIZE);
  519. if (!stack) {
  520. printf("malloc(STACK_SIZE) failed: %m\n");
  521. abort();
  522. }
  523. pid = clone(idle_thread_fn,
  524. stack + STACK_SIZE,
  525. SIGCHLD | flags,
  526. NULL);
  527. if (pid < 0) {
  528. printf("clone() failed: %m\n");
  529. abort();
  530. }
  531. return pid;
  532. }
  533. static void join_idle_thread(pid_t pid)
  534. {
  535. kill(pid, SIGTERM);
  536. waitpid(pid, NULL, 0);
  537. }
  538. /*
  539. * Test memfd_create() syscall
  540. * Verify syscall-argument validation, including name checks, flag validation
  541. * and more.
  542. */
  543. static void test_create(void)
  544. {
  545. char buf[2048];
  546. int fd;
  547. printf("%s CREATE\n", memfd_str);
  548. /* test NULL name */
  549. mfd_fail_new(NULL, 0);
  550. /* test over-long name (not zero-terminated) */
  551. memset(buf, 0xff, sizeof(buf));
  552. mfd_fail_new(buf, 0);
  553. /* test over-long zero-terminated name */
  554. memset(buf, 0xff, sizeof(buf));
  555. buf[sizeof(buf) - 1] = 0;
  556. mfd_fail_new(buf, 0);
  557. /* verify "" is a valid name */
  558. fd = mfd_assert_new("", 0, 0);
  559. close(fd);
  560. /* verify invalid O_* open flags */
  561. mfd_fail_new("", 0x0100);
  562. mfd_fail_new("", ~MFD_CLOEXEC);
  563. mfd_fail_new("", ~MFD_ALLOW_SEALING);
  564. mfd_fail_new("", ~0);
  565. mfd_fail_new("", 0x80000000U);
  566. /* verify MFD_CLOEXEC is allowed */
  567. fd = mfd_assert_new("", 0, MFD_CLOEXEC);
  568. close(fd);
  569. /* verify MFD_ALLOW_SEALING is allowed */
  570. fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING);
  571. close(fd);
  572. /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */
  573. fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC);
  574. close(fd);
  575. }
  576. /*
  577. * Test basic sealing
  578. * A very basic sealing test to see whether setting/retrieving seals works.
  579. */
  580. static void test_basic(void)
  581. {
  582. int fd;
  583. printf("%s BASIC\n", memfd_str);
  584. fd = mfd_assert_new("kern_memfd_basic",
  585. mfd_def_size,
  586. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  587. /* add basic seals */
  588. mfd_assert_has_seals(fd, 0);
  589. mfd_assert_add_seals(fd, F_SEAL_SHRINK |
  590. F_SEAL_WRITE);
  591. mfd_assert_has_seals(fd, F_SEAL_SHRINK |
  592. F_SEAL_WRITE);
  593. /* add them again */
  594. mfd_assert_add_seals(fd, F_SEAL_SHRINK |
  595. F_SEAL_WRITE);
  596. mfd_assert_has_seals(fd, F_SEAL_SHRINK |
  597. F_SEAL_WRITE);
  598. /* add more seals and seal against sealing */
  599. mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL);
  600. mfd_assert_has_seals(fd, F_SEAL_SHRINK |
  601. F_SEAL_GROW |
  602. F_SEAL_WRITE |
  603. F_SEAL_SEAL);
  604. /* verify that sealing no longer works */
  605. mfd_fail_add_seals(fd, F_SEAL_GROW);
  606. mfd_fail_add_seals(fd, 0);
  607. close(fd);
  608. /* verify sealing does not work without MFD_ALLOW_SEALING */
  609. fd = mfd_assert_new("kern_memfd_basic",
  610. mfd_def_size,
  611. MFD_CLOEXEC);
  612. mfd_assert_has_seals(fd, F_SEAL_SEAL);
  613. mfd_fail_add_seals(fd, F_SEAL_SHRINK |
  614. F_SEAL_GROW |
  615. F_SEAL_WRITE);
  616. mfd_assert_has_seals(fd, F_SEAL_SEAL);
  617. close(fd);
  618. }
  619. /*
  620. * Test SEAL_WRITE
  621. * Test whether SEAL_WRITE actually prevents modifications.
  622. */
  623. static void test_seal_write(void)
  624. {
  625. int fd;
  626. printf("%s SEAL-WRITE\n", memfd_str);
  627. fd = mfd_assert_new("kern_memfd_seal_write",
  628. mfd_def_size,
  629. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  630. mfd_assert_has_seals(fd, 0);
  631. mfd_assert_add_seals(fd, F_SEAL_WRITE);
  632. mfd_assert_has_seals(fd, F_SEAL_WRITE);
  633. mfd_assert_read(fd);
  634. mfd_fail_write(fd);
  635. mfd_assert_shrink(fd);
  636. mfd_assert_grow(fd);
  637. mfd_fail_grow_write(fd);
  638. close(fd);
  639. }
  640. /*
  641. * Test SEAL_FUTURE_WRITE
  642. * Test whether SEAL_FUTURE_WRITE actually prevents modifications.
  643. */
  644. static void test_seal_future_write(void)
  645. {
  646. int fd, fd2;
  647. void *p;
  648. printf("%s SEAL-FUTURE-WRITE\n", memfd_str);
  649. fd = mfd_assert_new("kern_memfd_seal_future_write",
  650. mfd_def_size,
  651. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  652. p = mfd_assert_mmap_shared(fd);
  653. mfd_assert_has_seals(fd, 0);
  654. mfd_assert_add_seals(fd, F_SEAL_FUTURE_WRITE);
  655. mfd_assert_has_seals(fd, F_SEAL_FUTURE_WRITE);
  656. /* read should pass, writes should fail */
  657. mfd_assert_read(fd);
  658. mfd_assert_read_shared(fd);
  659. mfd_fail_write(fd);
  660. fd2 = mfd_assert_reopen_fd(fd);
  661. /* read should pass, writes should still fail */
  662. mfd_assert_read(fd2);
  663. mfd_assert_read_shared(fd2);
  664. mfd_fail_write(fd2);
  665. mfd_assert_fork_private_write(fd);
  666. munmap(p, mfd_def_size);
  667. close(fd2);
  668. close(fd);
  669. }
  670. /*
  671. * Test SEAL_SHRINK
  672. * Test whether SEAL_SHRINK actually prevents shrinking
  673. */
  674. static void test_seal_shrink(void)
  675. {
  676. int fd;
  677. printf("%s SEAL-SHRINK\n", memfd_str);
  678. fd = mfd_assert_new("kern_memfd_seal_shrink",
  679. mfd_def_size,
  680. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  681. mfd_assert_has_seals(fd, 0);
  682. mfd_assert_add_seals(fd, F_SEAL_SHRINK);
  683. mfd_assert_has_seals(fd, F_SEAL_SHRINK);
  684. mfd_assert_read(fd);
  685. mfd_assert_write(fd);
  686. mfd_fail_shrink(fd);
  687. mfd_assert_grow(fd);
  688. mfd_assert_grow_write(fd);
  689. close(fd);
  690. }
  691. /*
  692. * Test SEAL_GROW
  693. * Test whether SEAL_GROW actually prevents growing
  694. */
  695. static void test_seal_grow(void)
  696. {
  697. int fd;
  698. printf("%s SEAL-GROW\n", memfd_str);
  699. fd = mfd_assert_new("kern_memfd_seal_grow",
  700. mfd_def_size,
  701. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  702. mfd_assert_has_seals(fd, 0);
  703. mfd_assert_add_seals(fd, F_SEAL_GROW);
  704. mfd_assert_has_seals(fd, F_SEAL_GROW);
  705. mfd_assert_read(fd);
  706. mfd_assert_write(fd);
  707. mfd_assert_shrink(fd);
  708. mfd_fail_grow(fd);
  709. mfd_fail_grow_write(fd);
  710. close(fd);
  711. }
  712. /*
  713. * Test SEAL_SHRINK | SEAL_GROW
  714. * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing
  715. */
  716. static void test_seal_resize(void)
  717. {
  718. int fd;
  719. printf("%s SEAL-RESIZE\n", memfd_str);
  720. fd = mfd_assert_new("kern_memfd_seal_resize",
  721. mfd_def_size,
  722. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  723. mfd_assert_has_seals(fd, 0);
  724. mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
  725. mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW);
  726. mfd_assert_read(fd);
  727. mfd_assert_write(fd);
  728. mfd_fail_shrink(fd);
  729. mfd_fail_grow(fd);
  730. mfd_fail_grow_write(fd);
  731. close(fd);
  732. }
  733. /*
  734. * Test sharing via dup()
  735. * Test that seals are shared between dupped FDs and they're all equal.
  736. */
  737. static void test_share_dup(char *banner, char *b_suffix)
  738. {
  739. int fd, fd2;
  740. printf("%s %s %s\n", memfd_str, banner, b_suffix);
  741. fd = mfd_assert_new("kern_memfd_share_dup",
  742. mfd_def_size,
  743. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  744. mfd_assert_has_seals(fd, 0);
  745. fd2 = mfd_assert_dup(fd);
  746. mfd_assert_has_seals(fd2, 0);
  747. mfd_assert_add_seals(fd, F_SEAL_WRITE);
  748. mfd_assert_has_seals(fd, F_SEAL_WRITE);
  749. mfd_assert_has_seals(fd2, F_SEAL_WRITE);
  750. mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
  751. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
  752. mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
  753. mfd_assert_add_seals(fd, F_SEAL_SEAL);
  754. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
  755. mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
  756. mfd_fail_add_seals(fd, F_SEAL_GROW);
  757. mfd_fail_add_seals(fd2, F_SEAL_GROW);
  758. mfd_fail_add_seals(fd, F_SEAL_SEAL);
  759. mfd_fail_add_seals(fd2, F_SEAL_SEAL);
  760. close(fd2);
  761. mfd_fail_add_seals(fd, F_SEAL_GROW);
  762. close(fd);
  763. }
  764. /*
  765. * Test sealing with active mmap()s
  766. * Modifying seals is only allowed if no other mmap() refs exist.
  767. */
  768. static void test_share_mmap(char *banner, char *b_suffix)
  769. {
  770. int fd;
  771. void *p;
  772. printf("%s %s %s\n", memfd_str, banner, b_suffix);
  773. fd = mfd_assert_new("kern_memfd_share_mmap",
  774. mfd_def_size,
  775. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  776. mfd_assert_has_seals(fd, 0);
  777. /* shared/writable ref prevents sealing WRITE, but allows others */
  778. p = mfd_assert_mmap_shared(fd);
  779. mfd_fail_add_seals(fd, F_SEAL_WRITE);
  780. mfd_assert_has_seals(fd, 0);
  781. mfd_assert_add_seals(fd, F_SEAL_SHRINK);
  782. mfd_assert_has_seals(fd, F_SEAL_SHRINK);
  783. munmap(p, mfd_def_size);
  784. /* readable ref allows sealing */
  785. p = mfd_assert_mmap_private(fd);
  786. mfd_assert_add_seals(fd, F_SEAL_WRITE);
  787. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
  788. munmap(p, mfd_def_size);
  789. close(fd);
  790. }
  791. /*
  792. * Test sealing with open(/proc/self/fd/%d)
  793. * Via /proc we can get access to a separate file-context for the same memfd.
  794. * This is *not* like dup(), but like a real separate open(). Make sure the
  795. * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR.
  796. */
  797. static void test_share_open(char *banner, char *b_suffix)
  798. {
  799. int fd, fd2;
  800. printf("%s %s %s\n", memfd_str, banner, b_suffix);
  801. fd = mfd_assert_new("kern_memfd_share_open",
  802. mfd_def_size,
  803. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  804. mfd_assert_has_seals(fd, 0);
  805. fd2 = mfd_assert_open(fd, O_RDWR, 0);
  806. mfd_assert_add_seals(fd, F_SEAL_WRITE);
  807. mfd_assert_has_seals(fd, F_SEAL_WRITE);
  808. mfd_assert_has_seals(fd2, F_SEAL_WRITE);
  809. mfd_assert_add_seals(fd2, F_SEAL_SHRINK);
  810. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
  811. mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
  812. close(fd);
  813. fd = mfd_assert_open(fd2, O_RDONLY, 0);
  814. mfd_fail_add_seals(fd, F_SEAL_SEAL);
  815. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK);
  816. mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK);
  817. close(fd2);
  818. fd2 = mfd_assert_open(fd, O_RDWR, 0);
  819. mfd_assert_add_seals(fd2, F_SEAL_SEAL);
  820. mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
  821. mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL);
  822. close(fd2);
  823. close(fd);
  824. }
  825. /*
  826. * Test sharing via fork()
  827. * Test whether seal-modifications work as expected with forked childs.
  828. */
  829. static void test_share_fork(char *banner, char *b_suffix)
  830. {
  831. int fd;
  832. pid_t pid;
  833. printf("%s %s %s\n", memfd_str, banner, b_suffix);
  834. fd = mfd_assert_new("kern_memfd_share_fork",
  835. mfd_def_size,
  836. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  837. mfd_assert_has_seals(fd, 0);
  838. pid = spawn_idle_thread(0);
  839. mfd_assert_add_seals(fd, F_SEAL_SEAL);
  840. mfd_assert_has_seals(fd, F_SEAL_SEAL);
  841. mfd_fail_add_seals(fd, F_SEAL_WRITE);
  842. mfd_assert_has_seals(fd, F_SEAL_SEAL);
  843. join_idle_thread(pid);
  844. mfd_fail_add_seals(fd, F_SEAL_WRITE);
  845. mfd_assert_has_seals(fd, F_SEAL_SEAL);
  846. close(fd);
  847. }
  848. int main(int argc, char **argv)
  849. {
  850. pid_t pid;
  851. if (argc == 2) {
  852. if (!strcmp(argv[1], "hugetlbfs")) {
  853. unsigned long hpage_size = default_huge_page_size();
  854. if (!hpage_size) {
  855. printf("Unable to determine huge page size\n");
  856. abort();
  857. }
  858. hugetlbfs_test = 1;
  859. memfd_str = MEMFD_HUGE_STR;
  860. mfd_def_size = hpage_size * 2;
  861. } else {
  862. printf("Unknown option: %s\n", argv[1]);
  863. abort();
  864. }
  865. }
  866. test_create();
  867. test_basic();
  868. test_seal_write();
  869. test_seal_future_write();
  870. test_seal_shrink();
  871. test_seal_grow();
  872. test_seal_resize();
  873. test_share_dup("SHARE-DUP", "");
  874. test_share_mmap("SHARE-MMAP", "");
  875. test_share_open("SHARE-OPEN", "");
  876. test_share_fork("SHARE-FORK", "");
  877. /* Run test-suite in a multi-threaded environment with a shared
  878. * file-table. */
  879. pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM);
  880. test_share_dup("SHARE-DUP", SHARED_FT_STR);
  881. test_share_mmap("SHARE-MMAP", SHARED_FT_STR);
  882. test_share_open("SHARE-OPEN", SHARED_FT_STR);
  883. test_share_fork("SHARE-FORK", SHARED_FT_STR);
  884. join_idle_thread(pid);
  885. printf("memfd: DONE\n");
  886. return 0;
  887. }