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