]> git.proxmox.com Git - mirror_lxcfs.git/blob - bindings.c
Merge pull request #145 from brauner/2016-09-04/lxcfs_on_ramfs
[mirror_lxcfs.git] / bindings.c
1 /* lxcfs
2 *
3 * Copyright © 2014-2016 Canonical, Inc
4 * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
5 *
6 * See COPYING file for details.
7 */
8
9 #define FUSE_USE_VERSION 26
10
11 #include <dirent.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <fuse.h>
15 #include <libgen.h>
16 #include <pthread.h>
17 #include <sched.h>
18 #include <stdbool.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <wait.h>
25 #include <linux/magic.h>
26 #include <linux/sched.h>
27 #include <sys/epoll.h>
28 #include <sys/mman.h>
29 #include <sys/mount.h>
30 #include <sys/param.h>
31 #include <sys/socket.h>
32 #include <sys/syscall.h>
33 #include <sys/vfs.h>
34
35 #include "bindings.h"
36 #include "config.h" // for VERSION
37
38 /* Define pivot_root() if missing from the C library */
39 #ifndef HAVE_PIVOT_ROOT
40 static int pivot_root(const char * new_root, const char * put_old)
41 {
42 #ifdef __NR_pivot_root
43 return syscall(__NR_pivot_root, new_root, put_old);
44 #else
45 errno = ENOSYS;
46 return -1;
47 #endif
48 }
49 #else
50 extern int pivot_root(const char * new_root, const char * put_old);
51 #endif
52
53 enum {
54 LXC_TYPE_CGDIR,
55 LXC_TYPE_CGFILE,
56 LXC_TYPE_PROC_MEMINFO,
57 LXC_TYPE_PROC_CPUINFO,
58 LXC_TYPE_PROC_UPTIME,
59 LXC_TYPE_PROC_STAT,
60 LXC_TYPE_PROC_DISKSTATS,
61 LXC_TYPE_PROC_SWAPS,
62 };
63
64 struct file_info {
65 char *controller;
66 char *cgroup;
67 char *file;
68 int type;
69 char *buf; // unused as of yet
70 int buflen;
71 int size; //actual data size
72 int cached;
73 };
74
75 /* reserve buffer size, for cpuall in /proc/stat */
76 #define BUF_RESERVE_SIZE 256
77
78 /*
79 * A table caching which pid is init for a pid namespace.
80 * When looking up which pid is init for $qpid, we first
81 * 1. Stat /proc/$qpid/ns/pid.
82 * 2. Check whether the ino_t is in our store.
83 * a. if not, fork a child in qpid's ns to send us
84 * ucred.pid = 1, and read the initpid. Cache
85 * initpid and creation time for /proc/initpid
86 * in a new store entry.
87 * b. if so, verify that /proc/initpid still matches
88 * what we have saved. If not, clear the store
89 * entry and go back to a. If so, return the
90 * cached initpid.
91 */
92 struct pidns_init_store {
93 ino_t ino; // inode number for /proc/$pid/ns/pid
94 pid_t initpid; // the pid of nit in that ns
95 long int ctime; // the time at which /proc/$initpid was created
96 struct pidns_init_store *next;
97 long int lastcheck;
98 };
99
100 /* lol - look at how they are allocated in the kernel */
101 #define PIDNS_HASH_SIZE 4096
102 #define HASH(x) ((x) % PIDNS_HASH_SIZE)
103
104 static struct pidns_init_store *pidns_hash_table[PIDNS_HASH_SIZE];
105 static pthread_mutex_t pidns_store_mutex = PTHREAD_MUTEX_INITIALIZER;
106 static void lock_mutex(pthread_mutex_t *l)
107 {
108 int ret;
109
110 if ((ret = pthread_mutex_lock(l)) != 0) {
111 lxcfs_error("returned:%d %s\n", ret, strerror(ret));
112 exit(1);
113 }
114 }
115
116 /* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run.
117 * Number of hierarchies mounted. */
118 static int num_hierarchies;
119
120 /* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run.
121 * Hierachies mounted {cpuset, blkio, ...}:
122 * Initialized via __constructor__ collect_and_mount_subsystems(). */
123 static char **hierarchies;
124
125 /* READ-ONLY after __constructor__ collect_and_mount_subsystems() has run.
126 * Open file descriptors:
127 * @fd_hierarchies[i] refers to cgroup @hierarchies[i]. They are mounted in a
128 * private mount namespace.
129 * Initialized via __constructor__ collect_and_mount_subsystems().
130 * @fd_hierarchies[i] can be used to perform file operations on the cgroup
131 * mounts and respective files in the private namespace even when located in
132 * another namespace using the *at() family of functions
133 * {openat(), fchownat(), ...}. */
134 static int *fd_hierarchies;
135
136 static void unlock_mutex(pthread_mutex_t *l)
137 {
138 int ret;
139
140 if ((ret = pthread_mutex_unlock(l)) != 0) {
141 lxcfs_error("returned:%d %s\n", ret, strerror(ret));
142 exit(1);
143 }
144 }
145
146 static void store_lock(void)
147 {
148 lock_mutex(&pidns_store_mutex);
149 }
150
151 static void store_unlock(void)
152 {
153 unlock_mutex(&pidns_store_mutex);
154 }
155
156 /* Must be called under store_lock */
157 static bool initpid_still_valid(struct pidns_init_store *e, struct stat *nsfdsb)
158 {
159 struct stat initsb;
160 char fnam[100];
161
162 snprintf(fnam, 100, "/proc/%d", e->initpid);
163 if (stat(fnam, &initsb) < 0)
164 return false;
165
166 lxcfs_debug("Comparing ctime %ld == %ld for pid %d.\n", e->ctime,
167 initsb.st_ctime, e->initpid);
168
169 if (e->ctime != initsb.st_ctime)
170 return false;
171 return true;
172 }
173
174 /* Must be called under store_lock */
175 static void remove_initpid(struct pidns_init_store *e)
176 {
177 struct pidns_init_store *tmp;
178 int h;
179
180 lxcfs_debug("Remove_initpid: removing entry for %d.\n", e->initpid);
181
182 h = HASH(e->ino);
183 if (pidns_hash_table[h] == e) {
184 pidns_hash_table[h] = e->next;
185 free(e);
186 return;
187 }
188
189 tmp = pidns_hash_table[h];
190 while (tmp) {
191 if (tmp->next == e) {
192 tmp->next = e->next;
193 free(e);
194 return;
195 }
196 tmp = tmp->next;
197 }
198 }
199
200 #define PURGE_SECS 5
201 /* Must be called under store_lock */
202 static void prune_initpid_store(void)
203 {
204 static long int last_prune = 0;
205 struct pidns_init_store *e, *prev, *delme;
206 long int now, threshold;
207 int i;
208
209 if (!last_prune) {
210 last_prune = time(NULL);
211 return;
212 }
213 now = time(NULL);
214 if (now < last_prune + PURGE_SECS)
215 return;
216
217 lxcfs_debug("%s\n", "Pruning.");
218
219 last_prune = now;
220 threshold = now - 2 * PURGE_SECS;
221
222 for (i = 0; i < PIDNS_HASH_SIZE; i++) {
223 for (prev = NULL, e = pidns_hash_table[i]; e; ) {
224 if (e->lastcheck < threshold) {
225
226 lxcfs_debug("Removing cached entry for %d.\n", e->initpid);
227
228 delme = e;
229 if (prev)
230 prev->next = e->next;
231 else
232 pidns_hash_table[i] = e->next;
233 e = e->next;
234 free(delme);
235 } else {
236 prev = e;
237 e = e->next;
238 }
239 }
240 }
241 }
242
243 /* Must be called under store_lock */
244 static void save_initpid(struct stat *sb, pid_t pid)
245 {
246 struct pidns_init_store *e;
247 char fpath[100];
248 struct stat procsb;
249 int h;
250
251 lxcfs_debug("Save_initpid: adding entry for %d.\n", pid);
252
253 snprintf(fpath, 100, "/proc/%d", pid);
254 if (stat(fpath, &procsb) < 0)
255 return;
256 do {
257 e = malloc(sizeof(*e));
258 } while (!e);
259 e->ino = sb->st_ino;
260 e->initpid = pid;
261 e->ctime = procsb.st_ctime;
262 h = HASH(e->ino);
263 e->next = pidns_hash_table[h];
264 e->lastcheck = time(NULL);
265 pidns_hash_table[h] = e;
266 }
267
268 /*
269 * Given the stat(2) info for a nsfd pid inode, lookup the init_pid_store
270 * entry for the inode number and creation time. Verify that the init pid
271 * is still valid. If not, remove it. Return the entry if valid, NULL
272 * otherwise.
273 * Must be called under store_lock
274 */
275 static struct pidns_init_store *lookup_verify_initpid(struct stat *sb)
276 {
277 int h = HASH(sb->st_ino);
278 struct pidns_init_store *e = pidns_hash_table[h];
279
280 while (e) {
281 if (e->ino == sb->st_ino) {
282 if (initpid_still_valid(e, sb)) {
283 e->lastcheck = time(NULL);
284 return e;
285 }
286 remove_initpid(e);
287 return NULL;
288 }
289 e = e->next;
290 }
291
292 return NULL;
293 }
294
295 static int is_dir(const char *path, int fd)
296 {
297 struct stat statbuf;
298 int ret = fstatat(fd, path, &statbuf, fd);
299 if (ret == 0 && S_ISDIR(statbuf.st_mode))
300 return 1;
301 return 0;
302 }
303
304 static char *must_copy_string(const char *str)
305 {
306 char *dup = NULL;
307 if (!str)
308 return NULL;
309 do {
310 dup = strdup(str);
311 } while (!dup);
312
313 return dup;
314 }
315
316 static inline void drop_trailing_newlines(char *s)
317 {
318 int l;
319
320 for (l=strlen(s); l>0 && s[l-1] == '\n'; l--)
321 s[l-1] = '\0';
322 }
323
324 #define BATCH_SIZE 50
325 static void dorealloc(char **mem, size_t oldlen, size_t newlen)
326 {
327 int newbatches = (newlen / BATCH_SIZE) + 1;
328 int oldbatches = (oldlen / BATCH_SIZE) + 1;
329
330 if (!*mem || newbatches > oldbatches) {
331 char *tmp;
332 do {
333 tmp = realloc(*mem, newbatches * BATCH_SIZE);
334 } while (!tmp);
335 *mem = tmp;
336 }
337 }
338 static void append_line(char **contents, size_t *len, char *line, ssize_t linelen)
339 {
340 size_t newlen = *len + linelen;
341 dorealloc(contents, *len, newlen + 1);
342 memcpy(*contents + *len, line, linelen+1);
343 *len = newlen;
344 }
345
346 static char *slurp_file(const char *from, int fd)
347 {
348 char *line = NULL;
349 char *contents = NULL;
350 FILE *f = fdopen(fd, "r");
351 size_t len = 0, fulllen = 0;
352 ssize_t linelen;
353
354 if (!f)
355 return NULL;
356
357 while ((linelen = getline(&line, &len, f)) != -1) {
358 append_line(&contents, &fulllen, line, linelen);
359 }
360 fclose(f);
361
362 if (contents)
363 drop_trailing_newlines(contents);
364 free(line);
365 return contents;
366 }
367
368 static bool write_string(const char *fnam, const char *string, int fd)
369 {
370 FILE *f;
371 size_t len, ret;
372
373 if (!(f = fdopen(fd, "w")))
374 return false;
375 len = strlen(string);
376 ret = fwrite(string, 1, len, f);
377 if (ret != len) {
378 lxcfs_error("Error writing to file: %s\n", strerror(errno));
379 fclose(f);
380 return false;
381 }
382 if (fclose(f) < 0) {
383 lxcfs_error("Error writing to file: %s\n", strerror(errno));
384 return false;
385 }
386 return true;
387 }
388
389 struct cgfs_files {
390 char *name;
391 uint32_t uid, gid;
392 uint32_t mode;
393 };
394
395 #define ALLOC_NUM 20
396 static bool store_hierarchy(char *stridx, char *h)
397 {
398 if (num_hierarchies % ALLOC_NUM == 0) {
399 size_t n = (num_hierarchies / ALLOC_NUM) + 1;
400 n *= ALLOC_NUM;
401 char **tmp = realloc(hierarchies, n * sizeof(char *));
402 if (!tmp) {
403 lxcfs_error("%s\n", strerror(errno));
404 exit(1);
405 }
406 hierarchies = tmp;
407 }
408
409 hierarchies[num_hierarchies++] = must_copy_string(h);
410 return true;
411 }
412
413 static void print_subsystems(void)
414 {
415 int i;
416
417 fprintf(stderr, "hierarchies:\n");
418 for (i = 0; i < num_hierarchies; i++) {
419 if (hierarchies[i])
420 fprintf(stderr, " %2d: fd: %3d: %s\n", i,
421 fd_hierarchies[i], hierarchies[i]);
422 }
423 }
424
425 static bool in_comma_list(const char *needle, const char *haystack)
426 {
427 const char *s = haystack, *e;
428 size_t nlen = strlen(needle);
429
430 while (*s && (e = strchr(s, ','))) {
431 if (nlen != e - s) {
432 s = e + 1;
433 continue;
434 }
435 if (strncmp(needle, s, nlen) == 0)
436 return true;
437 s = e + 1;
438 }
439 if (strcmp(needle, s) == 0)
440 return true;
441 return false;
442 }
443
444 /* do we need to do any massaging here? I'm not sure... */
445 /* Return the mounted controller and store the corresponding open file descriptor
446 * referring to the controller mountpoint in the private lxcfs namespace in
447 * @cfd.
448 */
449 static char *find_mounted_controller(const char *controller, int *cfd)
450 {
451 int i;
452
453 for (i = 0; i < num_hierarchies; i++) {
454 if (!hierarchies[i])
455 continue;
456 if (strcmp(hierarchies[i], controller) == 0) {
457 *cfd = fd_hierarchies[i];
458 return hierarchies[i];
459 }
460 if (in_comma_list(controller, hierarchies[i])) {
461 *cfd = fd_hierarchies[i];
462 return hierarchies[i];
463 }
464 }
465
466 return NULL;
467 }
468
469 bool cgfs_set_value(const char *controller, const char *cgroup, const char *file,
470 const char *value)
471 {
472 int ret, fd, cfd;
473 size_t len;
474 char *fnam, *tmpc;
475
476 tmpc = find_mounted_controller(controller, &cfd);
477 if (!tmpc)
478 return false;
479
480 /* Make sure we pass a relative path to *at() family of functions.
481 * . + /cgroup + / + file + \0
482 */
483 len = strlen(cgroup) + strlen(file) + 3;
484 fnam = alloca(len);
485 ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file);
486 if (ret < 0 || (size_t)ret >= len)
487 return false;
488
489 fd = openat(cfd, fnam, O_WRONLY);
490 if (fd < 0)
491 return false;
492
493 return write_string(fnam, value, fd);
494 }
495
496 // Chown all the files in the cgroup directory. We do this when we create
497 // a cgroup on behalf of a user.
498 static void chown_all_cgroup_files(const char *dirname, uid_t uid, gid_t gid, int fd)
499 {
500 struct dirent *direntp;
501 char path[MAXPATHLEN];
502 size_t len;
503 DIR *d;
504 int fd1, ret;
505
506 len = strlen(dirname);
507 if (len >= MAXPATHLEN) {
508 lxcfs_error("Pathname too long: %s\n", dirname);
509 return;
510 }
511
512 fd1 = openat(fd, dirname, O_DIRECTORY);
513 if (fd1 < 0)
514 return;
515
516 d = fdopendir(fd1);
517 if (!d) {
518 lxcfs_error("Failed to open %s\n", dirname);
519 return;
520 }
521
522 while ((direntp = readdir(d))) {
523 if (!strcmp(direntp->d_name, ".") || !strcmp(direntp->d_name, ".."))
524 continue;
525 ret = snprintf(path, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
526 if (ret < 0 || ret >= MAXPATHLEN) {
527 lxcfs_error("Pathname too long under %s\n", dirname);
528 continue;
529 }
530 if (fchownat(fd, path, uid, gid, 0) < 0)
531 lxcfs_error("Failed to chown file %s to %u:%u", path, uid, gid);
532 }
533 closedir(d);
534 }
535
536 int cgfs_create(const char *controller, const char *cg, uid_t uid, gid_t gid)
537 {
538 int cfd;
539 size_t len;
540 char *dirnam, *tmpc;
541
542 tmpc = find_mounted_controller(controller, &cfd);
543 if (!tmpc)
544 return -EINVAL;
545
546 /* Make sure we pass a relative path to *at() family of functions.
547 * . + /cg + \0
548 */
549 len = strlen(cg) + 2;
550 dirnam = alloca(len);
551 snprintf(dirnam, len, "%s%s", *cg == '/' ? "." : "", cg);
552
553 if (mkdirat(cfd, dirnam, 0755) < 0)
554 return -errno;
555
556 if (uid == 0 && gid == 0)
557 return 0;
558
559 if (fchownat(cfd, dirnam, uid, gid, 0) < 0)
560 return -errno;
561
562 chown_all_cgroup_files(dirnam, uid, gid, cfd);
563
564 return 0;
565 }
566
567 static bool recursive_rmdir(const char *dirname, int fd, const int cfd)
568 {
569 struct dirent *direntp;
570 DIR *dir;
571 bool ret = false;
572 char pathname[MAXPATHLEN];
573 int dupfd;
574
575 dupfd = dup(fd); // fdopendir() does bad things once it uses an fd.
576 if (dupfd < 0)
577 return false;
578
579 dir = fdopendir(dupfd);
580 if (!dir) {
581 lxcfs_debug("Failed to open %s: %s.\n", dirname, strerror(errno));
582 close(dupfd);
583 return false;
584 }
585
586 while ((direntp = readdir(dir))) {
587 struct stat mystat;
588 int rc;
589
590 if (!strcmp(direntp->d_name, ".") ||
591 !strcmp(direntp->d_name, ".."))
592 continue;
593
594 rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
595 if (rc < 0 || rc >= MAXPATHLEN) {
596 lxcfs_error("%s\n", "Pathname too long.");
597 continue;
598 }
599
600 rc = fstatat(cfd, pathname, &mystat, AT_SYMLINK_NOFOLLOW);
601 if (rc) {
602 lxcfs_debug("Failed to stat %s: %s.\n", pathname, strerror(errno));
603 continue;
604 }
605 if (S_ISDIR(mystat.st_mode))
606 if (!recursive_rmdir(pathname, fd, cfd))
607 lxcfs_debug("Error removing %s.\n", pathname);
608 }
609
610 ret = true;
611 if (closedir(dir) < 0) {
612 lxcfs_error("Failed to close directory %s: %s\n", dirname, strerror(errno));
613 ret = false;
614 }
615
616 if (unlinkat(cfd, dirname, AT_REMOVEDIR) < 0) {
617 lxcfs_debug("Failed to delete %s: %s.\n", dirname, strerror(errno));
618 ret = false;
619 }
620
621 close(dupfd);
622
623 return ret;
624 }
625
626 bool cgfs_remove(const char *controller, const char *cg)
627 {
628 int fd, cfd;
629 size_t len;
630 char *dirnam, *tmpc;
631 bool bret;
632
633 tmpc = find_mounted_controller(controller, &cfd);
634 if (!tmpc)
635 return false;
636
637 /* Make sure we pass a relative path to *at() family of functions.
638 * . + /cg + \0
639 */
640 len = strlen(cg) + 2;
641 dirnam = alloca(len);
642 snprintf(dirnam, len, "%s%s", *cg == '/' ? "." : "", cg);
643
644 fd = openat(cfd, dirnam, O_DIRECTORY);
645 if (fd < 0)
646 return false;
647
648 bret = recursive_rmdir(dirnam, fd, cfd);
649 close(fd);
650 return bret;
651 }
652
653 bool cgfs_chmod_file(const char *controller, const char *file, mode_t mode)
654 {
655 int cfd;
656 size_t len;
657 char *pathname, *tmpc;
658
659 tmpc = find_mounted_controller(controller, &cfd);
660 if (!tmpc)
661 return false;
662
663 /* Make sure we pass a relative path to *at() family of functions.
664 * . + /file + \0
665 */
666 len = strlen(file) + 2;
667 pathname = alloca(len);
668 snprintf(pathname, len, "%s%s", *file == '/' ? "." : "", file);
669 if (fchmodat(cfd, pathname, mode, 0) < 0)
670 return false;
671 return true;
672 }
673
674 static int chown_tasks_files(const char *dirname, uid_t uid, gid_t gid, int fd)
675 {
676 size_t len;
677 char *fname;
678
679 len = strlen(dirname) + strlen("/cgroup.procs") + 1;
680 fname = alloca(len);
681 snprintf(fname, len, "%s/tasks", dirname);
682 if (fchownat(fd, fname, uid, gid, 0) != 0)
683 return -errno;
684 snprintf(fname, len, "%s/cgroup.procs", dirname);
685 if (fchownat(fd, fname, uid, gid, 0) != 0)
686 return -errno;
687 return 0;
688 }
689
690 int cgfs_chown_file(const char *controller, const char *file, uid_t uid, gid_t gid)
691 {
692 int cfd;
693 size_t len;
694 char *pathname, *tmpc;
695
696 tmpc = find_mounted_controller(controller, &cfd);
697 if (!tmpc)
698 return -EINVAL;
699
700 /* Make sure we pass a relative path to *at() family of functions.
701 * . + /file + \0
702 */
703 len = strlen(file) + 2;
704 pathname = alloca(len);
705 snprintf(pathname, len, "%s%s", *file == '/' ? "." : "", file);
706 if (fchownat(cfd, pathname, uid, gid, 0) < 0)
707 return -errno;
708
709 if (is_dir(pathname, cfd))
710 // like cgmanager did, we want to chown the tasks file as well
711 return chown_tasks_files(pathname, uid, gid, cfd);
712
713 return 0;
714 }
715
716 FILE *open_pids_file(const char *controller, const char *cgroup)
717 {
718 int fd, cfd;
719 size_t len;
720 char *pathname, *tmpc;
721
722 tmpc = find_mounted_controller(controller, &cfd);
723 if (!tmpc)
724 return NULL;
725
726 /* Make sure we pass a relative path to *at() family of functions.
727 * . + /cgroup + / "cgroup.procs" + \0
728 */
729 len = strlen(cgroup) + strlen("cgroup.procs") + 3;
730 pathname = alloca(len);
731 snprintf(pathname, len, "%s%s/cgroup.procs", *cgroup == '/' ? "." : "", cgroup);
732
733 fd = openat(cfd, pathname, O_WRONLY);
734 if (fd < 0)
735 return NULL;
736
737 return fdopen(fd, "w");
738 }
739
740 static bool cgfs_iterate_cgroup(const char *controller, const char *cgroup, bool directories,
741 void ***list, size_t typesize,
742 void* (*iterator)(const char*, const char*, const char*))
743 {
744 int cfd, fd, ret;
745 size_t len;
746 char *cg, *tmpc;
747 char pathname[MAXPATHLEN];
748 size_t sz = 0, asz = 0;
749 struct dirent *dirent;
750 DIR *dir;
751
752 tmpc = find_mounted_controller(controller, &cfd);
753 *list = NULL;
754 if (!tmpc)
755 return false;
756
757 /* Make sure we pass a relative path to *at() family of functions. */
758 len = strlen(cgroup) + 1 /* . */ + 1 /* \0 */;
759 cg = alloca(len);
760 ret = snprintf(cg, len, "%s%s", *cgroup == '/' ? "." : "", cgroup);
761 if (ret < 0 || (size_t)ret >= len) {
762 lxcfs_error("Pathname too long under %s\n", cgroup);
763 return false;
764 }
765
766 fd = openat(cfd, cg, O_DIRECTORY);
767 if (fd < 0)
768 return false;
769
770 dir = fdopendir(fd);
771 if (!dir)
772 return false;
773
774 while ((dirent = readdir(dir))) {
775 struct stat mystat;
776
777 if (!strcmp(dirent->d_name, ".") ||
778 !strcmp(dirent->d_name, ".."))
779 continue;
780
781 ret = snprintf(pathname, MAXPATHLEN, "%s/%s", cg, dirent->d_name);
782 if (ret < 0 || ret >= MAXPATHLEN) {
783 lxcfs_error("Pathname too long under %s\n", cg);
784 continue;
785 }
786
787 ret = fstatat(cfd, pathname, &mystat, AT_SYMLINK_NOFOLLOW);
788 if (ret) {
789 lxcfs_error("Failed to stat %s: %s\n", pathname, strerror(errno));
790 continue;
791 }
792 if ((!directories && !S_ISREG(mystat.st_mode)) ||
793 (directories && !S_ISDIR(mystat.st_mode)))
794 continue;
795
796 if (sz+2 >= asz) {
797 void **tmp;
798 asz += BATCH_SIZE;
799 do {
800 tmp = realloc(*list, asz * typesize);
801 } while (!tmp);
802 *list = tmp;
803 }
804 (*list)[sz] = (*iterator)(controller, cg, dirent->d_name);
805 (*list)[sz+1] = NULL;
806 sz++;
807 }
808 if (closedir(dir) < 0) {
809 lxcfs_error("Failed closedir for %s: %s\n", cgroup, strerror(errno));
810 return false;
811 }
812 return true;
813 }
814
815 static void *make_children_list_entry(const char *controller, const char *cgroup, const char *dir_entry)
816 {
817 char *dup;
818 do {
819 dup = strdup(dir_entry);
820 } while (!dup);
821 return dup;
822 }
823
824 bool cgfs_list_children(const char *controller, const char *cgroup, char ***list)
825 {
826 return cgfs_iterate_cgroup(controller, cgroup, true, (void***)list, sizeof(*list), &make_children_list_entry);
827 }
828
829 void free_key(struct cgfs_files *k)
830 {
831 if (!k)
832 return;
833 free(k->name);
834 free(k);
835 }
836
837 void free_keys(struct cgfs_files **keys)
838 {
839 int i;
840
841 if (!keys)
842 return;
843 for (i = 0; keys[i]; i++) {
844 free_key(keys[i]);
845 }
846 free(keys);
847 }
848
849 bool cgfs_get_value(const char *controller, const char *cgroup, const char *file, char **value)
850 {
851 int ret, fd, cfd;
852 size_t len;
853 char *fnam, *tmpc;
854
855 tmpc = find_mounted_controller(controller, &cfd);
856 if (!tmpc)
857 return false;
858
859 /* Make sure we pass a relative path to *at() family of functions.
860 * . + /cgroup + / + file + \0
861 */
862 len = strlen(cgroup) + strlen(file) + 3;
863 fnam = alloca(len);
864 ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, file);
865 if (ret < 0 || (size_t)ret >= len)
866 return NULL;
867
868 fd = openat(cfd, fnam, O_RDONLY);
869 if (fd < 0)
870 return NULL;
871
872 *value = slurp_file(fnam, fd);
873 return *value != NULL;
874 }
875
876 struct cgfs_files *cgfs_get_key(const char *controller, const char *cgroup, const char *file)
877 {
878 int ret, cfd;
879 size_t len;
880 char *fnam, *tmpc;
881 struct stat sb;
882 struct cgfs_files *newkey;
883
884 tmpc = find_mounted_controller(controller, &cfd);
885 if (!tmpc)
886 return false;
887
888 if (file && *file == '/')
889 file++;
890
891 if (file && strchr(file, '/'))
892 return NULL;
893
894 /* Make sure we pass a relative path to *at() family of functions.
895 * . + /cgroup + / + file + \0
896 */
897 len = strlen(cgroup) + 3;
898 if (file)
899 len += strlen(file) + 1;
900 fnam = alloca(len);
901 snprintf(fnam, len, "%s%s%s%s", *cgroup == '/' ? "." : "", cgroup,
902 file ? "/" : "", file ? file : "");
903
904 ret = fstatat(cfd, fnam, &sb, 0);
905 if (ret < 0)
906 return NULL;
907
908 do {
909 newkey = malloc(sizeof(struct cgfs_files));
910 } while (!newkey);
911 if (file)
912 newkey->name = must_copy_string(file);
913 else if (strrchr(cgroup, '/'))
914 newkey->name = must_copy_string(strrchr(cgroup, '/'));
915 else
916 newkey->name = must_copy_string(cgroup);
917 newkey->uid = sb.st_uid;
918 newkey->gid = sb.st_gid;
919 newkey->mode = sb.st_mode;
920
921 return newkey;
922 }
923
924 static void *make_key_list_entry(const char *controller, const char *cgroup, const char *dir_entry)
925 {
926 struct cgfs_files *entry = cgfs_get_key(controller, cgroup, dir_entry);
927 if (!entry) {
928 lxcfs_error("Error getting files under %s:%s\n", controller,
929 cgroup);
930 }
931 return entry;
932 }
933
934 bool cgfs_list_keys(const char *controller, const char *cgroup, struct cgfs_files ***keys)
935 {
936 return cgfs_iterate_cgroup(controller, cgroup, false, (void***)keys, sizeof(*keys), &make_key_list_entry);
937 }
938
939 bool is_child_cgroup(const char *controller, const char *cgroup, const char *f)
940 {
941 int cfd;
942 size_t len;
943 char *fnam, *tmpc;
944 int ret;
945 struct stat sb;
946
947 tmpc = find_mounted_controller(controller, &cfd);
948 if (!tmpc)
949 return false;
950
951 /* Make sure we pass a relative path to *at() family of functions.
952 * . + /cgroup + / + f + \0
953 */
954 len = strlen(cgroup) + strlen(f) + 3;
955 fnam = alloca(len);
956 ret = snprintf(fnam, len, "%s%s/%s", *cgroup == '/' ? "." : "", cgroup, f);
957 if (ret < 0 || (size_t)ret >= len)
958 return false;
959
960 ret = fstatat(cfd, fnam, &sb, 0);
961 if (ret < 0 || !S_ISDIR(sb.st_mode))
962 return false;
963
964 return true;
965 }
966
967 #define SEND_CREDS_OK 0
968 #define SEND_CREDS_NOTSK 1
969 #define SEND_CREDS_FAIL 2
970 static bool recv_creds(int sock, struct ucred *cred, char *v);
971 static int wait_for_pid(pid_t pid);
972 static int send_creds(int sock, struct ucred *cred, char v, bool pingfirst);
973 static int send_creds_clone_wrapper(void *arg);
974
975 /*
976 * clone a task which switches to @task's namespace and writes '1'.
977 * over a unix sock so we can read the task's reaper's pid in our
978 * namespace
979 *
980 * Note: glibc's fork() does not respect pidns, which can lead to failed
981 * assertions inside glibc (and thus failed forks) if the child's pid in
982 * the pidns and the parent pid outside are identical. Using clone prevents
983 * this issue.
984 */
985 static void write_task_init_pid_exit(int sock, pid_t target)
986 {
987 char fnam[100];
988 pid_t pid;
989 int fd, ret;
990 size_t stack_size = sysconf(_SC_PAGESIZE);
991 void *stack = alloca(stack_size);
992
993 ret = snprintf(fnam, sizeof(fnam), "/proc/%d/ns/pid", (int)target);
994 if (ret < 0 || ret >= sizeof(fnam))
995 _exit(1);
996
997 fd = open(fnam, O_RDONLY);
998 if (fd < 0) {
999 perror("write_task_init_pid_exit open of ns/pid");
1000 _exit(1);
1001 }
1002 if (setns(fd, 0)) {
1003 perror("write_task_init_pid_exit setns 1");
1004 close(fd);
1005 _exit(1);
1006 }
1007 pid = clone(send_creds_clone_wrapper, stack + stack_size, SIGCHLD, &sock);
1008 if (pid < 0)
1009 _exit(1);
1010 if (pid != 0) {
1011 if (!wait_for_pid(pid))
1012 _exit(1);
1013 _exit(0);
1014 }
1015 }
1016
1017 static int send_creds_clone_wrapper(void *arg) {
1018 struct ucred cred;
1019 char v;
1020 int sock = *(int *)arg;
1021
1022 /* we are the child */
1023 cred.uid = 0;
1024 cred.gid = 0;
1025 cred.pid = 1;
1026 v = '1';
1027 if (send_creds(sock, &cred, v, true) != SEND_CREDS_OK)
1028 return 1;
1029 return 0;
1030 }
1031
1032 static pid_t get_init_pid_for_task(pid_t task)
1033 {
1034 int sock[2];
1035 pid_t pid;
1036 pid_t ret = -1;
1037 char v = '0';
1038 struct ucred cred;
1039
1040 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) {
1041 perror("socketpair");
1042 return -1;
1043 }
1044
1045 pid = fork();
1046 if (pid < 0)
1047 goto out;
1048 if (!pid) {
1049 close(sock[1]);
1050 write_task_init_pid_exit(sock[0], task);
1051 _exit(0);
1052 }
1053
1054 if (!recv_creds(sock[1], &cred, &v))
1055 goto out;
1056 ret = cred.pid;
1057
1058 out:
1059 close(sock[0]);
1060 close(sock[1]);
1061 if (pid > 0)
1062 wait_for_pid(pid);
1063 return ret;
1064 }
1065
1066 static pid_t lookup_initpid_in_store(pid_t qpid)
1067 {
1068 pid_t answer = 0;
1069 struct stat sb;
1070 struct pidns_init_store *e;
1071 char fnam[100];
1072
1073 snprintf(fnam, 100, "/proc/%d/ns/pid", qpid);
1074 store_lock();
1075 if (stat(fnam, &sb) < 0)
1076 goto out;
1077 e = lookup_verify_initpid(&sb);
1078 if (e) {
1079 answer = e->initpid;
1080 goto out;
1081 }
1082 answer = get_init_pid_for_task(qpid);
1083 if (answer > 0)
1084 save_initpid(&sb, answer);
1085
1086 out:
1087 /* we prune at end in case we are returning
1088 * the value we were about to return */
1089 prune_initpid_store();
1090 store_unlock();
1091 return answer;
1092 }
1093
1094 static int wait_for_pid(pid_t pid)
1095 {
1096 int status, ret;
1097
1098 if (pid <= 0)
1099 return -1;
1100
1101 again:
1102 ret = waitpid(pid, &status, 0);
1103 if (ret == -1) {
1104 if (errno == EINTR)
1105 goto again;
1106 return -1;
1107 }
1108 if (ret != pid)
1109 goto again;
1110 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
1111 return -1;
1112 return 0;
1113 }
1114
1115
1116 /*
1117 * append pid to *src.
1118 * src: a pointer to a char* in which ot append the pid.
1119 * sz: the number of characters printed so far, minus trailing \0.
1120 * asz: the allocated size so far
1121 * pid: the pid to append
1122 */
1123 static void must_strcat_pid(char **src, size_t *sz, size_t *asz, pid_t pid)
1124 {
1125 char tmp[30];
1126
1127 int tmplen = sprintf(tmp, "%d\n", (int)pid);
1128
1129 if (!*src || tmplen + *sz + 1 >= *asz) {
1130 char *tmp;
1131 do {
1132 tmp = realloc(*src, *asz + BUF_RESERVE_SIZE);
1133 } while (!tmp);
1134 *src = tmp;
1135 *asz += BUF_RESERVE_SIZE;
1136 }
1137 memcpy((*src) +*sz , tmp, tmplen+1); /* include the \0 */
1138 *sz += tmplen;
1139 }
1140
1141 /*
1142 * Given a open file * to /proc/pid/{u,g}id_map, and an id
1143 * valid in the caller's namespace, return the id mapped into
1144 * pid's namespace.
1145 * Returns the mapped id, or -1 on error.
1146 */
1147 unsigned int
1148 convert_id_to_ns(FILE *idfile, unsigned int in_id)
1149 {
1150 unsigned int nsuid, // base id for a range in the idfile's namespace
1151 hostuid, // base id for a range in the caller's namespace
1152 count; // number of ids in this range
1153 char line[400];
1154 int ret;
1155
1156 fseek(idfile, 0L, SEEK_SET);
1157 while (fgets(line, 400, idfile)) {
1158 ret = sscanf(line, "%u %u %u\n", &nsuid, &hostuid, &count);
1159 if (ret != 3)
1160 continue;
1161 if (hostuid + count < hostuid || nsuid + count < nsuid) {
1162 /*
1163 * uids wrapped around - unexpected as this is a procfile,
1164 * so just bail.
1165 */
1166 lxcfs_error("pid wrapparound at entry %u %u %u in %s\n",
1167 nsuid, hostuid, count, line);
1168 return -1;
1169 }
1170 if (hostuid <= in_id && hostuid+count > in_id) {
1171 /*
1172 * now since hostuid <= in_id < hostuid+count, and
1173 * hostuid+count and nsuid+count do not wrap around,
1174 * we know that nsuid+(in_id-hostuid) which must be
1175 * less that nsuid+(count) must not wrap around
1176 */
1177 return (in_id - hostuid) + nsuid;
1178 }
1179 }
1180
1181 // no answer found
1182 return -1;
1183 }
1184
1185 /*
1186 * for is_privileged_over,
1187 * specify whether we require the calling uid to be root in his
1188 * namespace
1189 */
1190 #define NS_ROOT_REQD true
1191 #define NS_ROOT_OPT false
1192
1193 #define PROCLEN 100
1194
1195 static bool is_privileged_over(pid_t pid, uid_t uid, uid_t victim, bool req_ns_root)
1196 {
1197 char fpath[PROCLEN];
1198 int ret;
1199 bool answer = false;
1200 uid_t nsuid;
1201
1202 if (victim == -1 || uid == -1)
1203 return false;
1204
1205 /*
1206 * If the request is one not requiring root in the namespace,
1207 * then having the same uid suffices. (i.e. uid 1000 has write
1208 * access to files owned by uid 1000
1209 */
1210 if (!req_ns_root && uid == victim)
1211 return true;
1212
1213 ret = snprintf(fpath, PROCLEN, "/proc/%d/uid_map", pid);
1214 if (ret < 0 || ret >= PROCLEN)
1215 return false;
1216 FILE *f = fopen(fpath, "r");
1217 if (!f)
1218 return false;
1219
1220 /* if caller's not root in his namespace, reject */
1221 nsuid = convert_id_to_ns(f, uid);
1222 if (nsuid)
1223 goto out;
1224
1225 /*
1226 * If victim is not mapped into caller's ns, reject.
1227 * XXX I'm not sure this check is needed given that fuse
1228 * will be sending requests where the vfs has converted
1229 */
1230 nsuid = convert_id_to_ns(f, victim);
1231 if (nsuid == -1)
1232 goto out;
1233
1234 answer = true;
1235
1236 out:
1237 fclose(f);
1238 return answer;
1239 }
1240
1241 static bool perms_include(int fmode, mode_t req_mode)
1242 {
1243 mode_t r;
1244
1245 switch (req_mode & O_ACCMODE) {
1246 case O_RDONLY:
1247 r = S_IROTH;
1248 break;
1249 case O_WRONLY:
1250 r = S_IWOTH;
1251 break;
1252 case O_RDWR:
1253 r = S_IROTH | S_IWOTH;
1254 break;
1255 default:
1256 return false;
1257 }
1258 return ((fmode & r) == r);
1259 }
1260
1261
1262 /*
1263 * taskcg is a/b/c
1264 * querycg is /a/b/c/d/e
1265 * we return 'd'
1266 */
1267 static char *get_next_cgroup_dir(const char *taskcg, const char *querycg)
1268 {
1269 char *start, *end;
1270
1271 if (strlen(taskcg) <= strlen(querycg)) {
1272 lxcfs_error("%s\n", "I was fed bad input.");
1273 return NULL;
1274 }
1275
1276 if ((strcmp(querycg, "/") == 0) || (strcmp(querycg, "./") == 0))
1277 start = strdup(taskcg + 1);
1278 else
1279 start = strdup(taskcg + strlen(querycg) + 1);
1280 if (!start)
1281 return NULL;
1282 end = strchr(start, '/');
1283 if (end)
1284 *end = '\0';
1285 return start;
1286 }
1287
1288 static void stripnewline(char *x)
1289 {
1290 size_t l = strlen(x);
1291 if (l && x[l-1] == '\n')
1292 x[l-1] = '\0';
1293 }
1294
1295 static char *get_pid_cgroup(pid_t pid, const char *contrl)
1296 {
1297 int cfd;
1298 char fnam[PROCLEN];
1299 FILE *f;
1300 char *answer = NULL;
1301 char *line = NULL;
1302 size_t len = 0;
1303 int ret;
1304 const char *h = find_mounted_controller(contrl, &cfd);
1305 if (!h)
1306 return NULL;
1307
1308 ret = snprintf(fnam, PROCLEN, "/proc/%d/cgroup", pid);
1309 if (ret < 0 || ret >= PROCLEN)
1310 return NULL;
1311 if (!(f = fopen(fnam, "r")))
1312 return NULL;
1313
1314 while (getline(&line, &len, f) != -1) {
1315 char *c1, *c2;
1316 if (!line[0])
1317 continue;
1318 c1 = strchr(line, ':');
1319 if (!c1)
1320 goto out;
1321 c1++;
1322 c2 = strchr(c1, ':');
1323 if (!c2)
1324 goto out;
1325 *c2 = '\0';
1326 if (strcmp(c1, h) != 0)
1327 continue;
1328 c2++;
1329 stripnewline(c2);
1330 do {
1331 answer = strdup(c2);
1332 } while (!answer);
1333 break;
1334 }
1335
1336 out:
1337 fclose(f);
1338 free(line);
1339 return answer;
1340 }
1341
1342 /*
1343 * check whether a fuse context may access a cgroup dir or file
1344 *
1345 * If file is not null, it is a cgroup file to check under cg.
1346 * If file is null, then we are checking perms on cg itself.
1347 *
1348 * For files we can check the mode of the list_keys result.
1349 * For cgroups, we must make assumptions based on the files under the
1350 * cgroup, because cgmanager doesn't tell us ownership/perms of cgroups
1351 * yet.
1352 */
1353 static bool fc_may_access(struct fuse_context *fc, const char *contrl, const char *cg, const char *file, mode_t mode)
1354 {
1355 struct cgfs_files *k = NULL;
1356 bool ret = false;
1357
1358 k = cgfs_get_key(contrl, cg, file);
1359 if (!k)
1360 return false;
1361
1362 if (is_privileged_over(fc->pid, fc->uid, k->uid, NS_ROOT_OPT)) {
1363 if (perms_include(k->mode >> 6, mode)) {
1364 ret = true;
1365 goto out;
1366 }
1367 }
1368 if (fc->gid == k->gid) {
1369 if (perms_include(k->mode >> 3, mode)) {
1370 ret = true;
1371 goto out;
1372 }
1373 }
1374 ret = perms_include(k->mode, mode);
1375
1376 out:
1377 free_key(k);
1378 return ret;
1379 }
1380
1381 #define INITSCOPE "/init.scope"
1382 static void prune_init_slice(char *cg)
1383 {
1384 char *point;
1385 size_t cg_len = strlen(cg), initscope_len = strlen(INITSCOPE);
1386
1387 if (cg_len < initscope_len)
1388 return;
1389
1390 point = cg + cg_len - initscope_len;
1391 if (strcmp(point, INITSCOPE) == 0) {
1392 if (point == cg)
1393 *(point+1) = '\0';
1394 else
1395 *point = '\0';
1396 }
1397 }
1398
1399 /*
1400 * If pid is in /a/b/c/d, he may only act on things under cg=/a/b/c/d.
1401 * If pid is in /a, he may act on /a/b, but not on /b.
1402 * if the answer is false and nextcg is not NULL, then *nextcg will point
1403 * to a string containing the next cgroup directory under cg, which must be
1404 * freed by the caller.
1405 */
1406 static bool caller_is_in_ancestor(pid_t pid, const char *contrl, const char *cg, char **nextcg)
1407 {
1408 bool answer = false;
1409 char *c2 = get_pid_cgroup(pid, contrl);
1410 char *linecmp;
1411
1412 if (!c2)
1413 return false;
1414 prune_init_slice(c2);
1415
1416 /*
1417 * callers pass in '/' or './' (openat()) for root cgroup, otherwise
1418 * they pass in a cgroup without leading '/'
1419 *
1420 * The original line here was:
1421 * linecmp = *cg == '/' ? c2 : c2+1;
1422 * TODO: I'm not sure why you'd want to increment when *cg != '/'?
1423 * Serge, do you know?
1424 */
1425 if (*cg == '/' || !strncmp(cg, "./", 2))
1426 linecmp = c2;
1427 else
1428 linecmp = c2 + 1;
1429 if (strncmp(linecmp, cg, strlen(linecmp)) != 0) {
1430 if (nextcg) {
1431 *nextcg = get_next_cgroup_dir(linecmp, cg);
1432 }
1433 goto out;
1434 }
1435 answer = true;
1436
1437 out:
1438 free(c2);
1439 return answer;
1440 }
1441
1442 /*
1443 * If pid is in /a/b/c, he may see that /a exists, but not /b or /a/c.
1444 */
1445 static bool caller_may_see_dir(pid_t pid, const char *contrl, const char *cg)
1446 {
1447 bool answer = false;
1448 char *c2, *task_cg;
1449 size_t target_len, task_len;
1450
1451 if (strcmp(cg, "/") == 0 || strcmp(cg, "./") == 0)
1452 return true;
1453
1454 c2 = get_pid_cgroup(pid, contrl);
1455 if (!c2)
1456 return false;
1457 prune_init_slice(c2);
1458
1459 task_cg = c2 + 1;
1460 target_len = strlen(cg);
1461 task_len = strlen(task_cg);
1462 if (task_len == 0) {
1463 /* Task is in the root cg, it can see everything. This case is
1464 * not handled by the strmcps below, since they test for the
1465 * last /, but that is the first / that we've chopped off
1466 * above.
1467 */
1468 answer = true;
1469 goto out;
1470 }
1471 if (strcmp(cg, task_cg) == 0) {
1472 answer = true;
1473 goto out;
1474 }
1475 if (target_len < task_len) {
1476 /* looking up a parent dir */
1477 if (strncmp(task_cg, cg, target_len) == 0 && task_cg[target_len] == '/')
1478 answer = true;
1479 goto out;
1480 }
1481 if (target_len > task_len) {
1482 /* looking up a child dir */
1483 if (strncmp(task_cg, cg, task_len) == 0 && cg[task_len] == '/')
1484 answer = true;
1485 goto out;
1486 }
1487
1488 out:
1489 free(c2);
1490 return answer;
1491 }
1492
1493 /*
1494 * given /cgroup/freezer/a/b, return "freezer".
1495 * the returned char* should NOT be freed.
1496 */
1497 static char *pick_controller_from_path(struct fuse_context *fc, const char *path)
1498 {
1499 const char *p1;
1500 char *contr, *slash;
1501
1502 if (strlen(path) < 9) {
1503 errno = EACCES;
1504 return NULL;
1505 }
1506 if (*(path + 7) != '/') {
1507 errno = EINVAL;
1508 return NULL;
1509 }
1510 p1 = path + 8;
1511 contr = strdupa(p1);
1512 if (!contr) {
1513 errno = ENOMEM;
1514 return NULL;
1515 }
1516 slash = strstr(contr, "/");
1517 if (slash)
1518 *slash = '\0';
1519
1520 int i;
1521 for (i = 0; i < num_hierarchies; i++) {
1522 if (hierarchies[i] && strcmp(hierarchies[i], contr) == 0)
1523 return hierarchies[i];
1524 }
1525 errno = ENOENT;
1526 return NULL;
1527 }
1528
1529 /*
1530 * Find the start of cgroup in /cgroup/controller/the/cgroup/path
1531 * Note that the returned value may include files (keynames) etc
1532 */
1533 static const char *find_cgroup_in_path(const char *path)
1534 {
1535 const char *p1;
1536
1537 if (strlen(path) < 9) {
1538 errno = EACCES;
1539 return NULL;
1540 }
1541 p1 = strstr(path + 8, "/");
1542 if (!p1) {
1543 errno = EINVAL;
1544 return NULL;
1545 }
1546 errno = 0;
1547 return p1 + 1;
1548 }
1549
1550 /*
1551 * split the last path element from the path in @cg.
1552 * @dir is newly allocated and should be freed, @last not
1553 */
1554 static void get_cgdir_and_path(const char *cg, char **dir, char **last)
1555 {
1556 char *p;
1557
1558 do {
1559 *dir = strdup(cg);
1560 } while (!*dir);
1561 *last = strrchr(cg, '/');
1562 if (!*last) {
1563 *last = NULL;
1564 return;
1565 }
1566 p = strrchr(*dir, '/');
1567 *p = '\0';
1568 }
1569
1570 /*
1571 * FUSE ops for /cgroup
1572 */
1573
1574 int cg_getattr(const char *path, struct stat *sb)
1575 {
1576 struct timespec now;
1577 struct fuse_context *fc = fuse_get_context();
1578 char * cgdir = NULL;
1579 char *last = NULL, *path1, *path2;
1580 struct cgfs_files *k = NULL;
1581 const char *cgroup;
1582 const char *controller = NULL;
1583 int ret = -ENOENT;
1584
1585
1586 if (!fc)
1587 return -EIO;
1588
1589 memset(sb, 0, sizeof(struct stat));
1590
1591 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
1592 return -EINVAL;
1593
1594 sb->st_uid = sb->st_gid = 0;
1595 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
1596 sb->st_size = 0;
1597
1598 if (strcmp(path, "/cgroup") == 0) {
1599 sb->st_mode = S_IFDIR | 00755;
1600 sb->st_nlink = 2;
1601 return 0;
1602 }
1603
1604 controller = pick_controller_from_path(fc, path);
1605 if (!controller)
1606 return -errno;
1607 cgroup = find_cgroup_in_path(path);
1608 if (!cgroup) {
1609 /* this is just /cgroup/controller, return it as a dir */
1610 sb->st_mode = S_IFDIR | 00755;
1611 sb->st_nlink = 2;
1612 return 0;
1613 }
1614
1615 get_cgdir_and_path(cgroup, &cgdir, &last);
1616
1617 if (!last) {
1618 path1 = "/";
1619 path2 = cgdir;
1620 } else {
1621 path1 = cgdir;
1622 path2 = last;
1623 }
1624
1625 pid_t initpid = lookup_initpid_in_store(fc->pid);
1626 if (initpid <= 0)
1627 initpid = fc->pid;
1628 /* check that cgcopy is either a child cgroup of cgdir, or listed in its keys.
1629 * Then check that caller's cgroup is under path if last is a child
1630 * cgroup, or cgdir if last is a file */
1631
1632 if (is_child_cgroup(controller, path1, path2)) {
1633 if (!caller_may_see_dir(initpid, controller, cgroup)) {
1634 ret = -ENOENT;
1635 goto out;
1636 }
1637 if (!caller_is_in_ancestor(initpid, controller, cgroup, NULL)) {
1638 /* this is just /cgroup/controller, return it as a dir */
1639 sb->st_mode = S_IFDIR | 00555;
1640 sb->st_nlink = 2;
1641 ret = 0;
1642 goto out;
1643 }
1644 if (!fc_may_access(fc, controller, cgroup, NULL, O_RDONLY)) {
1645 ret = -EACCES;
1646 goto out;
1647 }
1648
1649 // get uid, gid, from '/tasks' file and make up a mode
1650 // That is a hack, until cgmanager gains a GetCgroupPerms fn.
1651 sb->st_mode = S_IFDIR | 00755;
1652 k = cgfs_get_key(controller, cgroup, NULL);
1653 if (!k) {
1654 sb->st_uid = sb->st_gid = 0;
1655 } else {
1656 sb->st_uid = k->uid;
1657 sb->st_gid = k->gid;
1658 }
1659 free_key(k);
1660 sb->st_nlink = 2;
1661 ret = 0;
1662 goto out;
1663 }
1664
1665 if ((k = cgfs_get_key(controller, path1, path2)) != NULL) {
1666 sb->st_mode = S_IFREG | k->mode;
1667 sb->st_nlink = 1;
1668 sb->st_uid = k->uid;
1669 sb->st_gid = k->gid;
1670 sb->st_size = 0;
1671 free_key(k);
1672 if (!caller_is_in_ancestor(initpid, controller, path1, NULL)) {
1673 ret = -ENOENT;
1674 goto out;
1675 }
1676 if (!fc_may_access(fc, controller, path1, path2, O_RDONLY)) {
1677 ret = -EACCES;
1678 goto out;
1679 }
1680
1681 ret = 0;
1682 }
1683
1684 out:
1685 free(cgdir);
1686 return ret;
1687 }
1688
1689 int cg_opendir(const char *path, struct fuse_file_info *fi)
1690 {
1691 struct fuse_context *fc = fuse_get_context();
1692 const char *cgroup;
1693 struct file_info *dir_info;
1694 char *controller = NULL;
1695
1696 if (!fc)
1697 return -EIO;
1698
1699 if (strcmp(path, "/cgroup") == 0) {
1700 cgroup = NULL;
1701 controller = NULL;
1702 } else {
1703 // return list of keys for the controller, and list of child cgroups
1704 controller = pick_controller_from_path(fc, path);
1705 if (!controller)
1706 return -errno;
1707
1708 cgroup = find_cgroup_in_path(path);
1709 if (!cgroup) {
1710 /* this is just /cgroup/controller, return its contents */
1711 cgroup = "/";
1712 }
1713 }
1714
1715 pid_t initpid = lookup_initpid_in_store(fc->pid);
1716 if (initpid <= 0)
1717 initpid = fc->pid;
1718 if (cgroup) {
1719 if (!caller_may_see_dir(initpid, controller, cgroup))
1720 return -ENOENT;
1721 if (!fc_may_access(fc, controller, cgroup, NULL, O_RDONLY))
1722 return -EACCES;
1723 }
1724
1725 /* we'll free this at cg_releasedir */
1726 dir_info = malloc(sizeof(*dir_info));
1727 if (!dir_info)
1728 return -ENOMEM;
1729 dir_info->controller = must_copy_string(controller);
1730 dir_info->cgroup = must_copy_string(cgroup);
1731 dir_info->type = LXC_TYPE_CGDIR;
1732 dir_info->buf = NULL;
1733 dir_info->file = NULL;
1734 dir_info->buflen = 0;
1735
1736 fi->fh = (unsigned long)dir_info;
1737 return 0;
1738 }
1739
1740 int cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
1741 struct fuse_file_info *fi)
1742 {
1743 struct file_info *d = (struct file_info *)fi->fh;
1744 struct cgfs_files **list = NULL;
1745 int i, ret;
1746 char *nextcg = NULL;
1747 struct fuse_context *fc = fuse_get_context();
1748 char **clist = NULL;
1749
1750 if (filler(buf, ".", NULL, 0) != 0 || filler(buf, "..", NULL, 0) != 0)
1751 return -EIO;
1752
1753 if (d->type != LXC_TYPE_CGDIR) {
1754 lxcfs_error("%s\n", "Internal error: file cache info used in readdir.");
1755 return -EIO;
1756 }
1757 if (!d->cgroup && !d->controller) {
1758 // ls /var/lib/lxcfs/cgroup - just show list of controllers
1759 int i;
1760
1761 for (i = 0; i < num_hierarchies; i++) {
1762 if (hierarchies[i] && filler(buf, hierarchies[i], NULL, 0) != 0) {
1763 return -EIO;
1764 }
1765 }
1766 return 0;
1767 }
1768
1769 if (!cgfs_list_keys(d->controller, d->cgroup, &list)) {
1770 // not a valid cgroup
1771 ret = -EINVAL;
1772 goto out;
1773 }
1774
1775 pid_t initpid = lookup_initpid_in_store(fc->pid);
1776 if (initpid <= 0)
1777 initpid = fc->pid;
1778 if (!caller_is_in_ancestor(initpid, d->controller, d->cgroup, &nextcg)) {
1779 if (nextcg) {
1780 ret = filler(buf, nextcg, NULL, 0);
1781 free(nextcg);
1782 if (ret != 0) {
1783 ret = -EIO;
1784 goto out;
1785 }
1786 }
1787 ret = 0;
1788 goto out;
1789 }
1790
1791 for (i = 0; list[i]; i++) {
1792 if (filler(buf, list[i]->name, NULL, 0) != 0) {
1793 ret = -EIO;
1794 goto out;
1795 }
1796 }
1797
1798 // now get the list of child cgroups
1799
1800 if (!cgfs_list_children(d->controller, d->cgroup, &clist)) {
1801 ret = 0;
1802 goto out;
1803 }
1804 if (clist) {
1805 for (i = 0; clist[i]; i++) {
1806 if (filler(buf, clist[i], NULL, 0) != 0) {
1807 ret = -EIO;
1808 goto out;
1809 }
1810 }
1811 }
1812 ret = 0;
1813
1814 out:
1815 free_keys(list);
1816 if (clist) {
1817 for (i = 0; clist[i]; i++)
1818 free(clist[i]);
1819 free(clist);
1820 }
1821 return ret;
1822 }
1823
1824 static void do_release_file_info(struct fuse_file_info *fi)
1825 {
1826 struct file_info *f = (struct file_info *)fi->fh;
1827
1828 if (!f)
1829 return;
1830
1831 fi->fh = 0;
1832
1833 free(f->controller);
1834 f->controller = NULL;
1835 free(f->cgroup);
1836 f->cgroup = NULL;
1837 free(f->file);
1838 f->file = NULL;
1839 free(f->buf);
1840 f->buf = NULL;
1841 free(f);
1842 }
1843
1844 int cg_releasedir(const char *path, struct fuse_file_info *fi)
1845 {
1846 do_release_file_info(fi);
1847 return 0;
1848 }
1849
1850 int cg_open(const char *path, struct fuse_file_info *fi)
1851 {
1852 const char *cgroup;
1853 char *last = NULL, *path1, *path2, * cgdir = NULL, *controller;
1854 struct cgfs_files *k = NULL;
1855 struct file_info *file_info;
1856 struct fuse_context *fc = fuse_get_context();
1857 int ret;
1858
1859 if (!fc)
1860 return -EIO;
1861
1862 controller = pick_controller_from_path(fc, path);
1863 if (!controller)
1864 return -errno;
1865 cgroup = find_cgroup_in_path(path);
1866 if (!cgroup)
1867 return -errno;
1868
1869 get_cgdir_and_path(cgroup, &cgdir, &last);
1870 if (!last) {
1871 path1 = "/";
1872 path2 = cgdir;
1873 } else {
1874 path1 = cgdir;
1875 path2 = last;
1876 }
1877
1878 k = cgfs_get_key(controller, path1, path2);
1879 if (!k) {
1880 ret = -EINVAL;
1881 goto out;
1882 }
1883 free_key(k);
1884
1885 pid_t initpid = lookup_initpid_in_store(fc->pid);
1886 if (initpid <= 0)
1887 initpid = fc->pid;
1888 if (!caller_may_see_dir(initpid, controller, path1)) {
1889 ret = -ENOENT;
1890 goto out;
1891 }
1892 if (!fc_may_access(fc, controller, path1, path2, fi->flags)) {
1893 ret = -EACCES;
1894 goto out;
1895 }
1896
1897 /* we'll free this at cg_release */
1898 file_info = malloc(sizeof(*file_info));
1899 if (!file_info) {
1900 ret = -ENOMEM;
1901 goto out;
1902 }
1903 file_info->controller = must_copy_string(controller);
1904 file_info->cgroup = must_copy_string(path1);
1905 file_info->file = must_copy_string(path2);
1906 file_info->type = LXC_TYPE_CGFILE;
1907 file_info->buf = NULL;
1908 file_info->buflen = 0;
1909
1910 fi->fh = (unsigned long)file_info;
1911 ret = 0;
1912
1913 out:
1914 free(cgdir);
1915 return ret;
1916 }
1917
1918 int cg_access(const char *path, int mode)
1919 {
1920 int ret;
1921 const char *cgroup;
1922 char *path1, *path2, *controller;
1923 char *last = NULL, *cgdir = NULL;
1924 struct cgfs_files *k = NULL;
1925 struct fuse_context *fc = fuse_get_context();
1926
1927 if (strcmp(path, "/cgroup") == 0)
1928 return 0;
1929
1930 if (!fc)
1931 return -EIO;
1932
1933 controller = pick_controller_from_path(fc, path);
1934 if (!controller)
1935 return -errno;
1936 cgroup = find_cgroup_in_path(path);
1937 if (!cgroup) {
1938 // access("/sys/fs/cgroup/systemd", mode) - rx allowed, w not
1939 if ((mode & W_OK) == 0)
1940 return 0;
1941 return -EACCES;
1942 }
1943
1944 get_cgdir_and_path(cgroup, &cgdir, &last);
1945 if (!last) {
1946 path1 = "/";
1947 path2 = cgdir;
1948 } else {
1949 path1 = cgdir;
1950 path2 = last;
1951 }
1952
1953 k = cgfs_get_key(controller, path1, path2);
1954 if (!k) {
1955 if ((mode & W_OK) == 0)
1956 ret = 0;
1957 else
1958 ret = -EACCES;
1959 goto out;
1960 }
1961 free_key(k);
1962
1963 pid_t initpid = lookup_initpid_in_store(fc->pid);
1964 if (initpid <= 0)
1965 initpid = fc->pid;
1966 if (!caller_may_see_dir(initpid, controller, path1)) {
1967 ret = -ENOENT;
1968 goto out;
1969 }
1970 if (!fc_may_access(fc, controller, path1, path2, mode)) {
1971 ret = -EACCES;
1972 goto out;
1973 }
1974
1975 ret = 0;
1976
1977 out:
1978 free(cgdir);
1979 return ret;
1980 }
1981
1982 int cg_release(const char *path, struct fuse_file_info *fi)
1983 {
1984 do_release_file_info(fi);
1985 return 0;
1986 }
1987
1988 #define POLLIN_SET ( EPOLLIN | EPOLLHUP | EPOLLRDHUP )
1989
1990 static bool wait_for_sock(int sock, int timeout)
1991 {
1992 struct epoll_event ev;
1993 int epfd, ret, now, starttime, deltatime, saved_errno;
1994
1995 if ((starttime = time(NULL)) < 0)
1996 return false;
1997
1998 if ((epfd = epoll_create(1)) < 0) {
1999 lxcfs_error("%s\n", "Failed to create epoll socket: %m.");
2000 return false;
2001 }
2002
2003 ev.events = POLLIN_SET;
2004 ev.data.fd = sock;
2005 if (epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &ev) < 0) {
2006 lxcfs_error("%s\n", "Failed adding socket to epoll: %m.");
2007 close(epfd);
2008 return false;
2009 }
2010
2011 again:
2012 if ((now = time(NULL)) < 0) {
2013 close(epfd);
2014 return false;
2015 }
2016
2017 deltatime = (starttime + timeout) - now;
2018 if (deltatime < 0) { // timeout
2019 errno = 0;
2020 close(epfd);
2021 return false;
2022 }
2023 ret = epoll_wait(epfd, &ev, 1, 1000*deltatime + 1);
2024 if (ret < 0 && errno == EINTR)
2025 goto again;
2026 saved_errno = errno;
2027 close(epfd);
2028
2029 if (ret <= 0) {
2030 errno = saved_errno;
2031 return false;
2032 }
2033 return true;
2034 }
2035
2036 static int msgrecv(int sockfd, void *buf, size_t len)
2037 {
2038 if (!wait_for_sock(sockfd, 2))
2039 return -1;
2040 return recv(sockfd, buf, len, MSG_DONTWAIT);
2041 }
2042
2043 static int send_creds(int sock, struct ucred *cred, char v, bool pingfirst)
2044 {
2045 struct msghdr msg = { 0 };
2046 struct iovec iov;
2047 struct cmsghdr *cmsg;
2048 char cmsgbuf[CMSG_SPACE(sizeof(*cred))];
2049 char buf[1];
2050 buf[0] = 'p';
2051
2052 if (pingfirst) {
2053 if (msgrecv(sock, buf, 1) != 1) {
2054 lxcfs_error("%s\n", "Error getting reply from server over socketpair.");
2055 return SEND_CREDS_FAIL;
2056 }
2057 }
2058
2059 msg.msg_control = cmsgbuf;
2060 msg.msg_controllen = sizeof(cmsgbuf);
2061
2062 cmsg = CMSG_FIRSTHDR(&msg);
2063 cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
2064 cmsg->cmsg_level = SOL_SOCKET;
2065 cmsg->cmsg_type = SCM_CREDENTIALS;
2066 memcpy(CMSG_DATA(cmsg), cred, sizeof(*cred));
2067
2068 msg.msg_name = NULL;
2069 msg.msg_namelen = 0;
2070
2071 buf[0] = v;
2072 iov.iov_base = buf;
2073 iov.iov_len = sizeof(buf);
2074 msg.msg_iov = &iov;
2075 msg.msg_iovlen = 1;
2076
2077 if (sendmsg(sock, &msg, 0) < 0) {
2078 lxcfs_error("Failed at sendmsg: %s.\n",strerror(errno));
2079 if (errno == 3)
2080 return SEND_CREDS_NOTSK;
2081 return SEND_CREDS_FAIL;
2082 }
2083
2084 return SEND_CREDS_OK;
2085 }
2086
2087 static bool recv_creds(int sock, struct ucred *cred, char *v)
2088 {
2089 struct msghdr msg = { 0 };
2090 struct iovec iov;
2091 struct cmsghdr *cmsg;
2092 char cmsgbuf[CMSG_SPACE(sizeof(*cred))];
2093 char buf[1];
2094 int ret;
2095 int optval = 1;
2096
2097 *v = '1';
2098
2099 cred->pid = -1;
2100 cred->uid = -1;
2101 cred->gid = -1;
2102
2103 if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
2104 lxcfs_error("Failed to set passcred: %s\n", strerror(errno));
2105 return false;
2106 }
2107 buf[0] = '1';
2108 if (write(sock, buf, 1) != 1) {
2109 lxcfs_error("Failed to start write on scm fd: %s\n", strerror(errno));
2110 return false;
2111 }
2112
2113 msg.msg_name = NULL;
2114 msg.msg_namelen = 0;
2115 msg.msg_control = cmsgbuf;
2116 msg.msg_controllen = sizeof(cmsgbuf);
2117
2118 iov.iov_base = buf;
2119 iov.iov_len = sizeof(buf);
2120 msg.msg_iov = &iov;
2121 msg.msg_iovlen = 1;
2122
2123 if (!wait_for_sock(sock, 2)) {
2124 lxcfs_error("Timed out waiting for scm_cred: %s\n", strerror(errno));
2125 return false;
2126 }
2127 ret = recvmsg(sock, &msg, MSG_DONTWAIT);
2128 if (ret < 0) {
2129 lxcfs_error("Failed to receive scm_cred: %s\n", strerror(errno));
2130 return false;
2131 }
2132
2133 cmsg = CMSG_FIRSTHDR(&msg);
2134
2135 if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)) &&
2136 cmsg->cmsg_level == SOL_SOCKET &&
2137 cmsg->cmsg_type == SCM_CREDENTIALS) {
2138 memcpy(cred, CMSG_DATA(cmsg), sizeof(*cred));
2139 }
2140 *v = buf[0];
2141
2142 return true;
2143 }
2144
2145 struct pid_ns_clone_args {
2146 int *cpipe;
2147 int sock;
2148 pid_t tpid;
2149 int (*wrapped) (int, pid_t); // pid_from_ns or pid_to_ns
2150 };
2151
2152 /*
2153 * pid_ns_clone_wrapper - wraps pid_to_ns or pid_from_ns for usage
2154 * with clone(). This simply writes '1' as ACK back to the parent
2155 * before calling the actual wrapped function.
2156 */
2157 static int pid_ns_clone_wrapper(void *arg) {
2158 struct pid_ns_clone_args* args = (struct pid_ns_clone_args *) arg;
2159 char b = '1';
2160
2161 close(args->cpipe[0]);
2162 if (write(args->cpipe[1], &b, sizeof(char)) < 0)
2163 lxcfs_error("(child): error on write: %s.\n", strerror(errno));
2164 close(args->cpipe[1]);
2165 return args->wrapped(args->sock, args->tpid);
2166 }
2167
2168 /*
2169 * pid_to_ns - reads pids from a ucred over a socket, then writes the
2170 * int value back over the socket. This shifts the pid from the
2171 * sender's pidns into tpid's pidns.
2172 */
2173 static int pid_to_ns(int sock, pid_t tpid)
2174 {
2175 char v = '0';
2176 struct ucred cred;
2177
2178 while (recv_creds(sock, &cred, &v)) {
2179 if (v == '1')
2180 return 0;
2181 if (write(sock, &cred.pid, sizeof(pid_t)) != sizeof(pid_t))
2182 return 1;
2183 }
2184 return 0;
2185 }
2186
2187
2188 /*
2189 * pid_to_ns_wrapper: when you setns into a pidns, you yourself remain
2190 * in your old pidns. Only children which you clone will be in the target
2191 * pidns. So the pid_to_ns_wrapper does the setns, then clones a child to
2192 * actually convert pids.
2193 *
2194 * Note: glibc's fork() does not respect pidns, which can lead to failed
2195 * assertions inside glibc (and thus failed forks) if the child's pid in
2196 * the pidns and the parent pid outside are identical. Using clone prevents
2197 * this issue.
2198 */
2199 static void pid_to_ns_wrapper(int sock, pid_t tpid)
2200 {
2201 int newnsfd = -1, ret, cpipe[2];
2202 char fnam[100];
2203 pid_t cpid;
2204 char v;
2205
2206 ret = snprintf(fnam, sizeof(fnam), "/proc/%d/ns/pid", tpid);
2207 if (ret < 0 || ret >= sizeof(fnam))
2208 _exit(1);
2209 newnsfd = open(fnam, O_RDONLY);
2210 if (newnsfd < 0)
2211 _exit(1);
2212 if (setns(newnsfd, 0) < 0)
2213 _exit(1);
2214 close(newnsfd);
2215
2216 if (pipe(cpipe) < 0)
2217 _exit(1);
2218
2219 struct pid_ns_clone_args args = {
2220 .cpipe = cpipe,
2221 .sock = sock,
2222 .tpid = tpid,
2223 .wrapped = &pid_to_ns
2224 };
2225 size_t stack_size = sysconf(_SC_PAGESIZE);
2226 void *stack = alloca(stack_size);
2227
2228 cpid = clone(pid_ns_clone_wrapper, stack + stack_size, SIGCHLD, &args);
2229 if (cpid < 0)
2230 _exit(1);
2231
2232 // give the child 1 second to be done forking and
2233 // write its ack
2234 if (!wait_for_sock(cpipe[0], 1))
2235 _exit(1);
2236 ret = read(cpipe[0], &v, 1);
2237 if (ret != sizeof(char) || v != '1')
2238 _exit(1);
2239
2240 if (!wait_for_pid(cpid))
2241 _exit(1);
2242 _exit(0);
2243 }
2244
2245 /*
2246 * To read cgroup files with a particular pid, we will setns into the child
2247 * pidns, open a pipe, fork a child - which will be the first to really be in
2248 * the child ns - which does the cgfs_get_value and writes the data to the pipe.
2249 */
2250 bool do_read_pids(pid_t tpid, const char *contrl, const char *cg, const char *file, char **d)
2251 {
2252 int sock[2] = {-1, -1};
2253 char *tmpdata = NULL;
2254 int ret;
2255 pid_t qpid, cpid = -1;
2256 bool answer = false;
2257 char v = '0';
2258 struct ucred cred;
2259 size_t sz = 0, asz = 0;
2260
2261 if (!cgfs_get_value(contrl, cg, file, &tmpdata))
2262 return false;
2263
2264 /*
2265 * Now we read the pids from returned data one by one, pass
2266 * them into a child in the target namespace, read back the
2267 * translated pids, and put them into our to-return data
2268 */
2269
2270 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) {
2271 perror("socketpair");
2272 free(tmpdata);
2273 return false;
2274 }
2275
2276 cpid = fork();
2277 if (cpid == -1)
2278 goto out;
2279
2280 if (!cpid) // child - exits when done
2281 pid_to_ns_wrapper(sock[1], tpid);
2282
2283 char *ptr = tmpdata;
2284 cred.uid = 0;
2285 cred.gid = 0;
2286 while (sscanf(ptr, "%d\n", &qpid) == 1) {
2287 cred.pid = qpid;
2288 ret = send_creds(sock[0], &cred, v, true);
2289
2290 if (ret == SEND_CREDS_NOTSK)
2291 goto next;
2292 if (ret == SEND_CREDS_FAIL)
2293 goto out;
2294
2295 // read converted results
2296 if (!wait_for_sock(sock[0], 2)) {
2297 lxcfs_error("Timed out waiting for pid from child: %s.\n", strerror(errno));
2298 goto out;
2299 }
2300 if (read(sock[0], &qpid, sizeof(qpid)) != sizeof(qpid)) {
2301 lxcfs_error("Error reading pid from child: %s.\n", strerror(errno));
2302 goto out;
2303 }
2304 must_strcat_pid(d, &sz, &asz, qpid);
2305 next:
2306 ptr = strchr(ptr, '\n');
2307 if (!ptr)
2308 break;
2309 ptr++;
2310 }
2311
2312 cred.pid = getpid();
2313 v = '1';
2314 if (send_creds(sock[0], &cred, v, true) != SEND_CREDS_OK) {
2315 // failed to ask child to exit
2316 lxcfs_error("Failed to ask child to exit: %s.\n", strerror(errno));
2317 goto out;
2318 }
2319
2320 answer = true;
2321
2322 out:
2323 free(tmpdata);
2324 if (cpid != -1)
2325 wait_for_pid(cpid);
2326 if (sock[0] != -1) {
2327 close(sock[0]);
2328 close(sock[1]);
2329 }
2330 return answer;
2331 }
2332
2333 int cg_read(const char *path, char *buf, size_t size, off_t offset,
2334 struct fuse_file_info *fi)
2335 {
2336 struct fuse_context *fc = fuse_get_context();
2337 struct file_info *f = (struct file_info *)fi->fh;
2338 struct cgfs_files *k = NULL;
2339 char *data = NULL;
2340 int ret, s;
2341 bool r;
2342
2343 if (f->type != LXC_TYPE_CGFILE) {
2344 lxcfs_error("%s\n", "Internal error: directory cache info used in cg_read.");
2345 return -EIO;
2346 }
2347
2348 if (offset)
2349 return 0;
2350
2351 if (!fc)
2352 return -EIO;
2353
2354 if (!f->controller)
2355 return -EINVAL;
2356
2357 if ((k = cgfs_get_key(f->controller, f->cgroup, f->file)) == NULL) {
2358 return -EINVAL;
2359 }
2360 free_key(k);
2361
2362
2363 if (!fc_may_access(fc, f->controller, f->cgroup, f->file, O_RDONLY)) {
2364 ret = -EACCES;
2365 goto out;
2366 }
2367
2368 if (strcmp(f->file, "tasks") == 0 ||
2369 strcmp(f->file, "/tasks") == 0 ||
2370 strcmp(f->file, "/cgroup.procs") == 0 ||
2371 strcmp(f->file, "cgroup.procs") == 0)
2372 // special case - we have to translate the pids
2373 r = do_read_pids(fc->pid, f->controller, f->cgroup, f->file, &data);
2374 else
2375 r = cgfs_get_value(f->controller, f->cgroup, f->file, &data);
2376
2377 if (!r) {
2378 ret = -EINVAL;
2379 goto out;
2380 }
2381
2382 if (!data) {
2383 ret = 0;
2384 goto out;
2385 }
2386 s = strlen(data);
2387 if (s > size)
2388 s = size;
2389 memcpy(buf, data, s);
2390 if (s > 0 && s < size && data[s-1] != '\n')
2391 buf[s++] = '\n';
2392
2393 ret = s;
2394
2395 out:
2396 free(data);
2397 return ret;
2398 }
2399
2400 static int pid_from_ns(int sock, pid_t tpid)
2401 {
2402 pid_t vpid;
2403 struct ucred cred;
2404 char v;
2405 int ret;
2406
2407 cred.uid = 0;
2408 cred.gid = 0;
2409 while (1) {
2410 if (!wait_for_sock(sock, 2)) {
2411 lxcfs_error("%s\n", "Timeout reading from parent.");
2412 return 1;
2413 }
2414 if ((ret = read(sock, &vpid, sizeof(pid_t))) != sizeof(pid_t)) {
2415 lxcfs_error("Bad read from parent: %s.\n", strerror(errno));
2416 return 1;
2417 }
2418 if (vpid == -1) // done
2419 break;
2420 v = '0';
2421 cred.pid = vpid;
2422 if (send_creds(sock, &cred, v, true) != SEND_CREDS_OK) {
2423 v = '1';
2424 cred.pid = getpid();
2425 if (send_creds(sock, &cred, v, false) != SEND_CREDS_OK)
2426 return 1;
2427 }
2428 }
2429 return 0;
2430 }
2431
2432 static void pid_from_ns_wrapper(int sock, pid_t tpid)
2433 {
2434 int newnsfd = -1, ret, cpipe[2];
2435 char fnam[100];
2436 pid_t cpid;
2437 char v;
2438
2439 ret = snprintf(fnam, sizeof(fnam), "/proc/%d/ns/pid", tpid);
2440 if (ret < 0 || ret >= sizeof(fnam))
2441 _exit(1);
2442 newnsfd = open(fnam, O_RDONLY);
2443 if (newnsfd < 0)
2444 _exit(1);
2445 if (setns(newnsfd, 0) < 0)
2446 _exit(1);
2447 close(newnsfd);
2448
2449 if (pipe(cpipe) < 0)
2450 _exit(1);
2451
2452 struct pid_ns_clone_args args = {
2453 .cpipe = cpipe,
2454 .sock = sock,
2455 .tpid = tpid,
2456 .wrapped = &pid_from_ns
2457 };
2458 size_t stack_size = sysconf(_SC_PAGESIZE);
2459 void *stack = alloca(stack_size);
2460
2461 cpid = clone(pid_ns_clone_wrapper, stack + stack_size, SIGCHLD, &args);
2462 if (cpid < 0)
2463 _exit(1);
2464
2465 // give the child 1 second to be done forking and
2466 // write its ack
2467 if (!wait_for_sock(cpipe[0], 1))
2468 _exit(1);
2469 ret = read(cpipe[0], &v, 1);
2470 if (ret != sizeof(char) || v != '1')
2471 _exit(1);
2472
2473 if (!wait_for_pid(cpid))
2474 _exit(1);
2475 _exit(0);
2476 }
2477
2478 /*
2479 * Given host @uid, return the uid to which it maps in
2480 * @pid's user namespace, or -1 if none.
2481 */
2482 bool hostuid_to_ns(uid_t uid, pid_t pid, uid_t *answer)
2483 {
2484 FILE *f;
2485 char line[400];
2486
2487 sprintf(line, "/proc/%d/uid_map", pid);
2488 if ((f = fopen(line, "r")) == NULL) {
2489 return false;
2490 }
2491
2492 *answer = convert_id_to_ns(f, uid);
2493 fclose(f);
2494
2495 if (*answer == -1)
2496 return false;
2497 return true;
2498 }
2499
2500 /*
2501 * get_pid_creds: get the real uid and gid of @pid from
2502 * /proc/$$/status
2503 * (XXX should we use euid here?)
2504 */
2505 void get_pid_creds(pid_t pid, uid_t *uid, gid_t *gid)
2506 {
2507 char line[400];
2508 uid_t u;
2509 gid_t g;
2510 FILE *f;
2511
2512 *uid = -1;
2513 *gid = -1;
2514 sprintf(line, "/proc/%d/status", pid);
2515 if ((f = fopen(line, "r")) == NULL) {
2516 lxcfs_error("Error opening %s: %s\n", line, strerror(errno));
2517 return;
2518 }
2519 while (fgets(line, 400, f)) {
2520 if (strncmp(line, "Uid:", 4) == 0) {
2521 if (sscanf(line+4, "%u", &u) != 1) {
2522 lxcfs_error("bad uid line for pid %u\n", pid);
2523 fclose(f);
2524 return;
2525 }
2526 *uid = u;
2527 } else if (strncmp(line, "Gid:", 4) == 0) {
2528 if (sscanf(line+4, "%u", &g) != 1) {
2529 lxcfs_error("bad gid line for pid %u\n", pid);
2530 fclose(f);
2531 return;
2532 }
2533 *gid = g;
2534 }
2535 }
2536 fclose(f);
2537 }
2538
2539 /*
2540 * May the requestor @r move victim @v to a new cgroup?
2541 * This is allowed if
2542 * . they are the same task
2543 * . they are ownedy by the same uid
2544 * . @r is root on the host, or
2545 * . @v's uid is mapped into @r's where @r is root.
2546 */
2547 bool may_move_pid(pid_t r, uid_t r_uid, pid_t v)
2548 {
2549 uid_t v_uid, tmpuid;
2550 gid_t v_gid;
2551
2552 if (r == v)
2553 return true;
2554 if (r_uid == 0)
2555 return true;
2556 get_pid_creds(v, &v_uid, &v_gid);
2557 if (r_uid == v_uid)
2558 return true;
2559 if (hostuid_to_ns(r_uid, r, &tmpuid) && tmpuid == 0
2560 && hostuid_to_ns(v_uid, r, &tmpuid))
2561 return true;
2562 return false;
2563 }
2564
2565 static bool do_write_pids(pid_t tpid, uid_t tuid, const char *contrl, const char *cg,
2566 const char *file, const char *buf)
2567 {
2568 int sock[2] = {-1, -1};
2569 pid_t qpid, cpid = -1;
2570 FILE *pids_file = NULL;
2571 bool answer = false, fail = false;
2572
2573 pids_file = open_pids_file(contrl, cg);
2574 if (!pids_file)
2575 return false;
2576
2577 /*
2578 * write the pids to a socket, have helper in writer's pidns
2579 * call movepid for us
2580 */
2581 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) {
2582 perror("socketpair");
2583 goto out;
2584 }
2585
2586 cpid = fork();
2587 if (cpid == -1)
2588 goto out;
2589
2590 if (!cpid) { // child
2591 fclose(pids_file);
2592 pid_from_ns_wrapper(sock[1], tpid);
2593 }
2594
2595 const char *ptr = buf;
2596 while (sscanf(ptr, "%d", &qpid) == 1) {
2597 struct ucred cred;
2598 char v;
2599
2600 if (write(sock[0], &qpid, sizeof(qpid)) != sizeof(qpid)) {
2601 lxcfs_error("Error writing pid to child: %s.\n", strerror(errno));
2602 goto out;
2603 }
2604
2605 if (recv_creds(sock[0], &cred, &v)) {
2606 if (v == '0') {
2607 if (!may_move_pid(tpid, tuid, cred.pid)) {
2608 fail = true;
2609 break;
2610 }
2611 if (fprintf(pids_file, "%d", (int) cred.pid) < 0)
2612 fail = true;
2613 }
2614 }
2615
2616 ptr = strchr(ptr, '\n');
2617 if (!ptr)
2618 break;
2619 ptr++;
2620 }
2621
2622 /* All good, write the value */
2623 qpid = -1;
2624 if (write(sock[0], &qpid ,sizeof(qpid)) != sizeof(qpid))
2625 lxcfs_error("%s\n", "Warning: failed to ask child to exit.");
2626
2627 if (!fail)
2628 answer = true;
2629
2630 out:
2631 if (cpid != -1)
2632 wait_for_pid(cpid);
2633 if (sock[0] != -1) {
2634 close(sock[0]);
2635 close(sock[1]);
2636 }
2637 if (pids_file) {
2638 if (fclose(pids_file) != 0)
2639 answer = false;
2640 }
2641 return answer;
2642 }
2643
2644 int cg_write(const char *path, const char *buf, size_t size, off_t offset,
2645 struct fuse_file_info *fi)
2646 {
2647 struct fuse_context *fc = fuse_get_context();
2648 char *localbuf = NULL;
2649 struct cgfs_files *k = NULL;
2650 struct file_info *f = (struct file_info *)fi->fh;
2651 bool r;
2652
2653 if (f->type != LXC_TYPE_CGFILE) {
2654 lxcfs_error("%s\n", "Internal error: directory cache info used in cg_write.");
2655 return -EIO;
2656 }
2657
2658 if (offset)
2659 return 0;
2660
2661 if (!fc)
2662 return -EIO;
2663
2664 localbuf = alloca(size+1);
2665 localbuf[size] = '\0';
2666 memcpy(localbuf, buf, size);
2667
2668 if ((k = cgfs_get_key(f->controller, f->cgroup, f->file)) == NULL) {
2669 size = -EINVAL;
2670 goto out;
2671 }
2672
2673 if (!fc_may_access(fc, f->controller, f->cgroup, f->file, O_WRONLY)) {
2674 size = -EACCES;
2675 goto out;
2676 }
2677
2678 if (strcmp(f->file, "tasks") == 0 ||
2679 strcmp(f->file, "/tasks") == 0 ||
2680 strcmp(f->file, "/cgroup.procs") == 0 ||
2681 strcmp(f->file, "cgroup.procs") == 0)
2682 // special case - we have to translate the pids
2683 r = do_write_pids(fc->pid, fc->uid, f->controller, f->cgroup, f->file, localbuf);
2684 else
2685 r = cgfs_set_value(f->controller, f->cgroup, f->file, localbuf);
2686
2687 if (!r)
2688 size = -EINVAL;
2689
2690 out:
2691 free_key(k);
2692 return size;
2693 }
2694
2695 int cg_chown(const char *path, uid_t uid, gid_t gid)
2696 {
2697 struct fuse_context *fc = fuse_get_context();
2698 char *cgdir = NULL, *last = NULL, *path1, *path2, *controller;
2699 struct cgfs_files *k = NULL;
2700 const char *cgroup;
2701 int ret;
2702
2703 if (!fc)
2704 return -EIO;
2705
2706 if (strcmp(path, "/cgroup") == 0)
2707 return -EPERM;
2708
2709 controller = pick_controller_from_path(fc, path);
2710 if (!controller)
2711 return errno == ENOENT ? -EPERM : -errno;
2712
2713 cgroup = find_cgroup_in_path(path);
2714 if (!cgroup)
2715 /* this is just /cgroup/controller */
2716 return -EPERM;
2717
2718 get_cgdir_and_path(cgroup, &cgdir, &last);
2719
2720 if (!last) {
2721 path1 = "/";
2722 path2 = cgdir;
2723 } else {
2724 path1 = cgdir;
2725 path2 = last;
2726 }
2727
2728 if (is_child_cgroup(controller, path1, path2)) {
2729 // get uid, gid, from '/tasks' file and make up a mode
2730 // That is a hack, until cgmanager gains a GetCgroupPerms fn.
2731 k = cgfs_get_key(controller, cgroup, "tasks");
2732
2733 } else
2734 k = cgfs_get_key(controller, path1, path2);
2735
2736 if (!k) {
2737 ret = -EINVAL;
2738 goto out;
2739 }
2740
2741 /*
2742 * This being a fuse request, the uid and gid must be valid
2743 * in the caller's namespace. So we can just check to make
2744 * sure that the caller is root in his uid, and privileged
2745 * over the file's current owner.
2746 */
2747 if (!is_privileged_over(fc->pid, fc->uid, k->uid, NS_ROOT_REQD)) {
2748 ret = -EACCES;
2749 goto out;
2750 }
2751
2752 ret = cgfs_chown_file(controller, cgroup, uid, gid);
2753
2754 out:
2755 free_key(k);
2756 free(cgdir);
2757
2758 return ret;
2759 }
2760
2761 int cg_chmod(const char *path, mode_t mode)
2762 {
2763 struct fuse_context *fc = fuse_get_context();
2764 char * cgdir = NULL, *last = NULL, *path1, *path2, *controller;
2765 struct cgfs_files *k = NULL;
2766 const char *cgroup;
2767 int ret;
2768
2769 if (!fc)
2770 return -EIO;
2771
2772 if (strcmp(path, "/cgroup") == 0)
2773 return -EPERM;
2774
2775 controller = pick_controller_from_path(fc, path);
2776 if (!controller)
2777 return errno == ENOENT ? -EPERM : -errno;
2778
2779 cgroup = find_cgroup_in_path(path);
2780 if (!cgroup)
2781 /* this is just /cgroup/controller */
2782 return -EPERM;
2783
2784 get_cgdir_and_path(cgroup, &cgdir, &last);
2785
2786 if (!last) {
2787 path1 = "/";
2788 path2 = cgdir;
2789 } else {
2790 path1 = cgdir;
2791 path2 = last;
2792 }
2793
2794 if (is_child_cgroup(controller, path1, path2)) {
2795 // get uid, gid, from '/tasks' file and make up a mode
2796 // That is a hack, until cgmanager gains a GetCgroupPerms fn.
2797 k = cgfs_get_key(controller, cgroup, "tasks");
2798
2799 } else
2800 k = cgfs_get_key(controller, path1, path2);
2801
2802 if (!k) {
2803 ret = -EINVAL;
2804 goto out;
2805 }
2806
2807 /*
2808 * This being a fuse request, the uid and gid must be valid
2809 * in the caller's namespace. So we can just check to make
2810 * sure that the caller is root in his uid, and privileged
2811 * over the file's current owner.
2812 */
2813 if (!is_privileged_over(fc->pid, fc->uid, k->uid, NS_ROOT_OPT)) {
2814 ret = -EPERM;
2815 goto out;
2816 }
2817
2818 if (!cgfs_chmod_file(controller, cgroup, mode)) {
2819 ret = -EINVAL;
2820 goto out;
2821 }
2822
2823 ret = 0;
2824 out:
2825 free_key(k);
2826 free(cgdir);
2827 return ret;
2828 }
2829
2830 int cg_mkdir(const char *path, mode_t mode)
2831 {
2832 struct fuse_context *fc = fuse_get_context();
2833 char *last = NULL, *path1, *cgdir = NULL, *controller, *next = NULL;
2834 const char *cgroup;
2835 int ret;
2836
2837 if (!fc)
2838 return -EIO;
2839
2840 controller = pick_controller_from_path(fc, path);
2841 if (!controller)
2842 return errno == ENOENT ? -EPERM : -errno;
2843
2844 cgroup = find_cgroup_in_path(path);
2845 if (!cgroup)
2846 return -errno;
2847
2848 get_cgdir_and_path(cgroup, &cgdir, &last);
2849 if (!last)
2850 path1 = "/";
2851 else
2852 path1 = cgdir;
2853
2854 pid_t initpid = lookup_initpid_in_store(fc->pid);
2855 if (initpid <= 0)
2856 initpid = fc->pid;
2857 if (!caller_is_in_ancestor(initpid, controller, path1, &next)) {
2858 if (!next)
2859 ret = -EINVAL;
2860 else if (last && strcmp(next, last) == 0)
2861 ret = -EEXIST;
2862 else
2863 ret = -EPERM;
2864 goto out;
2865 }
2866
2867 if (!fc_may_access(fc, controller, path1, NULL, O_RDWR)) {
2868 ret = -EACCES;
2869 goto out;
2870 }
2871 if (!caller_is_in_ancestor(initpid, controller, path1, NULL)) {
2872 ret = -EACCES;
2873 goto out;
2874 }
2875
2876 ret = cgfs_create(controller, cgroup, fc->uid, fc->gid);
2877
2878 out:
2879 free(cgdir);
2880 free(next);
2881 return ret;
2882 }
2883
2884 int cg_rmdir(const char *path)
2885 {
2886 struct fuse_context *fc = fuse_get_context();
2887 char *last = NULL, *cgdir = NULL, *controller, *next = NULL;
2888 const char *cgroup;
2889 int ret;
2890
2891 if (!fc)
2892 return -EIO;
2893
2894 controller = pick_controller_from_path(fc, path);
2895 if (!controller) /* Someone's trying to delete "/cgroup". */
2896 return -EPERM;
2897
2898 cgroup = find_cgroup_in_path(path);
2899 if (!cgroup) /* Someone's trying to delete a controller e.g. "/blkio". */
2900 return -EPERM;
2901
2902 get_cgdir_and_path(cgroup, &cgdir, &last);
2903 if (!last) {
2904 /* Someone's trying to delete a cgroup on the same level as the
2905 * "/lxc" cgroup e.g. rmdir "/cgroup/blkio/lxc" or
2906 * rmdir "/cgroup/blkio/init.slice".
2907 */
2908 ret = -EPERM;
2909 goto out;
2910 }
2911
2912 pid_t initpid = lookup_initpid_in_store(fc->pid);
2913 if (initpid <= 0)
2914 initpid = fc->pid;
2915 if (!caller_is_in_ancestor(initpid, controller, cgroup, &next)) {
2916 if (!last || strcmp(next, last) == 0)
2917 ret = -EBUSY;
2918 else
2919 ret = -ENOENT;
2920 goto out;
2921 }
2922
2923 if (!fc_may_access(fc, controller, cgdir, NULL, O_WRONLY)) {
2924 ret = -EACCES;
2925 goto out;
2926 }
2927 if (!caller_is_in_ancestor(initpid, controller, cgroup, NULL)) {
2928 ret = -EACCES;
2929 goto out;
2930 }
2931
2932 if (!cgfs_remove(controller, cgroup)) {
2933 ret = -EINVAL;
2934 goto out;
2935 }
2936
2937 ret = 0;
2938
2939 out:
2940 free(cgdir);
2941 free(next);
2942 return ret;
2943 }
2944
2945 static bool startswith(const char *line, const char *pref)
2946 {
2947 if (strncmp(line, pref, strlen(pref)) == 0)
2948 return true;
2949 return false;
2950 }
2951
2952 static void parse_memstat(char *memstat, unsigned long *cached,
2953 unsigned long *active_anon, unsigned long *inactive_anon,
2954 unsigned long *active_file, unsigned long *inactive_file,
2955 unsigned long *unevictable)
2956 {
2957 char *eol;
2958
2959 while (*memstat) {
2960 if (startswith(memstat, "cache")) {
2961 sscanf(memstat + 11, "%lu", cached);
2962 *cached /= 1024;
2963 } else if (startswith(memstat, "active_anon")) {
2964 sscanf(memstat + 11, "%lu", active_anon);
2965 *active_anon /= 1024;
2966 } else if (startswith(memstat, "inactive_anon")) {
2967 sscanf(memstat + 11, "%lu", inactive_anon);
2968 *inactive_anon /= 1024;
2969 } else if (startswith(memstat, "active_file")) {
2970 sscanf(memstat + 11, "%lu", active_file);
2971 *active_file /= 1024;
2972 } else if (startswith(memstat, "inactive_file")) {
2973 sscanf(memstat + 11, "%lu", inactive_file);
2974 *inactive_file /= 1024;
2975 } else if (startswith(memstat, "unevictable")) {
2976 sscanf(memstat + 11, "%lu", unevictable);
2977 *unevictable /= 1024;
2978 }
2979 eol = strchr(memstat, '\n');
2980 if (!eol)
2981 return;
2982 memstat = eol+1;
2983 }
2984 }
2985
2986 static void get_blkio_io_value(char *str, unsigned major, unsigned minor, char *iotype, unsigned long *v)
2987 {
2988 char *eol;
2989 char key[32];
2990
2991 memset(key, 0, 32);
2992 snprintf(key, 32, "%u:%u %s", major, minor, iotype);
2993
2994 size_t len = strlen(key);
2995 *v = 0;
2996
2997 while (*str) {
2998 if (startswith(str, key)) {
2999 sscanf(str + len, "%lu", v);
3000 return;
3001 }
3002 eol = strchr(str, '\n');
3003 if (!eol)
3004 return;
3005 str = eol+1;
3006 }
3007 }
3008
3009 static int read_file(const char *path, char *buf, size_t size,
3010 struct file_info *d)
3011 {
3012 size_t linelen = 0, total_len = 0, rv = 0;
3013 char *line = NULL;
3014 char *cache = d->buf;
3015 size_t cache_size = d->buflen;
3016 FILE *f = fopen(path, "r");
3017 if (!f)
3018 return 0;
3019
3020 while (getline(&line, &linelen, f) != -1) {
3021 ssize_t l = snprintf(cache, cache_size, "%s", line);
3022 if (l < 0) {
3023 perror("Error writing to cache");
3024 rv = 0;
3025 goto err;
3026 }
3027 if (l >= cache_size) {
3028 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3029 rv = 0;
3030 goto err;
3031 }
3032 cache += l;
3033 cache_size -= l;
3034 total_len += l;
3035 }
3036
3037 d->size = total_len;
3038 if (total_len > size)
3039 total_len = size;
3040
3041 /* read from off 0 */
3042 memcpy(buf, d->buf, total_len);
3043 rv = total_len;
3044 err:
3045 fclose(f);
3046 free(line);
3047 return rv;
3048 }
3049
3050 /*
3051 * FUSE ops for /proc
3052 */
3053
3054 static unsigned long get_memlimit(const char *cgroup)
3055 {
3056 char *memlimit_str = NULL;
3057 unsigned long memlimit = -1;
3058
3059 if (cgfs_get_value("memory", cgroup, "memory.limit_in_bytes", &memlimit_str))
3060 memlimit = strtoul(memlimit_str, NULL, 10);
3061
3062 free(memlimit_str);
3063
3064 return memlimit;
3065 }
3066
3067 static unsigned long get_min_memlimit(const char *cgroup)
3068 {
3069 char *copy = strdupa(cgroup);
3070 unsigned long memlimit = 0, retlimit;
3071
3072 retlimit = get_memlimit(copy);
3073
3074 while (strcmp(copy, "/") != 0) {
3075 copy = dirname(copy);
3076 memlimit = get_memlimit(copy);
3077 if (memlimit != -1 && memlimit < retlimit)
3078 retlimit = memlimit;
3079 };
3080
3081 return retlimit;
3082 }
3083
3084 static int proc_meminfo_read(char *buf, size_t size, off_t offset,
3085 struct fuse_file_info *fi)
3086 {
3087 struct fuse_context *fc = fuse_get_context();
3088 struct file_info *d = (struct file_info *)fi->fh;
3089 char *cg;
3090 char *memusage_str = NULL, *memstat_str = NULL,
3091 *memswlimit_str = NULL, *memswusage_str = NULL,
3092 *memswlimit_default_str = NULL, *memswusage_default_str = NULL;
3093 unsigned long memlimit = 0, memusage = 0, memswlimit = 0, memswusage = 0,
3094 cached = 0, hosttotal = 0, active_anon = 0, inactive_anon = 0,
3095 active_file = 0, inactive_file = 0, unevictable = 0;
3096 char *line = NULL;
3097 size_t linelen = 0, total_len = 0, rv = 0;
3098 char *cache = d->buf;
3099 size_t cache_size = d->buflen;
3100 FILE *f = NULL;
3101
3102 if (offset){
3103 if (offset > d->size)
3104 return -EINVAL;
3105 if (!d->cached)
3106 return 0;
3107 int left = d->size - offset;
3108 total_len = left > size ? size: left;
3109 memcpy(buf, cache + offset, total_len);
3110 return total_len;
3111 }
3112
3113 pid_t initpid = lookup_initpid_in_store(fc->pid);
3114 if (initpid <= 0)
3115 initpid = fc->pid;
3116 cg = get_pid_cgroup(initpid, "memory");
3117 if (!cg)
3118 return read_file("/proc/meminfo", buf, size, d);
3119 prune_init_slice(cg);
3120
3121 memlimit = get_min_memlimit(cg);
3122 if (!cgfs_get_value("memory", cg, "memory.usage_in_bytes", &memusage_str))
3123 goto err;
3124 if (!cgfs_get_value("memory", cg, "memory.stat", &memstat_str))
3125 goto err;
3126
3127 // Following values are allowed to fail, because swapaccount might be turned
3128 // off for current kernel
3129 if(cgfs_get_value("memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str) &&
3130 cgfs_get_value("memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str))
3131 {
3132 /* If swapaccounting is turned on, then default value is assumed to be that of cgroup / */
3133 if (!cgfs_get_value("memory", "/", "memory.memsw.limit_in_bytes", &memswlimit_default_str))
3134 goto err;
3135 if (!cgfs_get_value("memory", "/", "memory.memsw.usage_in_bytes", &memswusage_default_str))
3136 goto err;
3137
3138 memswlimit = strtoul(memswlimit_str, NULL, 10);
3139 memswusage = strtoul(memswusage_str, NULL, 10);
3140
3141 if (!strcmp(memswlimit_str, memswlimit_default_str))
3142 memswlimit = 0;
3143 if (!strcmp(memswusage_str, memswusage_default_str))
3144 memswusage = 0;
3145
3146 memswlimit = memswlimit / 1024;
3147 memswusage = memswusage / 1024;
3148 }
3149
3150 memusage = strtoul(memusage_str, NULL, 10);
3151 memlimit /= 1024;
3152 memusage /= 1024;
3153
3154 parse_memstat(memstat_str, &cached, &active_anon,
3155 &inactive_anon, &active_file, &inactive_file,
3156 &unevictable);
3157
3158 f = fopen("/proc/meminfo", "r");
3159 if (!f)
3160 goto err;
3161
3162 while (getline(&line, &linelen, f) != -1) {
3163 ssize_t l;
3164 char *printme, lbuf[100];
3165
3166 memset(lbuf, 0, 100);
3167 if (startswith(line, "MemTotal:")) {
3168 sscanf(line+14, "%lu", &hosttotal);
3169 if (hosttotal < memlimit)
3170 memlimit = hosttotal;
3171 snprintf(lbuf, 100, "MemTotal: %8lu kB\n", memlimit);
3172 printme = lbuf;
3173 } else if (startswith(line, "MemFree:")) {
3174 snprintf(lbuf, 100, "MemFree: %8lu kB\n", memlimit - memusage);
3175 printme = lbuf;
3176 } else if (startswith(line, "MemAvailable:")) {
3177 snprintf(lbuf, 100, "MemAvailable: %8lu kB\n", memlimit - memusage);
3178 printme = lbuf;
3179 } else if (startswith(line, "SwapTotal:") && memswlimit > 0) {
3180 snprintf(lbuf, 100, "SwapTotal: %8lu kB\n", memswlimit - memlimit);
3181 printme = lbuf;
3182 } else if (startswith(line, "SwapFree:") && memswlimit > 0 && memswusage > 0) {
3183 unsigned long swaptotal = memswlimit - memlimit,
3184 swapusage = memswusage - memusage,
3185 swapfree = swapusage < swaptotal ? swaptotal - swapusage : 0;
3186 snprintf(lbuf, 100, "SwapFree: %8lu kB\n", swapfree);
3187 printme = lbuf;
3188 } else if (startswith(line, "Slab:")) {
3189 snprintf(lbuf, 100, "Slab: %8lu kB\n", 0UL);
3190 printme = lbuf;
3191 } else if (startswith(line, "Buffers:")) {
3192 snprintf(lbuf, 100, "Buffers: %8lu kB\n", 0UL);
3193 printme = lbuf;
3194 } else if (startswith(line, "Cached:")) {
3195 snprintf(lbuf, 100, "Cached: %8lu kB\n", cached);
3196 printme = lbuf;
3197 } else if (startswith(line, "SwapCached:")) {
3198 snprintf(lbuf, 100, "SwapCached: %8lu kB\n", 0UL);
3199 printme = lbuf;
3200 } else if (startswith(line, "Active")) {
3201 snprintf(lbuf, 100, "Active: %8lu kB\n",
3202 active_anon + active_file);
3203 printme = lbuf;
3204 } else if (startswith(line, "Inactive")) {
3205 snprintf(lbuf, 100, "Inactive: %8lu kB\n",
3206 inactive_anon + inactive_file);
3207 printme = lbuf;
3208 } else if (startswith(line, "Active(anon)")) {
3209 snprintf(lbuf, 100, "Active(anon): %8lu kB\n", active_anon);
3210 printme = lbuf;
3211 } else if (startswith(line, "Inactive(anon)")) {
3212 snprintf(lbuf, 100, "Inactive(anon): %8lu kB\n", inactive_anon);
3213 printme = lbuf;
3214 } else if (startswith(line, "Active(file)")) {
3215 snprintf(lbuf, 100, "Active(file): %8lu kB\n", active_file);
3216 printme = lbuf;
3217 } else if (startswith(line, "Inactive(file)")) {
3218 snprintf(lbuf, 100, "Inactive(file): %8lu kB\n", inactive_file);
3219 printme = lbuf;
3220 } else if (startswith(line, "Unevictable")) {
3221 snprintf(lbuf, 100, "Unevictable: %8lu kB\n", unevictable);
3222 printme = lbuf;
3223 } else if (startswith(line, "SReclaimable")) {
3224 snprintf(lbuf, 100, "SReclaimable: %8lu kB\n", 0UL);
3225 printme = lbuf;
3226 } else if (startswith(line, "SUnreclaim")) {
3227 snprintf(lbuf, 100, "SUnreclaim: %8lu kB\n", 0UL);
3228 printme = lbuf;
3229 } else
3230 printme = line;
3231
3232 l = snprintf(cache, cache_size, "%s", printme);
3233 if (l < 0) {
3234 perror("Error writing to cache");
3235 rv = 0;
3236 goto err;
3237
3238 }
3239 if (l >= cache_size) {
3240 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3241 rv = 0;
3242 goto err;
3243 }
3244
3245 cache += l;
3246 cache_size -= l;
3247 total_len += l;
3248 }
3249
3250 d->cached = 1;
3251 d->size = total_len;
3252 if (total_len > size ) total_len = size;
3253 memcpy(buf, d->buf, total_len);
3254
3255 rv = total_len;
3256 err:
3257 if (f)
3258 fclose(f);
3259 free(line);
3260 free(cg);
3261 free(memusage_str);
3262 free(memswlimit_str);
3263 free(memswusage_str);
3264 free(memstat_str);
3265 free(memswlimit_default_str);
3266 free(memswusage_default_str);
3267 return rv;
3268 }
3269
3270 /*
3271 * Read the cpuset.cpus for cg
3272 * Return the answer in a newly allocated string which must be freed
3273 */
3274 static char *get_cpuset(const char *cg)
3275 {
3276 char *answer;
3277
3278 if (!cgfs_get_value("cpuset", cg, "cpuset.cpus", &answer))
3279 return NULL;
3280 return answer;
3281 }
3282
3283 bool cpu_in_cpuset(int cpu, const char *cpuset);
3284
3285 static bool cpuline_in_cpuset(const char *line, const char *cpuset)
3286 {
3287 int cpu;
3288
3289 if (sscanf(line, "processor : %d", &cpu) != 1)
3290 return false;
3291 return cpu_in_cpuset(cpu, cpuset);
3292 }
3293
3294 /*
3295 * check whether this is a '^processor" line in /proc/cpuinfo
3296 */
3297 static bool is_processor_line(const char *line)
3298 {
3299 int cpu;
3300
3301 if (sscanf(line, "processor : %d", &cpu) == 1)
3302 return true;
3303 return false;
3304 }
3305
3306 static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
3307 struct fuse_file_info *fi)
3308 {
3309 struct fuse_context *fc = fuse_get_context();
3310 struct file_info *d = (struct file_info *)fi->fh;
3311 char *cg;
3312 char *cpuset = NULL;
3313 char *line = NULL;
3314 size_t linelen = 0, total_len = 0, rv = 0;
3315 bool am_printing = false, firstline = true, is_s390x = false;
3316 int curcpu = -1, cpu;
3317 char *cache = d->buf;
3318 size_t cache_size = d->buflen;
3319 FILE *f = NULL;
3320
3321 if (offset){
3322 if (offset > d->size)
3323 return -EINVAL;
3324 if (!d->cached)
3325 return 0;
3326 int left = d->size - offset;
3327 total_len = left > size ? size: left;
3328 memcpy(buf, cache + offset, total_len);
3329 return total_len;
3330 }
3331
3332 pid_t initpid = lookup_initpid_in_store(fc->pid);
3333 if (initpid <= 0)
3334 initpid = fc->pid;
3335 cg = get_pid_cgroup(initpid, "cpuset");
3336 if (!cg)
3337 return read_file("proc/cpuinfo", buf, size, d);
3338 prune_init_slice(cg);
3339
3340 cpuset = get_cpuset(cg);
3341 if (!cpuset)
3342 goto err;
3343
3344 f = fopen("/proc/cpuinfo", "r");
3345 if (!f)
3346 goto err;
3347
3348 while (getline(&line, &linelen, f) != -1) {
3349 ssize_t l;
3350 if (firstline) {
3351 firstline = false;
3352 if (strstr(line, "IBM/S390") != NULL) {
3353 is_s390x = true;
3354 am_printing = true;
3355 continue;
3356 }
3357 }
3358 if (strncmp(line, "# processors:", 12) == 0)
3359 continue;
3360 if (is_processor_line(line)) {
3361 am_printing = cpuline_in_cpuset(line, cpuset);
3362 if (am_printing) {
3363 curcpu ++;
3364 l = snprintf(cache, cache_size, "processor : %d\n", curcpu);
3365 if (l < 0) {
3366 perror("Error writing to cache");
3367 rv = 0;
3368 goto err;
3369 }
3370 if (l >= cache_size) {
3371 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3372 rv = 0;
3373 goto err;
3374 }
3375 cache += l;
3376 cache_size -= l;
3377 total_len += l;
3378 }
3379 continue;
3380 } else if (is_s390x && sscanf(line, "processor %d:", &cpu) == 1) {
3381 char *p;
3382 if (!cpu_in_cpuset(cpu, cpuset))
3383 continue;
3384 curcpu ++;
3385 p = strchr(line, ':');
3386 if (!p || !*p)
3387 goto err;
3388 p++;
3389 l = snprintf(cache, cache_size, "processor %d:%s", curcpu, p);
3390 if (l < 0) {
3391 perror("Error writing to cache");
3392 rv = 0;
3393 goto err;
3394 }
3395 if (l >= cache_size) {
3396 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3397 rv = 0;
3398 goto err;
3399 }
3400 cache += l;
3401 cache_size -= l;
3402 total_len += l;
3403 continue;
3404
3405 }
3406 if (am_printing) {
3407 l = snprintf(cache, cache_size, "%s", line);
3408 if (l < 0) {
3409 perror("Error writing to cache");
3410 rv = 0;
3411 goto err;
3412 }
3413 if (l >= cache_size) {
3414 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3415 rv = 0;
3416 goto err;
3417 }
3418 cache += l;
3419 cache_size -= l;
3420 total_len += l;
3421 }
3422 }
3423
3424 if (is_s390x) {
3425 char *origcache = d->buf;
3426 ssize_t l;
3427 do {
3428 d->buf = malloc(d->buflen);
3429 } while (!d->buf);
3430 cache = d->buf;
3431 cache_size = d->buflen;
3432 total_len = 0;
3433 l = snprintf(cache, cache_size, "vendor_id : IBM/S390\n");
3434 if (l < 0 || l >= cache_size) {
3435 free(origcache);
3436 goto err;
3437 }
3438 cache_size -= l;
3439 cache += l;
3440 total_len += l;
3441 l = snprintf(cache, cache_size, "# processors : %d\n", curcpu + 1);
3442 if (l < 0 || l >= cache_size) {
3443 free(origcache);
3444 goto err;
3445 }
3446 cache_size -= l;
3447 cache += l;
3448 total_len += l;
3449 l = snprintf(cache, cache_size, "%s", origcache);
3450 free(origcache);
3451 if (l < 0 || l >= cache_size)
3452 goto err;
3453 total_len += l;
3454 }
3455
3456 d->cached = 1;
3457 d->size = total_len;
3458 if (total_len > size ) total_len = size;
3459
3460 /* read from off 0 */
3461 memcpy(buf, d->buf, total_len);
3462 rv = total_len;
3463 err:
3464 if (f)
3465 fclose(f);
3466 free(line);
3467 free(cpuset);
3468 free(cg);
3469 return rv;
3470 }
3471
3472 static int proc_stat_read(char *buf, size_t size, off_t offset,
3473 struct fuse_file_info *fi)
3474 {
3475 struct fuse_context *fc = fuse_get_context();
3476 struct file_info *d = (struct file_info *)fi->fh;
3477 char *cg;
3478 char *cpuset = NULL;
3479 char *line = NULL;
3480 size_t linelen = 0, total_len = 0, rv = 0;
3481 int curcpu = -1; /* cpu numbering starts at 0 */
3482 unsigned long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0;
3483 unsigned long user_sum = 0, nice_sum = 0, system_sum = 0, idle_sum = 0, iowait_sum = 0,
3484 irq_sum = 0, softirq_sum = 0, steal_sum = 0, guest_sum = 0;
3485 #define CPUALL_MAX_SIZE BUF_RESERVE_SIZE
3486 char cpuall[CPUALL_MAX_SIZE];
3487 /* reserve for cpu all */
3488 char *cache = d->buf + CPUALL_MAX_SIZE;
3489 size_t cache_size = d->buflen - CPUALL_MAX_SIZE;
3490 FILE *f = NULL;
3491
3492 if (offset){
3493 if (offset > d->size)
3494 return -EINVAL;
3495 if (!d->cached)
3496 return 0;
3497 int left = d->size - offset;
3498 total_len = left > size ? size: left;
3499 memcpy(buf, d->buf + offset, total_len);
3500 return total_len;
3501 }
3502
3503 pid_t initpid = lookup_initpid_in_store(fc->pid);
3504 if (initpid <= 0)
3505 initpid = fc->pid;
3506 cg = get_pid_cgroup(initpid, "cpuset");
3507 if (!cg)
3508 return read_file("/proc/stat", buf, size, d);
3509 prune_init_slice(cg);
3510
3511 cpuset = get_cpuset(cg);
3512 if (!cpuset)
3513 goto err;
3514
3515 f = fopen("/proc/stat", "r");
3516 if (!f)
3517 goto err;
3518
3519 //skip first line
3520 if (getline(&line, &linelen, f) < 0) {
3521 lxcfs_error("%s\n", "proc_stat_read read first line failed.");
3522 goto err;
3523 }
3524
3525 while (getline(&line, &linelen, f) != -1) {
3526 ssize_t l;
3527 int cpu;
3528 char cpu_char[10]; /* That's a lot of cores */
3529 char *c;
3530
3531 if (strlen(line) == 0)
3532 continue;
3533 if (sscanf(line, "cpu%9[^ ]", cpu_char) != 1) {
3534 /* not a ^cpuN line containing a number N, just print it */
3535 l = snprintf(cache, cache_size, "%s", line);
3536 if (l < 0) {
3537 perror("Error writing to cache");
3538 rv = 0;
3539 goto err;
3540 }
3541 if (l >= cache_size) {
3542 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3543 rv = 0;
3544 goto err;
3545 }
3546 cache += l;
3547 cache_size -= l;
3548 total_len += l;
3549 continue;
3550 }
3551
3552 if (sscanf(cpu_char, "%d", &cpu) != 1)
3553 continue;
3554 if (!cpu_in_cpuset(cpu, cpuset))
3555 continue;
3556 curcpu ++;
3557
3558 c = strchr(line, ' ');
3559 if (!c)
3560 continue;
3561 l = snprintf(cache, cache_size, "cpu%d%s", curcpu, c);
3562 if (l < 0) {
3563 perror("Error writing to cache");
3564 rv = 0;
3565 goto err;
3566
3567 }
3568 if (l >= cache_size) {
3569 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3570 rv = 0;
3571 goto err;
3572 }
3573
3574 cache += l;
3575 cache_size -= l;
3576 total_len += l;
3577
3578 if (sscanf(line, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu", &user, &nice, &system, &idle, &iowait, &irq,
3579 &softirq, &steal, &guest) != 9)
3580 continue;
3581 user_sum += user;
3582 nice_sum += nice;
3583 system_sum += system;
3584 idle_sum += idle;
3585 iowait_sum += iowait;
3586 irq_sum += irq;
3587 softirq_sum += softirq;
3588 steal_sum += steal;
3589 guest_sum += guest;
3590 }
3591
3592 cache = d->buf;
3593
3594 int cpuall_len = snprintf(cpuall, CPUALL_MAX_SIZE, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
3595 "cpu ", user_sum, nice_sum, system_sum, idle_sum, iowait_sum, irq_sum, softirq_sum, steal_sum, guest_sum);
3596 if (cpuall_len > 0 && cpuall_len < CPUALL_MAX_SIZE){
3597 memcpy(cache, cpuall, cpuall_len);
3598 cache += cpuall_len;
3599 } else{
3600 /* shouldn't happen */
3601 lxcfs_error("proc_stat_read copy cpuall failed, cpuall_len=%d.", cpuall_len);
3602 cpuall_len = 0;
3603 }
3604
3605 memmove(cache, d->buf + CPUALL_MAX_SIZE, total_len);
3606 total_len += cpuall_len;
3607 d->cached = 1;
3608 d->size = total_len;
3609 if (total_len > size ) total_len = size;
3610
3611 memcpy(buf, d->buf, total_len);
3612 rv = total_len;
3613
3614 err:
3615 if (f)
3616 fclose(f);
3617 free(line);
3618 free(cpuset);
3619 free(cg);
3620 return rv;
3621 }
3622
3623 static long int getreaperage(pid_t pid)
3624 {
3625 char fnam[100];
3626 struct stat sb;
3627 int ret;
3628 pid_t qpid;
3629
3630 qpid = lookup_initpid_in_store(pid);
3631 if (qpid <= 0)
3632 return 0;
3633
3634 ret = snprintf(fnam, 100, "/proc/%d", qpid);
3635 if (ret < 0 || ret >= 100)
3636 return 0;
3637
3638 if (lstat(fnam, &sb) < 0)
3639 return 0;
3640
3641 return time(NULL) - sb.st_ctime;
3642 }
3643
3644 static unsigned long get_reaper_busy(pid_t task)
3645 {
3646 pid_t initpid = lookup_initpid_in_store(task);
3647 char *cgroup = NULL, *usage_str = NULL;
3648 unsigned long usage = 0;
3649
3650 if (initpid <= 0)
3651 return 0;
3652
3653 cgroup = get_pid_cgroup(initpid, "cpuacct");
3654 if (!cgroup)
3655 goto out;
3656 prune_init_slice(cgroup);
3657 if (!cgfs_get_value("cpuacct", cgroup, "cpuacct.usage", &usage_str))
3658 goto out;
3659 usage = strtoul(usage_str, NULL, 10);
3660 usage /= 1000000000;
3661
3662 out:
3663 free(cgroup);
3664 free(usage_str);
3665 return usage;
3666 }
3667
3668 #if RELOADTEST
3669 void iwashere(void)
3670 {
3671 int fd;
3672
3673 fd = creat("/tmp/lxcfs-iwashere", 0644);
3674 if (fd >= 0)
3675 close(fd);
3676 }
3677 #endif
3678
3679 /*
3680 * We read /proc/uptime and reuse its second field.
3681 * For the first field, we use the mtime for the reaper for
3682 * the calling pid as returned by getreaperage
3683 */
3684 static int proc_uptime_read(char *buf, size_t size, off_t offset,
3685 struct fuse_file_info *fi)
3686 {
3687 struct fuse_context *fc = fuse_get_context();
3688 struct file_info *d = (struct file_info *)fi->fh;
3689 long int reaperage = getreaperage(fc->pid);
3690 unsigned long int busytime = get_reaper_busy(fc->pid), idletime;
3691 char *cache = d->buf;
3692 ssize_t total_len = 0;
3693
3694 #if RELOADTEST
3695 iwashere();
3696 #endif
3697
3698 if (offset){
3699 if (offset > d->size)
3700 return -EINVAL;
3701 if (!d->cached)
3702 return 0;
3703 int left = d->size - offset;
3704 total_len = left > size ? size: left;
3705 memcpy(buf, cache + offset, total_len);
3706 return total_len;
3707 }
3708
3709 idletime = reaperage - busytime;
3710 if (idletime > reaperage)
3711 idletime = reaperage;
3712
3713 total_len = snprintf(d->buf, d->size, "%ld.0 %lu.0\n", reaperage, idletime);
3714 if (total_len < 0){
3715 perror("Error writing to cache");
3716 return 0;
3717 }
3718
3719 d->size = (int)total_len;
3720 d->cached = 1;
3721
3722 if (total_len > size) total_len = size;
3723
3724 memcpy(buf, d->buf, total_len);
3725 return total_len;
3726 }
3727
3728 static int proc_diskstats_read(char *buf, size_t size, off_t offset,
3729 struct fuse_file_info *fi)
3730 {
3731 char dev_name[72];
3732 struct fuse_context *fc = fuse_get_context();
3733 struct file_info *d = (struct file_info *)fi->fh;
3734 char *cg;
3735 char *io_serviced_str = NULL, *io_merged_str = NULL, *io_service_bytes_str = NULL,
3736 *io_wait_time_str = NULL, *io_service_time_str = NULL;
3737 unsigned long read = 0, write = 0;
3738 unsigned long read_merged = 0, write_merged = 0;
3739 unsigned long read_sectors = 0, write_sectors = 0;
3740 unsigned long read_ticks = 0, write_ticks = 0;
3741 unsigned long ios_pgr = 0, tot_ticks = 0, rq_ticks = 0;
3742 unsigned long rd_svctm = 0, wr_svctm = 0, rd_wait = 0, wr_wait = 0;
3743 char *cache = d->buf;
3744 size_t cache_size = d->buflen;
3745 char *line = NULL;
3746 size_t linelen = 0, total_len = 0, rv = 0;
3747 unsigned int major = 0, minor = 0;
3748 int i = 0;
3749 FILE *f = NULL;
3750
3751 if (offset){
3752 if (offset > d->size)
3753 return -EINVAL;
3754 if (!d->cached)
3755 return 0;
3756 int left = d->size - offset;
3757 total_len = left > size ? size: left;
3758 memcpy(buf, cache + offset, total_len);
3759 return total_len;
3760 }
3761
3762 pid_t initpid = lookup_initpid_in_store(fc->pid);
3763 if (initpid <= 0)
3764 initpid = fc->pid;
3765 cg = get_pid_cgroup(initpid, "blkio");
3766 if (!cg)
3767 return read_file("/proc/diskstats", buf, size, d);
3768 prune_init_slice(cg);
3769
3770 if (!cgfs_get_value("blkio", cg, "blkio.io_serviced_recursive", &io_serviced_str))
3771 goto err;
3772 if (!cgfs_get_value("blkio", cg, "blkio.io_merged_recursive", &io_merged_str))
3773 goto err;
3774 if (!cgfs_get_value("blkio", cg, "blkio.io_service_bytes_recursive", &io_service_bytes_str))
3775 goto err;
3776 if (!cgfs_get_value("blkio", cg, "blkio.io_wait_time_recursive", &io_wait_time_str))
3777 goto err;
3778 if (!cgfs_get_value("blkio", cg, "blkio.io_service_time_recursive", &io_service_time_str))
3779 goto err;
3780
3781
3782 f = fopen("/proc/diskstats", "r");
3783 if (!f)
3784 goto err;
3785
3786 while (getline(&line, &linelen, f) != -1) {
3787 ssize_t l;
3788 char lbuf[256];
3789
3790 i = sscanf(line, "%u %u %71s", &major, &minor, dev_name);
3791 if (i != 3)
3792 continue;
3793
3794 get_blkio_io_value(io_serviced_str, major, minor, "Read", &read);
3795 get_blkio_io_value(io_serviced_str, major, minor, "Write", &write);
3796 get_blkio_io_value(io_merged_str, major, minor, "Read", &read_merged);
3797 get_blkio_io_value(io_merged_str, major, minor, "Write", &write_merged);
3798 get_blkio_io_value(io_service_bytes_str, major, minor, "Read", &read_sectors);
3799 read_sectors = read_sectors/512;
3800 get_blkio_io_value(io_service_bytes_str, major, minor, "Write", &write_sectors);
3801 write_sectors = write_sectors/512;
3802
3803 get_blkio_io_value(io_service_time_str, major, minor, "Read", &rd_svctm);
3804 rd_svctm = rd_svctm/1000000;
3805 get_blkio_io_value(io_wait_time_str, major, minor, "Read", &rd_wait);
3806 rd_wait = rd_wait/1000000;
3807 read_ticks = rd_svctm + rd_wait;
3808
3809 get_blkio_io_value(io_service_time_str, major, minor, "Write", &wr_svctm);
3810 wr_svctm = wr_svctm/1000000;
3811 get_blkio_io_value(io_wait_time_str, major, minor, "Write", &wr_wait);
3812 wr_wait = wr_wait/1000000;
3813 write_ticks = wr_svctm + wr_wait;
3814
3815 get_blkio_io_value(io_service_time_str, major, minor, "Total", &tot_ticks);
3816 tot_ticks = tot_ticks/1000000;
3817
3818 memset(lbuf, 0, 256);
3819 if (read || write || read_merged || write_merged || read_sectors || write_sectors || read_ticks || write_ticks)
3820 snprintf(lbuf, 256, "%u %u %s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
3821 major, minor, dev_name, read, read_merged, read_sectors, read_ticks,
3822 write, write_merged, write_sectors, write_ticks, ios_pgr, tot_ticks, rq_ticks);
3823 else
3824 continue;
3825
3826 l = snprintf(cache, cache_size, "%s", lbuf);
3827 if (l < 0) {
3828 perror("Error writing to fuse buf");
3829 rv = 0;
3830 goto err;
3831 }
3832 if (l >= cache_size) {
3833 lxcfs_error("%s\n", "Internal error: truncated write to cache.");
3834 rv = 0;
3835 goto err;
3836 }
3837 cache += l;
3838 cache_size -= l;
3839 total_len += l;
3840 }
3841
3842 d->cached = 1;
3843 d->size = total_len;
3844 if (total_len > size ) total_len = size;
3845 memcpy(buf, d->buf, total_len);
3846
3847 rv = total_len;
3848 err:
3849 free(cg);
3850 if (f)
3851 fclose(f);
3852 free(line);
3853 free(io_serviced_str);
3854 free(io_merged_str);
3855 free(io_service_bytes_str);
3856 free(io_wait_time_str);
3857 free(io_service_time_str);
3858 return rv;
3859 }
3860
3861 static int proc_swaps_read(char *buf, size_t size, off_t offset,
3862 struct fuse_file_info *fi)
3863 {
3864 struct fuse_context *fc = fuse_get_context();
3865 struct file_info *d = (struct file_info *)fi->fh;
3866 char *cg = NULL;
3867 char *memswlimit_str = NULL, *memlimit_str = NULL, *memusage_str = NULL, *memswusage_str = NULL,
3868 *memswlimit_default_str = NULL, *memswusage_default_str = NULL;
3869 unsigned long memswlimit = 0, memlimit = 0, memusage = 0, memswusage = 0, swap_total = 0, swap_free = 0;
3870 ssize_t total_len = 0, rv = 0;
3871 ssize_t l = 0;
3872 char *cache = d->buf;
3873
3874 if (offset) {
3875 if (offset > d->size)
3876 return -EINVAL;
3877 if (!d->cached)
3878 return 0;
3879 int left = d->size - offset;
3880 total_len = left > size ? size: left;
3881 memcpy(buf, cache + offset, total_len);
3882 return total_len;
3883 }
3884
3885 pid_t initpid = lookup_initpid_in_store(fc->pid);
3886 if (initpid <= 0)
3887 initpid = fc->pid;
3888 cg = get_pid_cgroup(initpid, "memory");
3889 if (!cg)
3890 return read_file("/proc/swaps", buf, size, d);
3891 prune_init_slice(cg);
3892
3893 if (!cgfs_get_value("memory", cg, "memory.limit_in_bytes", &memlimit_str))
3894 goto err;
3895
3896 if (!cgfs_get_value("memory", cg, "memory.usage_in_bytes", &memusage_str))
3897 goto err;
3898
3899 memlimit = strtoul(memlimit_str, NULL, 10);
3900 memusage = strtoul(memusage_str, NULL, 10);
3901
3902 if (cgfs_get_value("memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str) &&
3903 cgfs_get_value("memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str)) {
3904
3905 /* If swap accounting is turned on, then default value is assumed to be that of cgroup / */
3906 if (!cgfs_get_value("memory", "/", "memory.memsw.limit_in_bytes", &memswlimit_default_str))
3907 goto err;
3908 if (!cgfs_get_value("memory", "/", "memory.memsw.usage_in_bytes", &memswusage_default_str))
3909 goto err;
3910
3911 memswlimit = strtoul(memswlimit_str, NULL, 10);
3912 memswusage = strtoul(memswusage_str, NULL, 10);
3913
3914 if (!strcmp(memswlimit_str, memswlimit_default_str))
3915 memswlimit = 0;
3916 if (!strcmp(memswusage_str, memswusage_default_str))
3917 memswusage = 0;
3918
3919 swap_total = (memswlimit - memlimit) / 1024;
3920 swap_free = (memswusage - memusage) / 1024;
3921 }
3922
3923 total_len = snprintf(d->buf, d->size, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
3924
3925 /* When no mem + swap limit is specified or swapaccount=0*/
3926 if (!memswlimit) {
3927 char *line = NULL;
3928 size_t linelen = 0;
3929 FILE *f = fopen("/proc/meminfo", "r");
3930
3931 if (!f)
3932 goto err;
3933
3934 while (getline(&line, &linelen, f) != -1) {
3935 if (startswith(line, "SwapTotal:")) {
3936 sscanf(line, "SwapTotal: %8lu kB", &swap_total);
3937 } else if (startswith(line, "SwapFree:")) {
3938 sscanf(line, "SwapFree: %8lu kB", &swap_free);
3939 }
3940 }
3941
3942 free(line);
3943 fclose(f);
3944 }
3945
3946 if (swap_total > 0) {
3947 l = snprintf(d->buf + total_len, d->size - total_len,
3948 "none%*svirtual\t\t%lu\t%lu\t0\n", 36, " ",
3949 swap_total, swap_free);
3950 total_len += l;
3951 }
3952
3953 if (total_len < 0 || l < 0) {
3954 perror("Error writing to cache");
3955 rv = 0;
3956 goto err;
3957 }
3958
3959 d->cached = 1;
3960 d->size = (int)total_len;
3961
3962 if (total_len > size) total_len = size;
3963 memcpy(buf, d->buf, total_len);
3964 rv = total_len;
3965
3966 err:
3967 free(cg);
3968 free(memswlimit_str);
3969 free(memlimit_str);
3970 free(memusage_str);
3971 free(memswusage_str);
3972 free(memswusage_default_str);
3973 free(memswlimit_default_str);
3974 return rv;
3975 }
3976
3977 static off_t get_procfile_size(const char *which)
3978 {
3979 FILE *f = fopen(which, "r");
3980 char *line = NULL;
3981 size_t len = 0;
3982 ssize_t sz, answer = 0;
3983 if (!f)
3984 return 0;
3985
3986 while ((sz = getline(&line, &len, f)) != -1)
3987 answer += sz;
3988 fclose (f);
3989 free(line);
3990
3991 return answer;
3992 }
3993
3994 int proc_getattr(const char *path, struct stat *sb)
3995 {
3996 struct timespec now;
3997
3998 memset(sb, 0, sizeof(struct stat));
3999 if (clock_gettime(CLOCK_REALTIME, &now) < 0)
4000 return -EINVAL;
4001 sb->st_uid = sb->st_gid = 0;
4002 sb->st_atim = sb->st_mtim = sb->st_ctim = now;
4003 if (strcmp(path, "/proc") == 0) {
4004 sb->st_mode = S_IFDIR | 00555;
4005 sb->st_nlink = 2;
4006 return 0;
4007 }
4008 if (strcmp(path, "/proc/meminfo") == 0 ||
4009 strcmp(path, "/proc/cpuinfo") == 0 ||
4010 strcmp(path, "/proc/uptime") == 0 ||
4011 strcmp(path, "/proc/stat") == 0 ||
4012 strcmp(path, "/proc/diskstats") == 0 ||
4013 strcmp(path, "/proc/swaps") == 0) {
4014 sb->st_size = 0;
4015 sb->st_mode = S_IFREG | 00444;
4016 sb->st_nlink = 1;
4017 return 0;
4018 }
4019
4020 return -ENOENT;
4021 }
4022
4023 int proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
4024 struct fuse_file_info *fi)
4025 {
4026 if (filler(buf, ".", NULL, 0) != 0 ||
4027 filler(buf, "..", NULL, 0) != 0 ||
4028 filler(buf, "cpuinfo", NULL, 0) != 0 ||
4029 filler(buf, "meminfo", NULL, 0) != 0 ||
4030 filler(buf, "stat", NULL, 0) != 0 ||
4031 filler(buf, "uptime", NULL, 0) != 0 ||
4032 filler(buf, "diskstats", NULL, 0) != 0 ||
4033 filler(buf, "swaps", NULL, 0) != 0)
4034 return -EINVAL;
4035 return 0;
4036 }
4037
4038 int proc_open(const char *path, struct fuse_file_info *fi)
4039 {
4040 int type = -1;
4041 struct file_info *info;
4042
4043 if (strcmp(path, "/proc/meminfo") == 0)
4044 type = LXC_TYPE_PROC_MEMINFO;
4045 else if (strcmp(path, "/proc/cpuinfo") == 0)
4046 type = LXC_TYPE_PROC_CPUINFO;
4047 else if (strcmp(path, "/proc/uptime") == 0)
4048 type = LXC_TYPE_PROC_UPTIME;
4049 else if (strcmp(path, "/proc/stat") == 0)
4050 type = LXC_TYPE_PROC_STAT;
4051 else if (strcmp(path, "/proc/diskstats") == 0)
4052 type = LXC_TYPE_PROC_DISKSTATS;
4053 else if (strcmp(path, "/proc/swaps") == 0)
4054 type = LXC_TYPE_PROC_SWAPS;
4055 if (type == -1)
4056 return -ENOENT;
4057
4058 info = malloc(sizeof(*info));
4059 if (!info)
4060 return -ENOMEM;
4061
4062 memset(info, 0, sizeof(*info));
4063 info->type = type;
4064
4065 info->buflen = get_procfile_size(path) + BUF_RESERVE_SIZE;
4066 do {
4067 info->buf = malloc(info->buflen);
4068 } while (!info->buf);
4069 memset(info->buf, 0, info->buflen);
4070 /* set actual size to buffer size */
4071 info->size = info->buflen;
4072
4073 fi->fh = (unsigned long)info;
4074 return 0;
4075 }
4076
4077 int proc_access(const char *path, int mask)
4078 {
4079 if (strcmp(path, "/proc") == 0 && access(path, R_OK) == 0)
4080 return 0;
4081
4082 /* these are all read-only */
4083 if ((mask & ~R_OK) != 0)
4084 return -EACCES;
4085 return 0;
4086 }
4087
4088 int proc_release(const char *path, struct fuse_file_info *fi)
4089 {
4090 do_release_file_info(fi);
4091 return 0;
4092 }
4093
4094 int proc_read(const char *path, char *buf, size_t size, off_t offset,
4095 struct fuse_file_info *fi)
4096 {
4097 struct file_info *f = (struct file_info *) fi->fh;
4098
4099 switch (f->type) {
4100 case LXC_TYPE_PROC_MEMINFO:
4101 return proc_meminfo_read(buf, size, offset, fi);
4102 case LXC_TYPE_PROC_CPUINFO:
4103 return proc_cpuinfo_read(buf, size, offset, fi);
4104 case LXC_TYPE_PROC_UPTIME:
4105 return proc_uptime_read(buf, size, offset, fi);
4106 case LXC_TYPE_PROC_STAT:
4107 return proc_stat_read(buf, size, offset, fi);
4108 case LXC_TYPE_PROC_DISKSTATS:
4109 return proc_diskstats_read(buf, size, offset, fi);
4110 case LXC_TYPE_PROC_SWAPS:
4111 return proc_swaps_read(buf, size, offset, fi);
4112 default:
4113 return -EINVAL;
4114 }
4115 }
4116
4117 /*
4118 * Functions needed to setup cgroups in the __constructor__.
4119 */
4120
4121 static bool mkdir_p(const char *dir, mode_t mode)
4122 {
4123 const char *tmp = dir;
4124 const char *orig = dir;
4125 char *makeme;
4126
4127 do {
4128 dir = tmp + strspn(tmp, "/");
4129 tmp = dir + strcspn(dir, "/");
4130 makeme = strndup(orig, dir - orig);
4131 if (!makeme)
4132 return false;
4133 if (mkdir(makeme, mode) && errno != EEXIST) {
4134 lxcfs_error("Failed to create directory '%s': %s.\n",
4135 makeme, strerror(errno));
4136 free(makeme);
4137 return false;
4138 }
4139 free(makeme);
4140 } while(tmp != dir);
4141
4142 return true;
4143 }
4144
4145 static bool umount_if_mounted(void)
4146 {
4147 if (umount2(BASEDIR, MNT_DETACH) < 0 && errno != EINVAL) {
4148 lxcfs_error("Failed to unmount %s: %s.\n", BASEDIR, strerror(errno));
4149 return false;
4150 }
4151 return true;
4152 }
4153
4154 /* __typeof__ should be safe to use with all compilers. */
4155 typedef __typeof__(((struct statfs *)NULL)->f_type) fs_type_magic;
4156 static bool has_fs_type(const struct statfs *fs, fs_type_magic magic_val)
4157 {
4158 return (fs->f_type == (fs_type_magic)magic_val);
4159 }
4160
4161 /*
4162 * looking at fs/proc_namespace.c, it appears we can
4163 * actually expect the rootfs entry to very specifically contain
4164 * " - rootfs rootfs "
4165 * IIUC, so long as we've chrooted so that rootfs is not our root,
4166 * the rootfs entry should always be skipped in mountinfo contents.
4167 */
4168 static bool is_on_ramfs(void)
4169 {
4170 FILE *f;
4171 char *p, *p2;
4172 char *line = NULL;
4173 size_t len = 0;
4174 int i;
4175
4176 f = fopen("/proc/self/mountinfo", "r");
4177 if (!f)
4178 return false;
4179
4180 while (getline(&line, &len, f) != -1) {
4181 for (p = line, i = 0; p && i < 4; i++)
4182 p = strchr(p + 1, ' ');
4183 if (!p)
4184 continue;
4185 p2 = strchr(p + 1, ' ');
4186 if (!p2)
4187 continue;
4188 *p2 = '\0';
4189 if (strcmp(p + 1, "/") == 0) {
4190 // this is '/'. is it the ramfs?
4191 p = strchr(p2 + 1, '-');
4192 if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
4193 free(line);
4194 fclose(f);
4195 return true;
4196 }
4197 }
4198 }
4199 free(line);
4200 fclose(f);
4201 return false;
4202 }
4203
4204 static int pivot_enter()
4205 {
4206 int ret = -1, oldroot = -1, newroot = -1;
4207
4208 oldroot = open("/", O_DIRECTORY | O_RDONLY);
4209 if (oldroot < 0) {
4210 lxcfs_error("%s\n", "Failed to open old root for fchdir.");
4211 return ret;
4212 }
4213
4214 newroot = open(ROOTDIR, O_DIRECTORY | O_RDONLY);
4215 if (newroot < 0) {
4216 lxcfs_error("%s\n", "Failed to open new root for fchdir.");
4217 goto err;
4218 }
4219
4220 /* change into new root fs */
4221 if (fchdir(newroot) < 0) {
4222 lxcfs_error("Failed to change directory to new rootfs: %s.\n", ROOTDIR);
4223 goto err;
4224 }
4225
4226 /* pivot_root into our new root fs */
4227 if (pivot_root(".", ".") < 0) {
4228 lxcfs_error("pivot_root() syscall failed: %s.\n", strerror(errno));
4229 goto err;
4230 }
4231
4232 /*
4233 * At this point the old-root is mounted on top of our new-root.
4234 * To unmounted it we must not be chdir'd into it, so escape back
4235 * to the old-root.
4236 */
4237 if (fchdir(oldroot) < 0) {
4238 lxcfs_error("%s\n", "Failed to enter old root.");
4239 goto err;
4240 }
4241
4242 if (umount2(".", MNT_DETACH) < 0) {
4243 lxcfs_error("%s\n", "Failed to detach old root.");
4244 goto err;
4245 }
4246
4247 if (fchdir(newroot) < 0) {
4248 lxcfs_error("%s\n", "Failed to re-enter new root.");
4249 goto err;
4250 }
4251
4252 ret = 0;
4253
4254 err:
4255 if (oldroot > 0)
4256 close(oldroot);
4257 if (newroot > 0)
4258 close(newroot);
4259
4260 return ret;
4261 }
4262
4263 static int chroot_enter()
4264 {
4265 if (mount(ROOTDIR, "/", NULL, MS_REC | MS_BIND, NULL)) {
4266 lxcfs_error("Failed to recursively bind-mount %s into /.", ROOTDIR);
4267 return -1;
4268 }
4269
4270 if (chroot(".") < 0) {
4271 lxcfs_error("Call to chroot() failed: %s.\n", strerror(errno));
4272 return -1;
4273 }
4274
4275 if (chdir("/") < 0) {
4276 lxcfs_error("Failed to change directory: %s.\n", strerror(errno));
4277 return -1;
4278 }
4279
4280 return 0;
4281 }
4282
4283 static int permute_and_enter(void)
4284 {
4285 struct statfs sb;
4286
4287 if (statfs("/", &sb) < 0) {
4288 lxcfs_error("%s\n", "Could not stat / mountpoint.");
4289 return -1;
4290 }
4291
4292 /* has_fs_type() is not reliable. When the ramfs is a tmpfs it will
4293 * likely report TMPFS_MAGIC. Hence, when it reports no we still check
4294 * /proc/1/mountinfo. */
4295 if (has_fs_type(&sb, RAMFS_MAGIC) || is_on_ramfs())
4296 return chroot_enter();
4297
4298 if (pivot_enter() < 0) {
4299 lxcfs_error("%s\n", "Could not perform pivot root.");
4300 return -1;
4301 }
4302
4303 return 0;
4304 }
4305
4306 /* Prepare our new clean root. */
4307 static int permute_prepare(void)
4308 {
4309 if (mkdir(ROOTDIR, 0700) < 0 && errno != EEXIST) {
4310 lxcfs_error("%s\n", "Failed to create directory for new root.");
4311 return -1;
4312 }
4313
4314 if (mount("/", ROOTDIR, NULL, MS_BIND, 0) < 0) {
4315 lxcfs_error("Failed to bind-mount / for new root: %s.\n", strerror(errno));
4316 return -1;
4317 }
4318
4319 if (mount(RUNTIME_PATH, ROOTDIR RUNTIME_PATH, NULL, MS_BIND, 0) < 0) {
4320 lxcfs_error("Failed to bind-mount /run into new root: %s.\n", strerror(errno));
4321 return -1;
4322 }
4323
4324 if (mount(BASEDIR, ROOTDIR BASEDIR, NULL, MS_REC | MS_MOVE, 0) < 0) {
4325 printf("Failed to move " BASEDIR " into new root: %s.\n", strerror(errno));
4326 return -1;
4327 }
4328
4329 return 0;
4330 }
4331
4332 /* Calls chroot() on ramfs, pivot_root() in all other cases. */
4333 static bool permute_root(void)
4334 {
4335 /* Prepare new root. */
4336 if (permute_prepare() < 0)
4337 return false;
4338
4339 /* Pivot into new root. */
4340 if (permute_and_enter() < 0)
4341 return false;
4342
4343 return true;
4344 }
4345
4346 static bool cgfs_prepare_mounts(void)
4347 {
4348 if (!mkdir_p(BASEDIR, 0700)) {
4349 lxcfs_error("%s\n", "Failed to create lxcfs cgroup mountpoint.");
4350 return false;
4351 }
4352
4353 if (!umount_if_mounted()) {
4354 lxcfs_error("%s\n", "Failed to clean up old lxcfs cgroup mountpoint.");
4355 return false;
4356 }
4357
4358 if (unshare(CLONE_NEWNS) < 0) {
4359 lxcfs_error("Failed to unshare mount namespace: %s.\n", strerror(errno));
4360 return false;
4361 }
4362
4363 if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) {
4364 lxcfs_error("Failed to remount / private: %s.\n", strerror(errno));
4365 return false;
4366 }
4367
4368 if (mount("tmpfs", BASEDIR, "tmpfs", 0, "size=100000,mode=700") < 0) {
4369 lxcfs_error("%s\n", "Failed to mount tmpfs over lxcfs cgroup mountpoint.");
4370 return false;
4371 }
4372
4373 return true;
4374 }
4375
4376 static bool cgfs_mount_hierarchies(void)
4377 {
4378 char *target;
4379 size_t clen, len;
4380 int i, ret;
4381
4382 for (i = 0; i < num_hierarchies; i++) {
4383 char *controller = hierarchies[i];
4384 clen = strlen(controller);
4385 len = strlen(BASEDIR) + clen + 2;
4386 target = malloc(len);
4387 if (!target)
4388 return false;
4389 ret = snprintf(target, len, "%s/%s", BASEDIR, controller);
4390 if (ret < 0 || ret >= len) {
4391 free(target);
4392 return false;
4393 }
4394 if (mkdir(target, 0755) < 0 && errno != EEXIST) {
4395 free(target);
4396 return false;
4397 }
4398 if (mount(controller, target, "cgroup", 0, controller) < 0) {
4399 lxcfs_error("Failed mounting cgroup %s\n", controller);
4400 free(target);
4401 return false;
4402 }
4403
4404 fd_hierarchies[i] = open(target, O_DIRECTORY);
4405 if (fd_hierarchies[i] < 0) {
4406 free(target);
4407 return false;
4408 }
4409 free(target);
4410 }
4411 return true;
4412 }
4413
4414 static bool cgfs_setup_controllers(void)
4415 {
4416 if (!cgfs_prepare_mounts())
4417 return false;
4418
4419 if (!cgfs_mount_hierarchies()) {
4420 lxcfs_error("%s\n", "Failed to set up private lxcfs cgroup mounts.");
4421 return false;
4422 }
4423
4424 if (!permute_root())
4425 return false;
4426
4427 return true;
4428 }
4429
4430 static int preserve_ns(int pid)
4431 {
4432 int ret;
4433 size_t len = 5 /* /proc */ + 21 /* /int_as_str */ + 7 /* /ns/mnt */ + 1 /* \0 */;
4434 char path[len];
4435
4436 ret = snprintf(path, len, "/proc/%d/ns/mnt", pid);
4437 if (ret < 0 || (size_t)ret >= len)
4438 return -1;
4439
4440 return open(path, O_RDONLY | O_CLOEXEC);
4441 }
4442
4443 static void __attribute__((constructor)) collect_and_mount_subsystems(void)
4444 {
4445 FILE *f;
4446 char *cret, *line = NULL;
4447 char cwd[MAXPATHLEN];
4448 size_t len = 0;
4449 int i, init_ns = -1;
4450
4451 if ((f = fopen("/proc/self/cgroup", "r")) == NULL) {
4452 lxcfs_error("Error opening /proc/self/cgroup: %s\n", strerror(errno));
4453 return;
4454 }
4455
4456 while (getline(&line, &len, f) != -1) {
4457 char *p, *p2;
4458
4459 p = strchr(line, ':');
4460 if (!p)
4461 goto out;
4462 *(p++) = '\0';
4463
4464 p2 = strrchr(p, ':');
4465 if (!p2)
4466 goto out;
4467 *p2 = '\0';
4468
4469 /* With cgroupv2 /proc/self/cgroup can contain entries of the
4470 * form: 0::/ This will cause lxcfs to fail the cgroup mounts
4471 * because it parses out the empty string "" and later on passes
4472 * it to mount(). Let's skip such entries.
4473 */
4474 if (!strcmp(p, ""))
4475 continue;
4476
4477 if (!store_hierarchy(line, p))
4478 goto out;
4479 }
4480
4481 /* Preserve initial namespace. */
4482 init_ns = preserve_ns(getpid());
4483 if (init_ns < 0) {
4484 lxcfs_error("%s\n", "Failed to preserve initial mount namespace.");
4485 goto out;
4486 }
4487
4488 fd_hierarchies = malloc(sizeof(int *) * num_hierarchies);
4489 if (!fd_hierarchies) {
4490 lxcfs_error("%s\n", strerror(errno));
4491 goto out;
4492 }
4493
4494 for (i = 0; i < num_hierarchies; i++)
4495 fd_hierarchies[i] = -1;
4496
4497 cret = getcwd(cwd, MAXPATHLEN);
4498 if (!cret)
4499 lxcfs_debug("Could not retrieve current working directory: %s.\n", strerror(errno));
4500
4501 /* This function calls unshare(CLONE_NEWNS) our initial mount namespace
4502 * to privately mount lxcfs cgroups. */
4503 if (!cgfs_setup_controllers()) {
4504 lxcfs_error("%s\n", "Failed to setup private cgroup mounts for lxcfs.");
4505 goto out;
4506 }
4507
4508 if (setns(init_ns, 0) < 0) {
4509 lxcfs_error("Failed to switch back to initial mount namespace: %s.\n", strerror(errno));
4510 goto out;
4511 }
4512
4513 if (!cret || chdir(cwd) < 0)
4514 lxcfs_debug("Could not change back to original working directory: %s.\n", strerror(errno));
4515
4516 print_subsystems();
4517
4518 out:
4519 free(line);
4520 fclose(f);
4521 if (init_ns >= 0)
4522 close(init_ns);
4523 }
4524
4525 static void __attribute__((destructor)) free_subsystems(void)
4526 {
4527 int i;
4528
4529 lxcfs_debug("%s\n", "Running destructor for liblxcfs.");
4530
4531 for (i = 0; i < num_hierarchies; i++) {
4532 if (hierarchies[i])
4533 free(hierarchies[i]);
4534 if (fd_hierarchies && fd_hierarchies[i] >= 0)
4535 close(fd_hierarchies[i]);
4536 }
4537 free(hierarchies);
4538 free(fd_hierarchies);
4539 }