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