aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar smitsohu <smitsohu@gmail.com>2019-12-25 17:23:17 +0100
committerLibravatar GitHub <noreply@github.com>2019-12-25 17:23:17 +0100
commit7119cc7da54c415369ea60a1a31905c4aed34571 (patch)
treef33ca36c35dea54ed87adb30c305023f85580231 /src
parentFix private-lib in gconf.profile (diff)
parentlet is_ready_for_join() return a boolean (diff)
downloadfirejail-7119cc7da54c415369ea60a1a31905c4aed34571.tar.gz
firejail-7119cc7da54c415369ea60a1a31905c4aed34571.tar.zst
firejail-7119cc7da54c415369ea60a1a31905c4aed34571.zip
Merge pull request #3093 from smitsohu/join
add join timeout and make it configurable
Diffstat (limited to 'src')
-rw-r--r--src/firejail/caps.c17
-rw-r--r--src/firejail/checkcfg.c6
-rw-r--r--src/firejail/cpu.c4
-rw-r--r--src/firejail/firejail.h4
-rw-r--r--src/firejail/join.c121
-rw-r--r--src/firejail/ls.c17
-rw-r--r--src/firejail/network_main.c17
-rw-r--r--src/firejail/protocol.c17
-rw-r--r--src/firejail/seccomp.c17
-rw-r--r--src/firejail/util.c80
10 files changed, 117 insertions, 183 deletions
diff --git a/src/firejail/caps.c b/src/firejail/caps.c
index 71dd9430b..738675766 100644
--- a/src/firejail/caps.c
+++ b/src/firejail/caps.c
@@ -404,21 +404,8 @@ void caps_print_filter(pid_t pid) {
404 // in case the pid is that of a firejail process, use the pid of the first child process 404 // in case the pid is that of a firejail process, use the pid of the first child process
405 pid = switch_to_child(pid); 405 pid = switch_to_child(pid);
406 406
407 // now check if the pid belongs to a firejail sandbox 407 // exit if no permission to join the sandbox
408 if (invalid_sandbox(pid)) { 408 check_join_permission(pid);
409 fprintf(stderr, "Error: no valid sandbox\n");
410 exit(1);
411 }
412
413 // check privileges for non-root users
414 uid_t uid = getuid();
415 if (uid != 0) {
416 uid_t sandbox_uid = pid_get_uid(pid);
417 if (uid != sandbox_uid) {
418 fprintf(stderr, "Error: permission denied.\n");
419 exit(1);
420 }
421 }
422 409
423 uint64_t caps = extract_caps(pid); 410 uint64_t caps = extract_caps(pid);
424 int i; 411 int i;
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c
index f94b95d60..d6b591133 100644
--- a/src/firejail/checkcfg.c
+++ b/src/firejail/checkcfg.c
@@ -31,6 +31,7 @@ char *xpra_extra_params = "";
31char *xvfb_screen = "800x600x24"; 31char *xvfb_screen = "800x600x24";
32char *xvfb_extra_params = ""; 32char *xvfb_extra_params = "";
33char *netfilter_default = NULL; 33char *netfilter_default = NULL;
34unsigned long join_timeout = 5000000; // microseconds
34 35
35int checkcfg(int val) { 36int checkcfg(int val) {
36 assert(val < CFG_MAX); 37 assert(val < CFG_MAX);
@@ -213,6 +214,11 @@ int checkcfg(int val) {
213 if (setenv("FIREJAIL_FILE_COPY_LIMIT", ptr + 16, 1) == -1) 214 if (setenv("FIREJAIL_FILE_COPY_LIMIT", ptr + 16, 1) == -1)
214 errExit("setenv"); 215 errExit("setenv");
215 } 216 }
217
218 // timeout for join option
219 else if (strncmp(ptr, "join-timeout ", 13) == 0)
220 join_timeout = strtoul(ptr + 13, NULL, 10) * 1000000; // seconds to microseconds
221
216 else 222 else
217 goto errout; 223 goto errout;
218 224
diff --git a/src/firejail/cpu.c b/src/firejail/cpu.c
index 7a0807257..702186eaf 100644
--- a/src/firejail/cpu.c
+++ b/src/firejail/cpu.c
@@ -170,13 +170,11 @@ void cpu_print_filter(pid_t pid) {
170 pid = switch_to_child(pid); 170 pid = switch_to_child(pid);
171 171
172 // now check if the pid belongs to a firejail sandbox 172 // now check if the pid belongs to a firejail sandbox
173 if (invalid_sandbox(pid)) { 173 if (is_ready_for_join(pid) == false) {
174 fprintf(stderr, "Error: no valid sandbox\n"); 174 fprintf(stderr, "Error: no valid sandbox\n");
175 exit(1); 175 exit(1);
176 } 176 }
177 177
178
179
180 print_cpu(pid); 178 print_cpu(pid);
181 exit(0); 179 exit(0);
182} 180}
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index fdbeb4691..03bcbda46 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -426,6 +426,8 @@ void usage(void);
426 426
427// join.c 427// join.c
428void join(pid_t pid, int argc, char **argv, int index); 428void join(pid_t pid, int argc, char **argv, int index);
429bool is_ready_for_join(const pid_t pid);
430void check_join_permission(pid_t pid);
429pid_t switch_to_child(pid_t pid); 431pid_t switch_to_child(pid_t pid);
430 432
431// shutdown.c 433// shutdown.c
@@ -491,7 +493,6 @@ unsigned extract_timeout(const char *str);
491void disable_file_or_dir(const char *fname); 493void disable_file_or_dir(const char *fname);
492void disable_file_path(const char *path, const char *file); 494void disable_file_path(const char *path, const char *file);
493int safe_fd(const char *path, int flags); 495int safe_fd(const char *path, int flags);
494int invalid_sandbox(const pid_t pid);
495int has_handler(pid_t pid, int signal); 496int has_handler(pid_t pid, int signal);
496void enter_network_namespace(pid_t pid); 497void enter_network_namespace(pid_t pid);
497 498
@@ -737,6 +738,7 @@ extern char *xpra_extra_params;
737extern char *xvfb_screen; 738extern char *xvfb_screen;
738extern char *xvfb_extra_params; 739extern char *xvfb_extra_params;
739extern char *netfilter_default; 740extern char *netfilter_default;
741extern unsigned long join_timeout;
740int checkcfg(int val); 742int checkcfg(int val);
741void print_compiletime_support(void); 743void print_compiletime_support(void);
742 744
diff --git a/src/firejail/join.c b/src/firejail/join.c
index 46dae0271..1494c782f 100644
--- a/src/firejail/join.c
+++ b/src/firejail/join.c
@@ -255,32 +255,114 @@ static void extract_umask(pid_t pid) {
255 fclose(fp); 255 fclose(fp);
256} 256}
257 257
258// return false if the sandbox identified by pid is not fully set up yet or if
259// it is no firejail sandbox at all, return true if the sandbox is complete
260bool is_ready_for_join(const pid_t pid) {
261 EUID_ASSERT();
262 // check if a file "ready-for-join" exists
263 char *fname;
264 if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_READY_FOR_JOIN) == -1)
265 errExit("asprintf");
266 EUID_ROOT();
267 FILE *fp = fopen(fname, "re");
268 EUID_USER();
269 free(fname);
270 if (!fp)
271 return false;
272 // regular file owned by root
273 int fd = fileno(fp);
274 if (fd == -1)
275 errExit("fileno");
276 struct stat s;
277 if (fstat(fd, &s) == -1)
278 errExit("fstat");
279 if (!S_ISREG(s.st_mode) || s.st_uid != 0) {
280 fclose(fp);
281 return false;
282 }
283 // check if it is non-empty
284 char buf[BUFLEN];
285 if (fgets(buf, BUFLEN, fp) == NULL) {
286 fclose(fp);
287 return false;
288 }
289 fclose(fp);
290 // confirm "ready" string was written
291 if (strcmp(buf, "ready\n") != 0)
292 return false;
293
294 // walk down the process tree a few nodes, there should be no firejail leaf
295#define MAXNODES 5
296 pid_t current = pid, next;
297 int i;
298 for (i = 0; i < MAXNODES; i++) {
299 if (find_child(current, &next) == 1) {
300 // found a leaf
301 EUID_ROOT();
302 char *comm = pid_proc_comm(current);
303 EUID_USER();
304 if (!comm) {
305 fprintf(stderr, "Error: cannot read /proc file\n");
306 exit(1);
307 }
308 if (strcmp(comm, "firejail") == 0) {
309 free(comm);
310 return false;
311 }
312 free(comm);
313 break;
314 }
315 current = next;
316 }
317
318 return true;
319}
320
321#define SNOOZE 100000 // sleep interval in microseconds
322void check_join_permission(pid_t pid) {
323 // check if pid belongs to a fully set up firejail sandbox
324 unsigned long i;
325 for (i = 0; is_ready_for_join(pid) == false; i += SNOOZE) { // give sandbox some time to start up
326 if (i >= join_timeout) {
327 fprintf(stderr, "Error: no valid sandbox\n");
328 exit(1);
329 }
330 usleep(SNOOZE);
331 }
332 // check privileges for non-root users
333 uid_t uid = getuid();
334 if (uid != 0) {
335 uid_t sandbox_uid = pid_get_uid(pid);
336 if (uid != sandbox_uid) {
337 fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n");
338 exit(1);
339 }
340 }
341}
342
258pid_t switch_to_child(pid_t pid) { 343pid_t switch_to_child(pid_t pid) {
344 EUID_ASSERT();
259 EUID_ROOT(); 345 EUID_ROOT();
346 pid_t rv = pid;
260 errno = 0; 347 errno = 0;
261 char *comm = pid_proc_comm(pid); 348 char *comm = pid_proc_comm(pid);
262 if (!comm) { 349 if (!comm) {
263 if (errno == ENOENT) { 350 if (errno == ENOENT)
264 fprintf(stderr, "Error: cannot find process with pid %d\n", pid); 351 fprintf(stderr, "Error: cannot find process with pid %d\n", pid);
265 exit(1); 352 else
266 }
267 else {
268 fprintf(stderr, "Error: cannot read /proc file\n"); 353 fprintf(stderr, "Error: cannot read /proc file\n");
269 exit(1); 354 exit(1);
270 }
271 } 355 }
272 EUID_USER(); 356 EUID_USER();
273 if (strcmp(comm, "firejail") == 0) { 357 if (strcmp(comm, "firejail") == 0) {
274 pid_t child; 358 if (find_child(pid, &rv) == 1) {
275 if (find_child(pid, &child) == 1) {
276 fprintf(stderr, "Error: no valid sandbox\n"); 359 fprintf(stderr, "Error: no valid sandbox\n");
277 exit(1); 360 exit(1);
278 } 361 }
279 fmessage("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) child); 362 fmessage("Switching to pid %u, the first child process inside the sandbox\n", (unsigned) rv);
280 pid = child;
281 } 363 }
282 free(comm); 364 free(comm);
283 return pid; 365 return rv;
284} 366}
285 367
286 368
@@ -292,21 +374,8 @@ void join(pid_t pid, int argc, char **argv, int index) {
292 // in case the pid is that of a firejail process, use the pid of the first child process 374 // in case the pid is that of a firejail process, use the pid of the first child process
293 pid = switch_to_child(pid); 375 pid = switch_to_child(pid);
294 376
295 // now check if the pid belongs to a firejail sandbox 377 // exit if no permission to join the sandbox
296 if (invalid_sandbox(pid)) { 378 check_join_permission(pid);
297 fprintf(stderr, "Error: no valid sandbox\n");
298 exit(1);
299 }
300
301 // check privileges for non-root users
302 uid_t uid = getuid();
303 if (uid != 0) {
304 uid_t sandbox_uid = pid_get_uid(pid);
305 if (uid != sandbox_uid) {
306 fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n");
307 exit(1);
308 }
309 }
310 379
311 extract_x11_display(parent); 380 extract_x11_display(parent);
312 381
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 08cf5f16a..75333fdc2 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -215,21 +215,8 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
215 // in case the pid is that of a firejail process, use the pid of the first child process 215 // in case the pid is that of a firejail process, use the pid of the first child process
216 pid = switch_to_child(pid); 216 pid = switch_to_child(pid);
217 217
218 // now check if the pid belongs to a firejail sandbox 218 // exit if no permission to join the sandbox
219 if (invalid_sandbox(pid)) { 219 check_join_permission(pid);
220 fprintf(stderr, "Error: no valid sandbox\n");
221 exit(1);
222 }
223
224 // check privileges for non-root users
225 uid_t uid = getuid();
226 if (uid != 0) {
227 uid_t sandbox_uid = pid_get_uid(pid);
228 if (uid != sandbox_uid) {
229 fprintf(stderr, "Error: permission denied.\n");
230 exit(1);
231 }
232 }
233 220
234 // expand paths 221 // expand paths
235 char *fname1 = expand_path(path1);; 222 char *fname1 = expand_path(path1);;
diff --git a/src/firejail/network_main.c b/src/firejail/network_main.c
index 6a199469a..6800bde8d 100644
--- a/src/firejail/network_main.c
+++ b/src/firejail/network_main.c
@@ -272,21 +272,8 @@ void net_dns_print(pid_t pid) {
272 // in case the pid is that of a firejail process, use the pid of the first child process 272 // in case the pid is that of a firejail process, use the pid of the first child process
273 pid = switch_to_child(pid); 273 pid = switch_to_child(pid);
274 274
275 // now check if the pid belongs to a firejail sandbox 275 // exit if no permission to join the sandbox
276 if (invalid_sandbox(pid)) { 276 check_join_permission(pid);
277 fprintf(stderr, "Error: no valid sandbox\n");
278 exit(1);
279 }
280
281 // check privileges for non-root users
282 uid_t uid = getuid();
283 if (uid != 0) {
284 uid_t sandbox_uid = pid_get_uid(pid);
285 if (uid != sandbox_uid) {
286 fprintf(stderr, "Error: permission denied.\n");
287 exit(1);
288 }
289 }
290 277
291 EUID_ROOT(); 278 EUID_ROOT();
292 if (join_namespace(pid, "mnt")) 279 if (join_namespace(pid, "mnt"))
diff --git a/src/firejail/protocol.c b/src/firejail/protocol.c
index 72d29c671..d3a9e0153 100644
--- a/src/firejail/protocol.c
+++ b/src/firejail/protocol.c
@@ -67,21 +67,8 @@ void protocol_print_filter(pid_t pid) {
67 // in case the pid is that of a firejail process, use the pid of the first child process 67 // in case the pid is that of a firejail process, use the pid of the first child process
68 pid = switch_to_child(pid); 68 pid = switch_to_child(pid);
69 69
70 // now check if the pid belongs to a firejail sandbox 70 // exit if no permission to join the sandbox
71 if (invalid_sandbox(pid)) { 71 check_join_permission(pid);
72 fprintf(stderr, "Error: no valid sandbox\n");
73 exit(1);
74 }
75
76 // check privileges for non-root users
77 uid_t uid = getuid();
78 if (uid != 0) {
79 uid_t sandbox_uid = pid_get_uid(pid);
80 if (uid != sandbox_uid) {
81 fprintf(stderr, "Error: permission denied.\n");
82 exit(1);
83 }
84 }
85 72
86 // find the seccomp filter 73 // find the seccomp filter
87 EUID_ROOT(); 74 EUID_ROOT();
diff --git a/src/firejail/seccomp.c b/src/firejail/seccomp.c
index 609ebb7be..648ce1612 100644
--- a/src/firejail/seccomp.c
+++ b/src/firejail/seccomp.c
@@ -332,21 +332,8 @@ void seccomp_print_filter(pid_t pid) {
332 // in case the pid is that of a firejail process, use the pid of the first child process 332 // in case the pid is that of a firejail process, use the pid of the first child process
333 pid = switch_to_child(pid); 333 pid = switch_to_child(pid);
334 334
335 // now check if the pid belongs to a firejail sandbox 335 // exit if no permission to join the sandbox
336 if (invalid_sandbox(pid)) { 336 check_join_permission(pid);
337 fprintf(stderr, "Error: no valid sandbox\n");
338 exit(1);
339 }
340
341 // check privileges for non-root users
342 uid_t uid = getuid();
343 if (uid != 0) {
344 uid_t sandbox_uid = pid_get_uid(pid);
345 if (uid != sandbox_uid) {
346 fprintf(stderr, "Error: permission denied.\n");
347 exit(1);
348 }
349 }
350 337
351 // find the seccomp list file 338 // find the seccomp list file
352 EUID_ROOT(); 339 EUID_ROOT();
diff --git a/src/firejail/util.c b/src/firejail/util.c
index dd70d68a9..18d121ca9 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -1200,69 +1200,6 @@ errexit:
1200 exit(1); 1200 exit(1);
1201} 1201}
1202 1202
1203
1204// return 1 if the sandbox identified by pid is not fully set up yet or if
1205// it is no firejail sandbox at all, return 0 if the sandbox is complete
1206int invalid_sandbox(const pid_t pid) {
1207 // check if a file "ready-for-join" exists
1208 char *fname;
1209 if (asprintf(&fname, "/proc/%d/root%s", pid, RUN_READY_FOR_JOIN) == -1)
1210 errExit("asprintf");
1211 EUID_ROOT();
1212 FILE *fp = fopen(fname, "re");
1213 EUID_USER();
1214 free(fname);
1215 if (!fp)
1216 return 1;
1217 // regular file owned by root
1218 int fd = fileno(fp);
1219 if (fd == -1)
1220 errExit("fileno");
1221 struct stat s;
1222 if (fstat(fd, &s) == -1)
1223 errExit("fstat");
1224 if (!S_ISREG(s.st_mode) || s.st_uid != 0) {
1225 fclose(fp);
1226 return 1;
1227 }
1228 // check if it is non-empty
1229 char buf[BUFLEN];
1230 if (fgets(buf, BUFLEN, fp) == NULL) {
1231 fclose(fp);
1232 return 1;
1233 }
1234 fclose(fp);
1235 // confirm "ready" string was written
1236 if (strncmp(buf, "ready\n", 6) != 0)
1237 return 1;
1238
1239 // walk down the process tree a few nodes, there should be no firejail leaf
1240#define MAXNODES 5
1241 pid_t current = pid, next;
1242 int i;
1243 for (i = 0; i < MAXNODES; i++) {
1244 if (find_child(current, &next) == 1) {
1245 // found a leaf
1246 EUID_ROOT();
1247 char *comm = pid_proc_comm(current);
1248 EUID_USER();
1249 if (!comm) {
1250 fprintf(stderr, "Error: cannot read /proc file\n");
1251 exit(1);
1252 }
1253 if (strcmp(comm, "firejail") == 0) {
1254 free(comm);
1255 return 1;
1256 }
1257 free(comm);
1258 break;
1259 }
1260 current = next;
1261 }
1262
1263 return 0;
1264}
1265
1266int has_handler(pid_t pid, int signal) { 1203int has_handler(pid_t pid, int signal) {
1267 if (signal > 0 && signal <= SIGRTMAX) { 1204 if (signal > 0 && signal <= SIGRTMAX) {
1268 char *fname; 1205 char *fname;
@@ -1297,21 +1234,8 @@ void enter_network_namespace(pid_t pid) {
1297 // in case the pid is that of a firejail process, use the pid of the first child process 1234 // in case the pid is that of a firejail process, use the pid of the first child process
1298 pid_t child = switch_to_child(pid); 1235 pid_t child = switch_to_child(pid);
1299 1236
1300 // now check if the pid belongs to a firejail sandbox 1237 // exit if no permission to join the sandbox
1301 if (invalid_sandbox(child)) { 1238 check_join_permission(child);
1302 fprintf(stderr, "Error: no valid sandbox\n");
1303 exit(1);
1304 }
1305
1306 // check privileges for non-root users
1307 uid_t uid = getuid();
1308 if (uid != 0) {
1309 uid_t sandbox_uid = pid_get_uid(pid);
1310 if (uid != sandbox_uid) {
1311 fprintf(stderr, "Error: permission is denied to join a sandbox created by a different user.\n");
1312 exit(1);
1313 }
1314 }
1315 1239
1316 // check network namespace 1240 // check network namespace
1317 char *name; 1241 char *name;