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