]> git.proxmox.com Git - mirror_lxcfs.git/blame - tests/test_syscalls.c
Merge pull request #474 from brauner/2021-09-01.meson
[mirror_lxcfs.git] / tests / test_syscalls.c
CommitLineData
db0463bf 1/* SPDX-License-Identifier: LGPL-2.1+ */
1f5596dd
CB
2
3#ifndef _GNU_SOURCE
a8b6c3e0 4#define _GNU_SOURCE
1f5596dd
CB
5#endif
6
625e698a 7#include "config.h"
1f5596dd
CB
8
9#include <errno.h>
10#include <fcntl.h>
11#include <libgen.h>
12#include <stddef.h>
13#include <stdint.h>
a8b6c3e0
SH
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
1f5596dd
CB
17#include <sys/mount.h>
18#include <sys/socket.h>
19#include <sys/stat.h>
a95d68e5 20#include <sys/sysmacros.h>
a8b6c3e0 21#include <sys/types.h>
1f5596dd
CB
22#include <sys/types.h>
23#include <sys/un.h>
24#include <sys/xattr.h>
25#include <unistd.h>
a8b6c3e0 26#include <utime.h>
a8b6c3e0
SH
27
28void 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
41void 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
54void 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
66void test_bind(const char *path)
67{
68 int sfd;
51816c7b 69 struct sockaddr_un my_addr;
a8b6c3e0
SH
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
93void 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
101void 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
109void 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
117void 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
131void 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
155void 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
171void 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
183void 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
210void 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
222void 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
248void 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
262void 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
274void 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
286void 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
298void 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
310void 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
322void 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
346void 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
362void 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
390int 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}