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