aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2021-10-16 11:57:30 +0200
committerLibravatar smitsohu <smitsohu@gmail.com>2021-10-16 12:19:10 +0200
commita99dca846401f7990df087aae6a712868ec5b033 (patch)
tree2ecaea99ad7e45853e3495c0337b31da74c04568
parentbuild: allow building with sanitizer (#4594) (diff)
downloadfirejail-a99dca846401f7990df087aae6a712868ec5b033.tar.gz
firejail-a99dca846401f7990df087aae6a712868ec5b033.tar.zst
firejail-a99dca846401f7990df087aae6a712868ec5b033.zip
cgroup: minor refactor, add v2 support, bugfixes
Adds minimal cgroupv2 support, and fixes an effective user id assertion in --join (instead of asserting effective user id of the user, drop privileges completely in a child process).
-rw-r--r--src/firejail/cgroup.c83
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/join.c2
-rw-r--r--src/firejail/main.c9
-rw-r--r--src/firejail/profile.c10
-rw-r--r--src/man/firejail.txt4
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
72static 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
72void 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 85void 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
113errout: 100errout:
114 fprintf(stderr, "Error: invalid cgroup\n"); 101 fprintf(stderr, "Error: invalid cgroup\n");
115 exit(1); 102 exit(1);
116errout2: 103}
117 fprintf(stderr, "Error: you don't have permissions to use this control group\n"); 104
118 exit(1); 105static 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
117void 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
648void save_cgroup(void); 648void save_cgroup(void);
649void load_cgroup(const char *fname); 649void load_cgroup(const char *fname);
650void set_cgroup(const char *path); 650void check_cgroup_file(const char *fname);
651void set_cgroup(const char *fname, pid_t pid);
651 652
652// output.c 653// output.c
653void check_output(int argc, char **argv); 654void 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
290Print content of file from sandbox container, see FILE TRANSFER section for more details. 290Print 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
294Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. 294Place 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