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