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