memfd_test.c 18 KB

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