diff options
-rw-r--r-- | src/firejail/cgroup.c | 83 | ||||
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/join.c | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 9 | ||||
-rw-r--r-- | src/firejail/profile.c | 10 | ||||
-rw-r--r-- | src/man/firejail.txt | 4 |
6 files changed, 64 insertions, 47 deletions
diff --git a/src/firejail/cgroup.c b/src/firejail/cgroup.c index e7ffbca36..38b3c32d3 100644 --- a/src/firejail/cgroup.c +++ b/src/firejail/cgroup.c | |||
@@ -18,7 +18,8 @@ | |||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
19 | */ | 19 | */ |
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/stat.h> | 21 | #include <sys/wait.h> |
22 | #include <errno.h> | ||
22 | 23 | ||
23 | #define MAXBUF 4096 | 24 | #define MAXBUF 4096 |
24 | 25 | ||
@@ -68,52 +69,60 @@ errout: | |||
68 | fclose(fp); | 69 | fclose(fp); |
69 | } | 70 | } |
70 | 71 | ||
72 | static int is_cgroup_path(const char *fname) { | ||
73 | // path starts with /sys/fs/cgroup | ||
74 | if (strncmp(fname, "/sys/fs/cgroup", 14) != 0) | ||
75 | return 0; | ||
71 | 76 | ||
72 | void set_cgroup(const char *path) { | 77 | // no .. traversal |
73 | EUID_ASSERT(); | 78 | char *ptr = strstr(fname, ".."); |
79 | if (ptr) | ||
80 | return 0; | ||
74 | 81 | ||
75 | invalid_filename(path, 0); // no globbing | 82 | return 1; |
83 | } | ||
76 | 84 | ||
77 | // path starts with /sys/fs/cgroup | 85 | void check_cgroup_file(const char *fname) { |
78 | if (strncmp(path, "/sys/fs/cgroup", 14) != 0) | 86 | assert(fname); |
79 | goto errout; | 87 | invalid_filename(fname, 0); // no globbing |
80 | 88 | ||
81 | // path ends in tasks | 89 | if (!is_cgroup_path(fname)) |
82 | char *ptr = strstr(path, "tasks"); | ||
83 | if (!ptr) | ||
84 | goto errout; | ||
85 | if (*(ptr + 5) != '\0') | ||
86 | goto errout; | 90 | goto errout; |
87 | 91 | ||
88 | // no .. traversal | 92 | const char *base = gnu_basename(fname); |
89 | ptr = strstr(path, ".."); | 93 | if (strcmp(base, "tasks") != 0 && // cgroup v1 |
90 | if (ptr) | 94 | strcmp(base, "cgroup.procs") != 0) |
91 | goto errout; | 95 | goto errout; |
92 | 96 | ||
93 | // tasks file exists | 97 | if (access(fname, W_OK) == 0) |
94 | FILE *fp = fopen(path, "ae"); | 98 | return; |
95 | if (!fp) | ||
96 | goto errout; | ||
97 | // task file belongs to the user running the sandbox | ||
98 | int fd = fileno(fp); | ||
99 | if (fd == -1) | ||
100 | errExit("fileno"); | ||
101 | struct stat s; | ||
102 | if (fstat(fd, &s) == -1) | ||
103 | errExit("fstat"); | ||
104 | if (s.st_uid != getuid() && s.st_gid != getgid()) | ||
105 | goto errout2; | ||
106 | // add the task to cgroup | ||
107 | pid_t pid = getpid(); | ||
108 | int rv = fprintf(fp, "%d\n", pid); | ||
109 | (void) rv; | ||
110 | fclose(fp); | ||
111 | return; | ||
112 | 99 | ||
113 | errout: | 100 | errout: |
114 | fprintf(stderr, "Error: invalid cgroup\n"); | 101 | fprintf(stderr, "Error: invalid cgroup\n"); |
115 | exit(1); | 102 | exit(1); |
116 | errout2: | 103 | } |
117 | fprintf(stderr, "Error: you don't have permissions to use this control group\n"); | 104 | |
118 | exit(1); | 105 | static void do_set_cgroup(const char *fname, pid_t pid) { |
106 | FILE *fp = fopen(fname, "ae"); | ||
107 | if (!fp) { | ||
108 | fwarning("cannot open %s for writing: %s\n", fname, strerror(errno)); | ||
109 | return; | ||
110 | } | ||
111 | |||
112 | int rv = fprintf(fp, "%d\n", pid); | ||
113 | (void) rv; | ||
114 | fclose(fp); | ||
115 | } | ||
116 | |||
117 | void set_cgroup(const char *fname, pid_t pid) { | ||
118 | pid_t child = fork(); | ||
119 | if (child < 0) | ||
120 | errExit("fork"); | ||
121 | if (child == 0) { | ||
122 | drop_privs(0); | ||
123 | |||
124 | do_set_cgroup(fname, pid); | ||
125 | _exit(0); | ||
126 | } | ||
127 | waitpid(child, NULL, 0); | ||
119 | } | 128 | } |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 45075d137..d29c2a976 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -647,7 +647,8 @@ void cpu_print_filter(pid_t pid) __attribute__((noreturn)); | |||
647 | // cgroup.c | 647 | // cgroup.c |
648 | void save_cgroup(void); | 648 | void save_cgroup(void); |
649 | void load_cgroup(const char *fname); | 649 | void load_cgroup(const char *fname); |
650 | void set_cgroup(const char *path); | 650 | void check_cgroup_file(const char *fname); |
651 | void set_cgroup(const char *fname, pid_t pid); | ||
651 | 652 | ||
652 | // output.c | 653 | // output.c |
653 | void check_output(int argc, char **argv); | 654 | void check_output(int argc, char **argv); |
diff --git a/src/firejail/join.c b/src/firejail/join.c index a869f6b64..0e76fd944 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -431,7 +431,7 @@ void join(pid_t pid, int argc, char **argv, int index) { | |||
431 | 431 | ||
432 | // set cgroup | 432 | // set cgroup |
433 | if (cfg.cgroup) // not available for uid 0 | 433 | if (cfg.cgroup) // not available for uid 0 |
434 | set_cgroup(cfg.cgroup); | 434 | set_cgroup(cfg.cgroup, getpid()); |
435 | 435 | ||
436 | // join namespaces | 436 | // join namespaces |
437 | if (arg_join_network) { | 437 | if (arg_join_network) { |
diff --git a/src/firejail/main.c b/src/firejail/main.c index cc5186204..c5b3d5739 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -1529,15 +1529,16 @@ int main(int argc, char **argv, char **envp) { | |||
1529 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { | 1529 | else if (strncmp(argv[i], "--cgroup=", 9) == 0) { |
1530 | if (checkcfg(CFG_CGROUP)) { | 1530 | if (checkcfg(CFG_CGROUP)) { |
1531 | if (option_cgroup) { | 1531 | if (option_cgroup) { |
1532 | fprintf(stderr, "Error: only a cgroup can be defined\n"); | 1532 | fprintf(stderr, "Error: only one cgroup can be defined\n"); |
1533 | exit(1); | 1533 | exit(1); |
1534 | } | 1534 | } |
1535 | |||
1536 | option_cgroup = 1; | ||
1537 | cfg.cgroup = strdup(argv[i] + 9); | 1535 | cfg.cgroup = strdup(argv[i] + 9); |
1538 | if (!cfg.cgroup) | 1536 | if (!cfg.cgroup) |
1539 | errExit("strdup"); | 1537 | errExit("strdup"); |
1540 | set_cgroup(cfg.cgroup); | 1538 | |
1539 | check_cgroup_file(cfg.cgroup); | ||
1540 | set_cgroup(cfg.cgroup, getpid()); | ||
1541 | option_cgroup = 1; | ||
1541 | } | 1542 | } |
1542 | else | 1543 | else |
1543 | exit_err_feature("cgroup"); | 1544 | exit_err_feature("cgroup"); |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 5390249ea..9d92b6199 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1129,8 +1129,14 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
1129 | 1129 | ||
1130 | // cgroup | 1130 | // cgroup |
1131 | if (strncmp(ptr, "cgroup ", 7) == 0) { | 1131 | if (strncmp(ptr, "cgroup ", 7) == 0) { |
1132 | if (checkcfg(CFG_CGROUP)) | 1132 | if (checkcfg(CFG_CGROUP)) { |
1133 | set_cgroup(ptr + 7); | 1133 | cfg.cgroup = strdup(ptr + 7); |
1134 | if (!cfg.cgroup) | ||
1135 | errExit("strdup"); | ||
1136 | |||
1137 | check_cgroup_file(cfg.cgroup); | ||
1138 | set_cgroup(cfg.cgroup, getpid()); | ||
1139 | } | ||
1134 | else | 1140 | else |
1135 | warning_feature_disabled("cgroup"); | 1141 | warning_feature_disabled("cgroup"); |
1136 | return 0; | 1142 | return 0; |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 2883ab257..154def585 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -290,8 +290,8 @@ $ firejail \-\-caps.print=3272 | |||
290 | Print content of file from sandbox container, see FILE TRANSFER section for more details. | 290 | Print content of file from sandbox container, see FILE TRANSFER section for more details. |
291 | #endif | 291 | #endif |
292 | .TP | 292 | .TP |
293 | \fB\-\-cgroup=tasks-file | 293 | \fB\-\-cgroup=file |
294 | Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. | 294 | Place the sandbox in the specified control group. file is the full path of a tasks or cgroup.procs file. |
295 | .br | 295 | .br |
296 | 296 | ||
297 | .br | 297 | .br |