]> git.proxmox.com Git - mirror_lxcfs.git/blob - tests/test_syscalls.c
Merge pull request #474 from brauner/2021-09-01.meson
[mirror_lxcfs.git] / tests / test_syscalls.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE
5 #endif
6
7 #include "config.h"
8
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <libgen.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/mount.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/sysmacros.h>
21 #include <sys/types.h>
22 #include <sys/types.h>
23 #include <sys/un.h>
24 #include <sys/xattr.h>
25 #include <unistd.h>
26 #include <utime.h>
27
28 void test_open(const char *path)
29 {
30 int fd = open(path, O_RDONLY);
31 if (fd >= 0) {
32 fprintf(stderr, "leak at open of %s\n", path);
33 exit(1);
34 }
35 if (errno != ENOENT) {
36 fprintf(stderr, "leak at open of %s: errno was %d\n", path, errno);
37 exit(1);
38 }
39 }
40
41 void test_stat(const char *path)
42 {
43 struct stat sb;
44 if (stat(path, &sb) >= 0) {
45 fprintf(stderr, "leak at stat of %s\n", path);
46 exit(1);
47 }
48 if (errno != ENOENT) {
49 fprintf(stderr, "leak at stat of %s: errno was %d\n", path, errno);
50 exit(1);
51 }
52 }
53
54 void test_access(const char *path)
55 {
56 if (access(path, O_RDONLY) >= 0) {
57 fprintf(stderr, "leak at access of %s\n", path);
58 exit(1);
59 }
60 if (errno != ENOENT) {
61 fprintf(stderr, "leak at access of %s: errno was %d\n", path, errno);
62 exit(1);
63 }
64 }
65
66 void test_bind(const char *path)
67 {
68 int sfd;
69 struct sockaddr_un my_addr;
70
71 sfd = socket(AF_UNIX, SOCK_STREAM, 0);
72
73 if (sfd < 0) {
74 fprintf(stderr, "Failed to open a socket for bind test\n");
75 exit(1);
76 }
77 memset(&my_addr, 0, sizeof(struct sockaddr_un));
78 my_addr.sun_family = AF_UNIX;
79 strncpy(my_addr.sun_path, path,
80 sizeof(my_addr.sun_path) - 1);
81 if (bind(sfd, (struct sockaddr *) &my_addr,
82 sizeof(struct sockaddr_un)) != -1) {
83 fprintf(stderr, "leak at bind of %s\n", path);
84 exit(1);
85 }
86 if (errno != ENOENT && errno != ENOSYS) {
87 fprintf(stderr, "leak at bind of %s: errno was %s\n", path, strerror(errno));
88 exit(1);
89 }
90 close(sfd);
91 }
92
93 void test_bindmount(const char *path)
94 {
95 if (mount(path, path, "none", MS_BIND, NULL) == 0) {
96 fprintf(stderr, "leak at bind mount of %s\n", path);
97 exit(1);
98 }
99 }
100
101 void test_truncate(const char *path)
102 {
103 if (truncate(path, 0) == 0) {
104 fprintf(stderr, "leak at truncate of %s\n", path);
105 exit(1);
106 }
107 }
108
109 void test_chdir(const char *path)
110 {
111 if (chdir(path) == 0) {
112 fprintf(stderr, "leak at chdir to %s\n", path);
113 exit(1);
114 }
115 }
116
117 void test_rename(const char *path)
118 {
119 char *d = strdupa(path), *tmpname;
120 d = dirname(d);
121 size_t len = strlen(path) + 30;
122
123 tmpname = alloca(len);
124 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
125 if (rename(path, tmpname) == 0 || errno != ENOENT) {
126 fprintf(stderr, "leak at rename of %s\n", path);
127 exit(1);
128 }
129 }
130
131 void test_mkdir(const char *path)
132 {
133 size_t len = strlen(path) + 30;
134 char *tmpname = alloca(len);
135 snprintf(tmpname, len, "%s/%d", path, (int)getpid());
136
137 if (mkdir(path, 0755) == 0) {
138 fprintf(stderr, "leak at mkdir of %s\n", path);
139 exit(1);
140 }
141 if (errno != ENOENT) {
142 fprintf(stderr, "leak at mkdir of %s, errno was %s\n", path, strerror(errno));
143 exit(1);
144 }
145 if (mkdir(tmpname, 0755) == 0) {
146 fprintf(stderr, "leak at mkdir of %s\n", tmpname);
147 exit(1);
148 }
149 if (errno != ENOENT) {
150 fprintf(stderr, "leak at mkdir of %s, errno was %s\n", path, strerror(errno));
151 exit(1);
152 }
153 }
154
155 void test_rmdir(const char *path)
156 {
157 size_t len = strlen(path) + 30;
158 char *tmpname = alloca(len);
159 snprintf(tmpname, len, "%s/%d", path, (int)getpid());
160
161 if (rmdir(path) == 0 || errno != ENOENT) {
162 fprintf(stderr, "leak at rmdir of %s\n", path);
163 exit(1);
164 }
165 if (rmdir(tmpname) == 0 || errno != ENOENT) {
166 fprintf(stderr, "leak at rmdir of %s\n", tmpname);
167 exit(1);
168 }
169 }
170
171 void test_creat(const char *path)
172 {
173 if (creat(path, 0755) >= 0) {
174 fprintf(stderr, "leak at creat of %s\n", path);
175 exit(1);
176 }
177 if (errno != ENOENT && errno != ENOSYS) {
178 fprintf(stderr, "leak at creat of %s: errno was %s\n", path, strerror(errno));
179 exit(1);
180 }
181 }
182
183 void test_link(const char *path)
184 {
185 char *d = strdupa(path), *tmpname;
186 d = dirname(d);
187 size_t len = strlen(path) + 30;
188 tmpname = alloca(len);
189 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
190
191 if (link(path, tmpname) == 0) {
192 fprintf(stderr, "leak at link of %s\n", path);
193 exit(1);
194 }
195 if (errno != ENOENT && errno != ENOSYS) {
196 fprintf(stderr, "leak at link of %s: errno was %s\n", path, strerror(errno));
197 exit(1);
198 }
199
200 if (link(tmpname, path) == 0) {
201 fprintf(stderr, "leak at link (2) of %s\n", path);
202 exit(1);
203 }
204 if (errno != ENOENT && errno != ENOSYS) {
205 fprintf(stderr, "leak at link (2) of %s: errno was %s\n", path, strerror(errno));
206 exit(1);
207 }
208 }
209
210 void test_unlink(const char *path)
211 {
212 if (unlink(path) == 0) {
213 fprintf(stderr, "leak at unlink of %s\n", path);
214 exit(1);
215 }
216 if (errno != ENOENT && errno != ENOSYS) {
217 fprintf(stderr, "leak at unlink of %s: errno was %s\n", path, strerror(errno));
218 exit(1);
219 }
220 }
221
222 void test_symlink(const char *path)
223 {
224 char *d = strdupa(path), *tmpname;
225 d = dirname(d);
226 size_t len = strlen(path) + 30;
227 tmpname = alloca(len);
228 snprintf(tmpname, len, "%s/%d", d, (int)getpid());
229
230 if (symlink(tmpname, path) == 0) {
231 fprintf(stderr, "leak at symlink of %s\n", path);
232 exit(1);
233 }
234 if (errno != ENOENT && errno != ENOSYS) {
235 fprintf(stderr, "leak at symlink of %s: errno was %s\n", path, strerror(errno));
236 exit(1);
237 }
238 if (symlink(path, tmpname) == 0) {
239 fprintf(stderr, "leak at symlink (2) of %s\n", path);
240 exit(1);
241 }
242 if (errno != ENOENT && errno != ENOSYS) {
243 fprintf(stderr, "leak at symlink (2) of %s: errno was %s\n", path, strerror(errno));
244 exit(1);
245 }
246 }
247
248 void test_readlink(const char *path)
249 {
250 char *dest = alloca(2 * strlen(path));
251
252 if (readlink(path, dest, 2 * strlen(path)) >= 0) {
253 fprintf(stderr, "leak at readlink of %s\n", path);
254 exit(1);
255 }
256 if (errno != ENOENT && errno != ENOSYS) {
257 fprintf(stderr, "leak at readlink of %s: errno was %s\n", path, strerror(errno));
258 exit(1);
259 }
260 }
261
262 void test_chmod(const char *path)
263 {
264 if (chmod(path, 0755) == 0) {
265 fprintf(stderr, "leak at chmod of %s\n", path);
266 exit(1);
267 }
268 if (errno != ENOENT && errno != ENOSYS) {
269 fprintf(stderr, "leak at chmod of %s: errno was %s\n", path, strerror(errno));
270 exit(1);
271 }
272 }
273
274 void test_chown(const char *path)
275 {
276 if (chown(path, 0, 0) == 0) {
277 fprintf(stderr, "leak at chown of %s\n", path);
278 exit(1);
279 }
280 if (errno != ENOENT && errno != ENOSYS) {
281 fprintf(stderr, "leak at chown of %s: errno was %s\n", path, strerror(errno));
282 exit(1);
283 }
284 }
285
286 void test_lchown(const char *path)
287 {
288 if (lchown(path, 0, 0) == 0) {
289 fprintf(stderr, "leak at lchown of %s\n", path);
290 exit(1);
291 }
292 if (errno != ENOENT && errno != ENOSYS) {
293 fprintf(stderr, "leak at lchown of %s: errno was %s\n", path, strerror(errno));
294 exit(1);
295 }
296 }
297
298 void test_mknod(const char *path)
299 {
300 if (mknod(path, 0755, makedev(0, 0)) == 0) {
301 fprintf(stderr, "leak at mknod of %s\n", path);
302 exit(1);
303 }
304 if (errno != ENOENT && errno != ENOSYS) {
305 fprintf(stderr, "leak at mknod of %s: errno was %s\n", path, strerror(errno));
306 exit(1);
307 }
308 }
309
310 void test_chroot(const char *path)
311 {
312 if (chroot(path) == 0) {
313 fprintf(stderr, "leak at chroot of %s\n", path);
314 exit(1);
315 }
316 if (errno != ENOENT && errno != ENOSYS) {
317 fprintf(stderr, "leak at chroot of %s: errno was %s\n", path, strerror(errno));
318 exit(1);
319 }
320 }
321
322 void test_xattrs(const char *path)
323 {
324 /*
325 * might consider doing all of:
326 * setxattr
327 * lsetxattr
328 * getxattr
329 * lgetxattr
330 * listxattr
331 * llistxattr
332 * removexattr
333 * lremovexattr
334 */
335 char value[200];
336 if (getxattr(path, "security.selinux", value, 200) >= 0) {
337 fprintf(stderr, "leak at getxattr of %s\n", path);
338 exit(1);
339 }
340 if (errno != ENOENT && errno != ENOSYS) {
341 fprintf(stderr, "leak at getxattr of %s: errno was %s\n", path, strerror(errno));
342 exit(1);
343 }
344 }
345
346 void test_utimes(const char *path)
347 {
348 struct utimbuf times;
349 times.actime = 0;
350 times.modtime = 0;
351
352 if (utime(path, &times) == 0) {
353 fprintf(stderr, "leak at utime of %s\n", path);
354 exit(1);
355 }
356 if (errno != ENOENT && errno != ENOSYS) {
357 fprintf(stderr, "leak at utime of %s: errno was %s\n", path, strerror(errno));
358 exit(1);
359 }
360 }
361
362 void test_openat(const char *path)
363 {
364 char *d = strdupa(path), *f, *tmpname;
365 int fd, fd2;
366 f = basename(d);
367 d = dirname(d);
368 fd = open(d, O_RDONLY);
369 if (fd < 0) {
370 fprintf(stderr, "Error in openat test: could not open parent dir\n");
371 fprintf(stderr, "(this is expected on the second run)\n");
372 return;
373 }
374 fd2 = openat(fd, f, O_RDONLY);
375 if (fd2 >= 0 || errno != ENOENT) {
376 fprintf(stderr, "leak at openat of %s\n", f);
377 exit(1);
378 }
379 size_t len = strlen(path) + strlen("/cgroup.procs") + 1;
380 tmpname = alloca(len);
381 snprintf(tmpname, len, "%s/cgroup.procs", f);
382 fd2 = openat(fd, tmpname, O_RDONLY);
383 if (fd2 >= 0 || errno != ENOENT) {
384 fprintf(stderr, "leak at openat of %s\n", tmpname);
385 exit(1);
386 }
387 close(fd);
388 }
389
390 int main(int argc, char *argv[])
391 {
392 char *procspath;
393 size_t len;
394
395 if (geteuid() != 0) {
396 fprintf(stderr, "Run me as root\n");
397 exit(1);
398 }
399
400 if (argc != 2) {
401 fprintf(stderr, "Usage: %s [lxcfs_test_cgroup_path]\n", argv[0]);
402 exit(1);
403 }
404
405 /* Try syscalls on the directory and on $directory/cgroup.procs */
406 len = strlen(argv[1]) + strlen("/cgroup.procs") + 1;
407 procspath = alloca(len);
408 snprintf(procspath, len, "%s/cgroup.procs", argv[1]);
409
410 test_open(argv[1]);
411 test_open(procspath);
412 test_stat(argv[1]);
413 test_stat(procspath);
414 test_access(argv[1]);
415 test_access(procspath);
416
417 test_bind(argv[1]);
418 test_bind(procspath);
419 test_bindmount(argv[1]);
420 test_bindmount(procspath);
421 test_truncate(argv[1]);
422 test_truncate(procspath);
423 test_chdir(argv[1]);
424 test_chdir(procspath);
425 test_rename(argv[1]);
426 test_rename(procspath);
427 test_mkdir(argv[1]);
428 test_mkdir(procspath);
429 test_rmdir(argv[1]);
430 test_rmdir(procspath);
431 test_creat(argv[1]);
432 test_creat(procspath);
433 test_link(argv[1]);
434 test_link(procspath);
435 test_unlink(argv[1]);
436 test_unlink(procspath);
437 test_symlink(argv[1]);
438 test_symlink(procspath);
439 test_readlink(argv[1]);
440 test_readlink(procspath);
441 test_chmod(argv[1]);
442 test_chmod(procspath);
443 test_chown(argv[1]);
444 test_chown(procspath);
445 test_lchown(argv[1]);
446 test_lchown(procspath);
447 test_mknod(argv[1]);
448 test_mknod(procspath);
449 test_chroot(argv[1]);
450 test_chroot(procspath);
451 test_xattrs(argv[1]);
452 test_xattrs(procspath);
453 test_utimes(argv[1]);
454 test_utimes(procspath);
455
456 test_openat(argv[1]);
457 // meh... linkat etc?
458
459 printf("All tests passed\n");
460 return 0;
461 }