register-restrictions.c 14 KB

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