personality.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #include "../config-host.h"
  2. /* SPDX-License-Identifier: MIT */
  3. /*
  4. * Description: test if personalities work
  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 "liburing.h"
  14. #define FNAME "/tmp/.tmp.access"
  15. #define USE_UID 1000
  16. static int no_personality;
  17. static int open_file(struct io_uring *ring, int cred_id, int with_link)
  18. {
  19. struct io_uring_cqe *cqe;
  20. struct io_uring_sqe *sqe;
  21. int ret, i, to_submit = 1;
  22. if (with_link) {
  23. sqe = io_uring_get_sqe(ring);
  24. io_uring_prep_nop(sqe);
  25. sqe->flags |= IOSQE_IO_LINK;
  26. sqe->user_data = 1;
  27. to_submit++;
  28. }
  29. sqe = io_uring_get_sqe(ring);
  30. io_uring_prep_openat(sqe, -1, FNAME, O_RDONLY, 0);
  31. sqe->user_data = 2;
  32. if (cred_id != -1)
  33. sqe->personality = cred_id;
  34. ret = io_uring_submit(ring);
  35. if (ret != to_submit) {
  36. fprintf(stderr, "submit got: %d\n", ret);
  37. goto err;
  38. }
  39. for (i = 0; i < to_submit; i++) {
  40. ret = io_uring_wait_cqe(ring, &cqe);
  41. if (ret < 0) {
  42. fprintf(stderr, "wait completion %d\n", ret);
  43. goto err;
  44. }
  45. ret = cqe->res;
  46. io_uring_cqe_seen(ring, cqe);
  47. }
  48. err:
  49. return ret;
  50. }
  51. static int test_personality(struct io_uring *ring)
  52. {
  53. int ret, cred_id;
  54. ret = io_uring_register_personality(ring);
  55. if (ret < 0) {
  56. if (ret == -EINVAL) {
  57. fprintf(stdout, "Personalities not supported, skipping\n");
  58. no_personality = 1;
  59. goto out;
  60. }
  61. fprintf(stderr, "register_personality: %d\n", ret);
  62. goto err;
  63. }
  64. cred_id = ret;
  65. /* create file only owner can open */
  66. ret = open(FNAME, O_RDONLY | O_CREAT, 0600);
  67. if (ret < 0) {
  68. perror("open");
  69. goto err;
  70. }
  71. close(ret);
  72. /* verify we can open it */
  73. ret = open_file(ring, -1, 0);
  74. if (ret < 0) {
  75. fprintf(stderr, "current open got: %d\n", ret);
  76. goto err;
  77. }
  78. if (seteuid(USE_UID) < 0) {
  79. fprintf(stdout, "Can't switch to UID %u, skipping\n", USE_UID);
  80. goto out;
  81. }
  82. /* verify we can't open it with current credentials */
  83. ret = open_file(ring, -1, 0);
  84. if (ret != -EACCES) {
  85. fprintf(stderr, "open got: %d\n", ret);
  86. goto err;
  87. }
  88. /* verify we can open with registered credentials */
  89. ret = open_file(ring, cred_id, 0);
  90. if (ret < 0) {
  91. fprintf(stderr, "credential open: %d\n", ret);
  92. goto err;
  93. }
  94. close(ret);
  95. /* verify we can open with registered credentials and as a link */
  96. ret = open_file(ring, cred_id, 1);
  97. if (ret < 0) {
  98. fprintf(stderr, "credential open: %d\n", ret);
  99. goto err;
  100. }
  101. if (seteuid(0))
  102. perror("seteuid");
  103. ret = io_uring_unregister_personality(ring, cred_id);
  104. if (ret) {
  105. fprintf(stderr, "register_personality: %d\n", ret);
  106. goto err;
  107. }
  108. out:
  109. unlink(FNAME);
  110. return 0;
  111. err:
  112. unlink(FNAME);
  113. return 1;
  114. }
  115. static int test_invalid_personality(struct io_uring *ring)
  116. {
  117. int ret;
  118. ret = open_file(ring, 2, 0);
  119. if (ret != -EINVAL) {
  120. fprintf(stderr, "invalid personality got: %d\n", ret);
  121. goto err;
  122. }
  123. return 0;
  124. err:
  125. return 1;
  126. }
  127. static int test_invalid_unregister(struct io_uring *ring)
  128. {
  129. int ret;
  130. ret = io_uring_unregister_personality(ring, 2);
  131. if (ret != -EINVAL) {
  132. fprintf(stderr, "invalid personality unregister got: %d\n", ret);
  133. goto err;
  134. }
  135. return 0;
  136. err:
  137. return 1;
  138. }
  139. int main(int argc, char *argv[])
  140. {
  141. struct io_uring ring;
  142. int ret;
  143. if (argc > 1)
  144. return 0;
  145. if (geteuid()) {
  146. fprintf(stderr, "Not root, skipping\n");
  147. return 0;
  148. }
  149. ret = io_uring_queue_init(8, &ring, 0);
  150. if (ret) {
  151. fprintf(stderr, "ring setup failed: %d\n", ret);
  152. return 1;
  153. }
  154. ret = test_personality(&ring);
  155. if (ret) {
  156. fprintf(stderr, "test_personality failed\n");
  157. return ret;
  158. }
  159. if (no_personality)
  160. return 0;
  161. ret = test_invalid_personality(&ring);
  162. if (ret) {
  163. fprintf(stderr, "test_invalid_personality failed\n");
  164. return ret;
  165. }
  166. ret = test_invalid_unregister(&ring);
  167. if (ret) {
  168. fprintf(stderr, "test_invalid_unregister failed\n");
  169. return ret;
  170. }
  171. return 0;
  172. }