aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-11-03 09:30:30 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-11-03 09:30:30 -0400
commite152e2d067e17be33c7e82ce438c8ae740af6a66 (patch)
tree34c1eb3a4b80b4d5973f95c23526bf4a8c1ee32f
parentremoved warning if --quiet is enabled (diff)
downloadfirejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.tar.gz
firejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.tar.zst
firejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.zip
fixed TOCTOU problem for --get and --put
-rw-r--r--RELNOTES1
-rw-r--r--src/firejail/ls.c192
-rw-r--r--src/firejail/util.c6
3 files changed, 74 insertions, 125 deletions
diff --git a/RELNOTES b/RELNOTES
index 44d313999..037f41a9b 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -1,6 +1,7 @@
1firejail (0.9.45) baseline; urgency=low 1firejail (0.9.45) baseline; urgency=low
2 * development version, work in progress 2 * development version, work in progress
3 * security: overwrite /etc/resolv.conf found by Martin Carpenter 3 * security: overwrite /etc/resolv.conf found by Martin Carpenter
4 * secuirty: TOCTOU exploit for --get and --put found by Daniel Hodson
4 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm) 5 * feature: allow root user access to /dev/shm (--noblacklist=/dev/shm)
5 * feature: split most of networking code in a separate executable 6 * feature: split most of networking code in a separate executable
6 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire 7 * new profiles: xiphos, Tor Browser Bundle, display (imagemagik), Wire
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index dba82be0b..7c5585324 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -324,22 +324,24 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
324 324
325 // get file from sandbox and store it in the current directory 325 // get file from sandbox and store it in the current directory
326 else if (op == SANDBOX_FS_GET) { 326 else if (op == SANDBOX_FS_GET) {
327 // check source file (sandbox) 327 char *src_fname =fname1;
328 char *src_fname; 328 char *dest_fname = strrchr(fname1, '/');
329 if (asprintf(&src_fname, "%s%s", rootdir, fname1) == -1) 329 if (!dest_fname || *(++dest_fname) == '\0') {
330 errExit("asprintf"); 330 fprintf(stderr, "Error: invalid file name %s\n", fname1);
331 EUID_ROOT();
332 struct stat s;
333 if (stat(src_fname, &s) == -1) {
334 fprintf(stderr, "Error: Cannot access %s\n", fname1);
335 exit(1);
336 }
337 if (is_dir(src_fname)) {
338 fprintf(stderr, "Error: source file name is a directory\n");
339 exit(1); 331 exit(1);
340 } 332 }
341 333
342 // try to open the source file - we need to chroot 334 EUID_ROOT();
335 if (arg_debug)
336 printf("copy %s to %s\n", src_fname, dest_fname);
337
338 // create a user-owned temporary file in /run/firejail directory
339 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
340 int fd = mkstemp(tmp_fname);
341 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
342 close(fd);
343
344 // copy the source file into the temporary file - we need to chroot
343 pid_t child = fork(); 345 pid_t child = fork();
344 if (child < 0) 346 if (child < 0)
345 errExit("fork"); 347 errExit("fork");
@@ -353,11 +355,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
353 // drop privileges 355 // drop privileges
354 drop_privs(0); 356 drop_privs(0);
355 357
356 // try to read the file 358 // copy the file
357 if (access(fname1, R_OK) == -1) { 359 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600))
358 fprintf(stderr, "Error: Cannot read %s\n", fname1); 360 _exit(1);
359 exit(1);
360 }
361 _exit(0); 361 _exit(0);
362 } 362 }
363 363
@@ -365,74 +365,54 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
365 int status = 0; 365 int status = 0;
366 waitpid(child, &status, 0); 366 waitpid(child, &status, 0);
367 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 367 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
368 else 368 else {
369 exit(1); 369 unlink(tmp_fname);
370 EUID_USER();
371
372 // check destination file (host)
373 char *dest_fname = strrchr(fname1, '/');
374 if (!dest_fname || *(++dest_fname) == '\0') {
375 fprintf(stderr, "Error: invalid file name %s\n", fname1);
376 exit(1); 370 exit(1);
377 } 371 }
378 372
379 if (access(dest_fname, F_OK) == -1) { 373 // copy the temporary file into the destionation file
380 // try to create the file as a regular user 374 child = fork();
381 pid_t child = fork(); 375 if (child < 0)
382 if (child < 0) 376 errExit("fork");
383 errExit("fork"); 377 if (child == 0) {
384 if (child == 0) { 378 // drop privileges
385 // drop privileges 379 drop_privs(0);
386 drop_privs(0); 380
387 381 // copy the file
388 FILE *fp = fopen(dest_fname, "w"); 382 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600))
389 if (!fp) { 383 _exit(1);
390 fprintf(stderr, "Error: cannot create %s\n", dest_fname); 384 _exit(0);
391 exit(1);
392 }
393 fclose(fp);
394 _exit(0);
395 }
396
397 // wait for the child to finish
398 int status = 0;
399 waitpid(child, &status, 0);
400 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
401 else
402 exit(1);
403 } 385 }
386
387 // wait for the child to finish
388 status = 0;
389 waitpid(child, &status, 0);
390 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
404 else { 391 else {
405 if (access(dest_fname, W_OK) == -1) { 392 unlink(tmp_fname);
406 fprintf(stderr, "Error: cannot write %s\n", dest_fname); 393 exit(1);
407 exit(1);
408 }
409 } 394 }
410 395
411 // copy file 396 // remove the temporary file
412 if (arg_debug) 397 unlink(tmp_fname);
413 printf("copy %s to %s\n", src_fname, dest_fname);
414 EUID_ROOT();
415 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
416 fprintf(stderr, "Error: transfer failed\n");
417 else
418 printf("Transfer complete\n");
419 EUID_USER(); 398 EUID_USER();
420 } 399 }
421 // get file from host and store it in the sandbox 400 // get file from host and store it in the sandbox
422 else if (op == SANDBOX_FS_PUT && path2) { 401 else if (op == SANDBOX_FS_PUT && path2) {
423 // verify the source file 402 char *src_fname =fname1;
424 const char *src_fname = path1; 403 char *dest_fname = fname2;
425 struct stat s; 404
426 if (stat(src_fname, &s) == -1) { 405 EUID_ROOT();
427 fprintf(stderr, "Error: Cannot access %s\n", fname1); 406 if (arg_debug)
428 exit(1); 407 printf("copy %s to %s\n", src_fname, dest_fname);
429 } 408
430 if (is_dir(src_fname)) { 409 // create a user-owned temporary file in /run/firejail directory
431 fprintf(stderr, "Error: source file name is a directory\n"); 410 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
432 exit(1); 411 int fd = mkstemp(tmp_fname);
433 } 412 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
434 413 close(fd);
435 // try to open the source file 414
415 // copy the source file into the temporary file - we need to chroot
436 pid_t child = fork(); 416 pid_t child = fork();
437 if (child < 0) 417 if (child < 0)
438 errExit("fork"); 418 errExit("fork");
@@ -440,11 +420,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
440 // drop privileges 420 // drop privileges
441 drop_privs(0); 421 drop_privs(0);
442 422
443 // try to read the file 423 // copy the file
444 if (access(src_fname, R_OK) == -1) { 424 if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600))
445 fprintf(stderr, "Error: Cannot read %s\n", src_fname); 425 _exit(1);
446 exit(1);
447 }
448 _exit(0); 426 _exit(0);
449 } 427 }
450 428
@@ -452,20 +430,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
452 int status = 0; 430 int status = 0;
453 waitpid(child, &status, 0); 431 waitpid(child, &status, 0);
454 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 432 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
455 else 433 else {
456 exit(1); 434 unlink(tmp_fname);
457
458 // check destination file (sandbox)
459 char *dest_fname;
460 if (asprintf(&dest_fname, "%s%s", rootdir, fname2) == -1)
461 errExit("asprintf");
462 EUID_ROOT();
463 if (is_dir(dest_fname)) {
464 fprintf(stderr, "Error: destination file name is a directory inside the sandbox\n");
465 exit(1); 435 exit(1);
466 } 436 }
467 437
468 // check write access on destination 438 // copy the temporary file into the destionation file
469 child = fork(); 439 child = fork();
470 if (child < 0) 440 if (child < 0)
471 errExit("fork"); 441 errExit("fork");
@@ -475,25 +445,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
475 errExit("chroot"); 445 errExit("chroot");
476 if (chdir("/") < 0) 446 if (chdir("/") < 0)
477 errExit("chdir"); 447 errExit("chdir");
478 448
479 // drop privileges 449 // drop privileges
480 drop_privs(0); 450 drop_privs(0);
481 451
482 if (access(path2, F_OK) == -1) { 452 // copy the file
483 FILE *fp = fopen(path2, "w"); 453 if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600))
484 if (!fp) { 454 _exit(1);
485 fprintf(stderr, "Error: cannot create %s\n", path2);
486 exit(1);
487 }
488 fclose(fp);
489 }
490 else {
491 if (access(path2, W_OK) == -1) {
492 fprintf(stderr, "Error: cannot write %s\n", path2);
493 exit(1);
494 }
495 }
496
497 _exit(0); 455 _exit(0);
498 } 456 }
499 457
@@ -501,17 +459,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
501 status = 0; 459 status = 0;
502 waitpid(child, &status, 0); 460 waitpid(child, &status, 0);
503 if (WIFEXITED(status) && WEXITSTATUS(status) == 0); 461 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
504 else 462 else {
463 unlink(tmp_fname);
505 exit(1); 464 exit(1);
506 465 }
507 // copy file 466
508 if (arg_debug) 467 // remove the temporary file
509 printf("copy %s to %s\n", src_fname, dest_fname); 468 unlink(tmp_fname);
510 EUID_ROOT();
511 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
512 fprintf(stderr, "Error: transfer failed\n");
513 else
514 printf("Transfer complete\n");
515 EUID_USER(); 469 EUID_USER();
516 } 470 }
517 471
diff --git a/src/firejail/util.c b/src/firejail/util.c
index 9752504e5..a7712441e 100644
--- a/src/firejail/util.c
+++ b/src/firejail/util.c
@@ -176,12 +176,6 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m
176 assert(srcname); 176 assert(srcname);
177 assert(destname); 177 assert(destname);
178 178
179 struct stat s;
180 if (stat(destname, &s) == 0) {
181 fprintf(stderr, "Error: file %s already exists\n", destname);
182 return -1;
183 }
184
185 // open source 179 // open source
186 int src = open(srcname, O_RDONLY); 180 int src = open(srcname, O_RDONLY);
187 if (src < 0) { 181 if (src < 0) {