register-restrictions.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test restrictions
  5. *
  6. */
  7. #include <errno.h>
  8. #include <stdio.h>
  9. #include <unistd.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <fcntl.h>
  13. #include <poll.h>
  14. #include <sys/eventfd.h>
  15. #include "liburing.h"
  16. enum {
  17. TEST_OK,
  18. TEST_SKIPPED,
  19. TEST_FAILED
  20. };
  21. static int test_restrictions_sqe_op(void)
  22. {
  23. struct io_uring_restriction res[2];
  24. struct io_uring_sqe *sqe;
  25. struct io_uring_cqe *cqe;
  26. struct io_uring ring;
  27. int ret, pipe1[2];
  28. uint64_t ptr;
  29. struct iovec vec = {
  30. .iov_base = &ptr,
  31. .iov_len = sizeof(ptr)
  32. };
  33. if (pipe(pipe1) != 0) {
  34. perror("pipe");
  35. return TEST_FAILED;
  36. }
  37. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  38. if (ret) {
  39. if (ret == -EINVAL)
  40. return TEST_SKIPPED;
  41. fprintf(stderr, "ring setup failed: %d\n", ret);
  42. return TEST_FAILED;
  43. }
  44. res[0].opcode = IORING_RESTRICTION_SQE_OP;
  45. res[0].sqe_op = IORING_OP_WRITEV;
  46. res[1].opcode = IORING_RESTRICTION_SQE_OP;
  47. res[1].sqe_op = IORING_OP_WRITE;
  48. ret = io_uring_register_restrictions(&ring, res, 2);
  49. if (ret) {
  50. if (ret == -EINVAL)
  51. return TEST_SKIPPED;
  52. fprintf(stderr, "failed to register restrictions: %d\n", ret);
  53. return TEST_FAILED;
  54. }
  55. ret = io_uring_enable_rings(&ring);
  56. if (ret) {
  57. fprintf(stderr, "ring enabling failed: %d\n", ret);
  58. return TEST_FAILED;
  59. }
  60. sqe = io_uring_get_sqe(&ring);
  61. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  62. sqe->user_data = 1;
  63. sqe = io_uring_get_sqe(&ring);
  64. io_uring_prep_readv(sqe, pipe1[0], &vec, 1, 0);
  65. sqe->user_data = 2;
  66. ret = io_uring_submit(&ring);
  67. if (ret != 2) {
  68. fprintf(stderr, "submit: %d\n", ret);
  69. return TEST_FAILED;
  70. }
  71. for (int i = 0; i < 2; i++) {
  72. ret = io_uring_wait_cqe(&ring, &cqe);
  73. if (ret) {
  74. fprintf(stderr, "wait: %d\n", ret);
  75. return TEST_FAILED;
  76. }
  77. switch (cqe->user_data) {
  78. case 1: /* writev */
  79. if (cqe->res != sizeof(ptr)) {
  80. fprintf(stderr, "write res: %d\n", cqe->res);
  81. return TEST_FAILED;
  82. }
  83. break;
  84. case 2: /* readv should be denied */
  85. if (cqe->res != -EACCES) {
  86. fprintf(stderr, "read res: %d\n", cqe->res);
  87. return TEST_FAILED;
  88. }
  89. break;
  90. }
  91. io_uring_cqe_seen(&ring, cqe);
  92. }
  93. io_uring_queue_exit(&ring);
  94. return TEST_OK;
  95. }
  96. static int test_restrictions_register_op(void)
  97. {
  98. struct io_uring_restriction res[1];
  99. struct io_uring ring;
  100. int ret, pipe1[2];
  101. uint64_t ptr;
  102. struct iovec vec = {
  103. .iov_base = &ptr,
  104. .iov_len = sizeof(ptr)
  105. };
  106. if (pipe(pipe1) != 0) {
  107. perror("pipe");
  108. return TEST_FAILED;
  109. }
  110. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  111. if (ret) {
  112. fprintf(stderr, "ring setup failed: %d\n", ret);
  113. return TEST_FAILED;
  114. }
  115. res[0].opcode = IORING_RESTRICTION_REGISTER_OP;
  116. res[0].register_op = IORING_REGISTER_BUFFERS;
  117. ret = io_uring_register_restrictions(&ring, res, 1);
  118. if (ret) {
  119. if (ret == -EINVAL)
  120. return TEST_SKIPPED;
  121. fprintf(stderr, "failed to register restrictions: %d\n", ret);
  122. return TEST_FAILED;
  123. }
  124. ret = io_uring_enable_rings(&ring);
  125. if (ret) {
  126. fprintf(stderr, "ring enabling failed: %d\n", ret);
  127. return TEST_FAILED;
  128. }
  129. ret = io_uring_register_buffers(&ring, &vec, 1);
  130. if (ret) {
  131. fprintf(stderr, "io_uring_register_buffers failed: %d\n", ret);
  132. return TEST_FAILED;
  133. }
  134. ret = io_uring_register_files(&ring, pipe1, 2);
  135. if (ret != -EACCES) {
  136. fprintf(stderr, "io_uring_register_files ret: %d\n", ret);
  137. return TEST_FAILED;
  138. }
  139. io_uring_queue_exit(&ring);
  140. return TEST_OK;
  141. }
  142. static int test_restrictions_fixed_file(void)
  143. {
  144. struct io_uring_restriction res[4];
  145. struct io_uring_sqe *sqe;
  146. struct io_uring_cqe *cqe;
  147. struct io_uring ring;
  148. int ret, pipe1[2];
  149. uint64_t ptr;
  150. struct iovec vec = {
  151. .iov_base = &ptr,
  152. .iov_len = sizeof(ptr)
  153. };
  154. if (pipe(pipe1) != 0) {
  155. perror("pipe");
  156. return TEST_FAILED;
  157. }
  158. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  159. if (ret) {
  160. fprintf(stderr, "ring setup failed: %d\n", ret);
  161. return TEST_FAILED;
  162. }
  163. res[0].opcode = IORING_RESTRICTION_SQE_OP;
  164. res[0].sqe_op = IORING_OP_WRITEV;
  165. res[1].opcode = IORING_RESTRICTION_SQE_OP;
  166. res[1].sqe_op = IORING_OP_READV;
  167. res[2].opcode = IORING_RESTRICTION_SQE_FLAGS_REQUIRED;
  168. res[2].sqe_flags = IOSQE_FIXED_FILE;
  169. res[3].opcode = IORING_RESTRICTION_REGISTER_OP;
  170. res[3].register_op = IORING_REGISTER_FILES;
  171. ret = io_uring_register_restrictions(&ring, res, 4);
  172. if (ret) {
  173. if (ret == -EINVAL)
  174. return TEST_SKIPPED;
  175. fprintf(stderr, "failed to register restrictions: %d\n", ret);
  176. return TEST_FAILED;
  177. }
  178. ret = io_uring_enable_rings(&ring);
  179. if (ret) {
  180. fprintf(stderr, "ring enabling failed: %d\n", ret);
  181. return TEST_FAILED;
  182. }
  183. ret = io_uring_register_files(&ring, pipe1, 2);
  184. if (ret) {
  185. fprintf(stderr, "io_uring_register_files ret: %d\n", ret);
  186. return TEST_FAILED;
  187. }
  188. sqe = io_uring_get_sqe(&ring);
  189. io_uring_prep_writev(sqe, 1, &vec, 1, 0);
  190. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
  191. sqe->user_data = 1;
  192. sqe = io_uring_get_sqe(&ring);
  193. io_uring_prep_readv(sqe, 0, &vec, 1, 0);
  194. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
  195. sqe->user_data = 2;
  196. sqe = io_uring_get_sqe(&ring);
  197. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  198. sqe->user_data = 3;
  199. ret = io_uring_submit(&ring);
  200. if (ret != 3) {
  201. fprintf(stderr, "submit: %d\n", ret);
  202. return TEST_FAILED;
  203. }
  204. for (int i = 0; i < 3; i++) {
  205. ret = io_uring_wait_cqe(&ring, &cqe);
  206. if (ret) {
  207. fprintf(stderr, "wait: %d\n", ret);
  208. return TEST_FAILED;
  209. }
  210. switch (cqe->user_data) {
  211. case 1: /* writev */
  212. if (cqe->res != sizeof(ptr)) {
  213. fprintf(stderr, "write res: %d\n", cqe->res);
  214. return TEST_FAILED;
  215. }
  216. break;
  217. case 2: /* readv */
  218. if (cqe->res != sizeof(ptr)) {
  219. fprintf(stderr, "read res: %d\n", cqe->res);
  220. return TEST_FAILED;
  221. }
  222. break;
  223. case 3: /* writev without fixed_file should be denied */
  224. if (cqe->res != -EACCES) {
  225. fprintf(stderr, "write res: %d\n", cqe->res);
  226. return TEST_FAILED;
  227. }
  228. break;
  229. }
  230. io_uring_cqe_seen(&ring, cqe);
  231. }
  232. io_uring_queue_exit(&ring);
  233. return TEST_OK;
  234. }
  235. static int test_restrictions_flags(void)
  236. {
  237. struct io_uring_restriction res[3];
  238. struct io_uring_sqe *sqe;
  239. struct io_uring_cqe *cqe;
  240. struct io_uring ring;
  241. int ret, pipe1[2];
  242. uint64_t ptr;
  243. struct iovec vec = {
  244. .iov_base = &ptr,
  245. .iov_len = sizeof(ptr)
  246. };
  247. if (pipe(pipe1) != 0) {
  248. perror("pipe");
  249. return TEST_FAILED;
  250. }
  251. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  252. if (ret) {
  253. fprintf(stderr, "ring setup failed: %d\n", ret);
  254. return TEST_FAILED;
  255. }
  256. res[0].opcode = IORING_RESTRICTION_SQE_OP;
  257. res[0].sqe_op = IORING_OP_WRITEV;
  258. res[1].opcode = IORING_RESTRICTION_SQE_FLAGS_ALLOWED;
  259. res[1].sqe_flags = IOSQE_ASYNC | IOSQE_IO_LINK;
  260. res[2].opcode = IORING_RESTRICTION_SQE_FLAGS_REQUIRED;
  261. res[2].sqe_flags = IOSQE_FIXED_FILE;
  262. ret = io_uring_register_restrictions(&ring, res, 3);
  263. if (ret) {
  264. if (ret == -EINVAL)
  265. return TEST_SKIPPED;
  266. fprintf(stderr, "failed to register restrictions: %d\n", ret);
  267. return TEST_FAILED;
  268. }
  269. ret = io_uring_register_files(&ring, pipe1, 2);
  270. if (ret) {
  271. fprintf(stderr, "io_uring_register_files ret: %d\n", ret);
  272. return TEST_FAILED;
  273. }
  274. ret = io_uring_enable_rings(&ring);
  275. if (ret) {
  276. fprintf(stderr, "ring enabling failed: %d\n", ret);
  277. return TEST_FAILED;
  278. }
  279. sqe = io_uring_get_sqe(&ring);
  280. io_uring_prep_writev(sqe, 1, &vec, 1, 0);
  281. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE);
  282. sqe->user_data = 1;
  283. sqe = io_uring_get_sqe(&ring);
  284. io_uring_prep_writev(sqe, 1, &vec, 1, 0);
  285. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE | IOSQE_ASYNC);
  286. sqe->user_data = 2;
  287. sqe = io_uring_get_sqe(&ring);
  288. io_uring_prep_writev(sqe, 1, &vec, 1, 0);
  289. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE | IOSQE_IO_LINK);
  290. sqe->user_data = 3;
  291. ret = io_uring_submit(&ring);
  292. if (ret != 3) {
  293. fprintf(stderr, "submit: %d\n", ret);
  294. return TEST_FAILED;
  295. }
  296. sqe = io_uring_get_sqe(&ring);
  297. io_uring_prep_writev(sqe, 1, &vec, 1, 0);
  298. io_uring_sqe_set_flags(sqe, IOSQE_FIXED_FILE | IOSQE_IO_DRAIN);
  299. sqe->user_data = 4;
  300. ret = io_uring_submit(&ring);
  301. if (ret != 1) {
  302. fprintf(stderr, "submit: %d\n", ret);
  303. return TEST_FAILED;
  304. }
  305. sqe = io_uring_get_sqe(&ring);
  306. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  307. io_uring_sqe_set_flags(sqe, IOSQE_IO_DRAIN);
  308. sqe->user_data = 5;
  309. ret = io_uring_submit(&ring);
  310. if (ret != 1) {
  311. fprintf(stderr, "submit: %d\n", ret);
  312. return TEST_FAILED;
  313. }
  314. sqe = io_uring_get_sqe(&ring);
  315. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  316. io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
  317. sqe->user_data = 6;
  318. ret = io_uring_submit(&ring);
  319. if (ret != 1) {
  320. fprintf(stderr, "submit: %d\n", ret);
  321. return TEST_FAILED;
  322. }
  323. sqe = io_uring_get_sqe(&ring);
  324. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  325. sqe->user_data = 7;
  326. ret = io_uring_submit(&ring);
  327. if (ret != 1) {
  328. fprintf(stderr, "submit: %d\n", ret);
  329. return TEST_FAILED;
  330. }
  331. for (int i = 0; i < 7; i++) {
  332. ret = io_uring_wait_cqe(&ring, &cqe);
  333. if (ret) {
  334. fprintf(stderr, "wait: %d\n", ret);
  335. return TEST_FAILED;
  336. }
  337. switch (cqe->user_data) {
  338. case 1: /* writev - flags = IOSQE_FIXED_FILE */
  339. case 2: /* writev - flags = IOSQE_FIXED_FILE | IOSQE_ASYNC */
  340. case 3: /* writev - flags = IOSQE_FIXED_FILE | IOSQE_IO_LINK */
  341. if (cqe->res != sizeof(ptr)) {
  342. fprintf(stderr, "write res: %d user_data %" PRIu64 "\n",
  343. cqe->res, (uint64_t) cqe->user_data);
  344. return TEST_FAILED;
  345. }
  346. break;
  347. case 4: /* writev - flags = IOSQE_FIXED_FILE | IOSQE_IO_DRAIN */
  348. case 5: /* writev - flags = IOSQE_IO_DRAIN */
  349. case 6: /* writev - flags = IOSQE_ASYNC */
  350. case 7: /* writev - flags = 0 */
  351. if (cqe->res != -EACCES) {
  352. fprintf(stderr, "write res: %d user_data %" PRIu64 "\n",
  353. cqe->res, (uint64_t) cqe->user_data);
  354. return TEST_FAILED;
  355. }
  356. break;
  357. }
  358. io_uring_cqe_seen(&ring, cqe);
  359. }
  360. io_uring_queue_exit(&ring);
  361. return TEST_OK;
  362. }
  363. static int test_restrictions_empty(void)
  364. {
  365. struct io_uring_restriction res[0];
  366. struct io_uring_sqe *sqe;
  367. struct io_uring_cqe *cqe;
  368. struct io_uring ring;
  369. int ret, pipe1[2];
  370. uint64_t ptr;
  371. struct iovec vec = {
  372. .iov_base = &ptr,
  373. .iov_len = sizeof(ptr)
  374. };
  375. if (pipe(pipe1) != 0) {
  376. perror("pipe");
  377. return TEST_FAILED;
  378. }
  379. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  380. if (ret) {
  381. fprintf(stderr, "ring setup failed: %d\n", ret);
  382. return TEST_FAILED;
  383. }
  384. ret = io_uring_register_restrictions(&ring, res, 0);
  385. if (ret) {
  386. if (ret == -EINVAL)
  387. return TEST_SKIPPED;
  388. fprintf(stderr, "failed to register restrictions: %d\n", ret);
  389. return TEST_FAILED;
  390. }
  391. ret = io_uring_enable_rings(&ring);
  392. if (ret) {
  393. fprintf(stderr, "ring enabling failed: %d\n", ret);
  394. return TEST_FAILED;
  395. }
  396. ret = io_uring_register_buffers(&ring, &vec, 1);
  397. if (ret != -EACCES) {
  398. fprintf(stderr, "io_uring_register_buffers ret: %d\n", ret);
  399. return TEST_FAILED;
  400. }
  401. ret = io_uring_register_files(&ring, pipe1, 2);
  402. if (ret != -EACCES) {
  403. fprintf(stderr, "io_uring_register_files ret: %d\n", ret);
  404. return TEST_FAILED;
  405. }
  406. sqe = io_uring_get_sqe(&ring);
  407. io_uring_prep_writev(sqe, pipe1[1], &vec, 1, 0);
  408. ret = io_uring_submit(&ring);
  409. if (ret != 1) {
  410. fprintf(stderr, "submit: %d\n", ret);
  411. return TEST_FAILED;
  412. }
  413. ret = io_uring_wait_cqe(&ring, &cqe);
  414. if (ret) {
  415. fprintf(stderr, "wait: %d\n", ret);
  416. return TEST_FAILED;
  417. }
  418. if (cqe->res != -EACCES) {
  419. fprintf(stderr, "write res: %d\n", cqe->res);
  420. return TEST_FAILED;
  421. }
  422. io_uring_cqe_seen(&ring, cqe);
  423. io_uring_queue_exit(&ring);
  424. return TEST_OK;
  425. }
  426. static int test_restrictions_rings_not_disabled(void)
  427. {
  428. struct io_uring_restriction res[1];
  429. struct io_uring ring;
  430. int ret;
  431. ret = io_uring_queue_init(8, &ring, 0);
  432. if (ret) {
  433. fprintf(stderr, "ring setup failed: %d\n", ret);
  434. return TEST_FAILED;
  435. }
  436. res[0].opcode = IORING_RESTRICTION_SQE_OP;
  437. res[0].sqe_op = IORING_OP_WRITEV;
  438. ret = io_uring_register_restrictions(&ring, res, 1);
  439. if (ret != -EBADFD) {
  440. fprintf(stderr, "io_uring_register_restrictions ret: %d\n",
  441. ret);
  442. return TEST_FAILED;
  443. }
  444. io_uring_queue_exit(&ring);
  445. return TEST_OK;
  446. }
  447. static int test_restrictions_rings_disabled(void)
  448. {
  449. struct io_uring_sqe *sqe;
  450. struct io_uring ring;
  451. int ret;
  452. ret = io_uring_queue_init(8, &ring, IORING_SETUP_R_DISABLED);
  453. if (ret) {
  454. fprintf(stderr, "ring setup failed: %d\n", ret);
  455. return TEST_FAILED;
  456. }
  457. sqe = io_uring_get_sqe(&ring);
  458. io_uring_prep_nop(sqe);
  459. ret = io_uring_submit(&ring);
  460. if (ret != -EBADFD) {
  461. fprintf(stderr, "submit: %d\n", ret);
  462. return TEST_FAILED;
  463. }
  464. io_uring_queue_exit(&ring);
  465. return TEST_OK;
  466. }
  467. int main(int argc, char *argv[])
  468. {
  469. int ret;
  470. if (argc > 1)
  471. return 0;
  472. ret = test_restrictions_sqe_op();
  473. if (ret == TEST_SKIPPED) {
  474. printf("test_restrictions_sqe_op: skipped\n");
  475. return 0;
  476. } else if (ret == TEST_FAILED) {
  477. fprintf(stderr, "test_restrictions_sqe_op failed\n");
  478. return ret;
  479. }
  480. ret = test_restrictions_register_op();
  481. if (ret == TEST_SKIPPED) {
  482. printf("test_restrictions_register_op: skipped\n");
  483. } else if (ret == TEST_FAILED) {
  484. fprintf(stderr, "test_restrictions_register_op failed\n");
  485. return ret;
  486. }
  487. ret = test_restrictions_fixed_file();
  488. if (ret == TEST_SKIPPED) {
  489. printf("test_restrictions_fixed_file: skipped\n");
  490. } else if (ret == TEST_FAILED) {
  491. fprintf(stderr, "test_restrictions_fixed_file failed\n");
  492. return ret;
  493. }
  494. ret = test_restrictions_flags();
  495. if (ret == TEST_SKIPPED) {
  496. printf("test_restrictions_flags: skipped\n");
  497. } else if (ret == TEST_FAILED) {
  498. fprintf(stderr, "test_restrictions_flags failed\n");
  499. return ret;
  500. }
  501. ret = test_restrictions_empty();
  502. if (ret == TEST_SKIPPED) {
  503. printf("test_restrictions_empty: skipped\n");
  504. } else if (ret == TEST_FAILED) {
  505. fprintf(stderr, "test_restrictions_empty failed\n");
  506. return ret;
  507. }
  508. ret = test_restrictions_rings_not_disabled();
  509. if (ret == TEST_SKIPPED) {
  510. printf("test_restrictions_rings_not_disabled: skipped\n");
  511. } else if (ret == TEST_FAILED) {
  512. fprintf(stderr, "test_restrictions_rings_not_disabled failed\n");
  513. return ret;
  514. }
  515. ret = test_restrictions_rings_disabled();
  516. if (ret == TEST_SKIPPED) {
  517. printf("test_restrictions_rings_disabled: skipped\n");
  518. } else if (ret == TEST_FAILED) {
  519. fprintf(stderr, "test_restrictions_rings_disabled failed\n");
  520. return ret;
  521. }
  522. return 0;
  523. }