memfd_test.c 18 KB

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