aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_home.c
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-11-16 16:40:12 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2016-11-16 16:40:12 -0500
commit98159c098b6afedfed20eecdc80719dae1f914ff (patch)
treed44407914904e81dcb4bd582bdae11e558705c3d /src/firejail/fs_home.c
parentfcopy part 1 (diff)
downloadfirejail-98159c098b6afedfed20eecdc80719dae1f914ff.tar.gz
firejail-98159c098b6afedfed20eecdc80719dae1f914ff.tar.zst
firejail-98159c098b6afedfed20eecdc80719dae1f914ff.zip
fcopy part 2
Diffstat (limited to 'src/firejail/fs_home.c')
-rw-r--r--src/firejail/fs_home.c269
1 files changed, 53 insertions, 216 deletions
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 242482d26..d8cd9ce4d 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -28,7 +28,7 @@
28#include <sys/wait.h> 28#include <sys/wait.h>
29#include <unistd.h> 29#include <unistd.h>
30#include <grp.h> 30#include <grp.h>
31#include <ftw.h> 31//#include <ftw.h>
32 32
33static void skel(const char *homedir, uid_t u, gid_t g) { 33static void skel(const char *homedir, uid_t u, gid_t g) {
34 char *fname; 34 char *fname;
@@ -349,106 +349,6 @@ void fs_check_private_dir(void) {
349//*********************************************************************************** 349//***********************************************************************************
350// --private-home 350// --private-home
351//*********************************************************************************** 351//***********************************************************************************
352#define PRIVATE_COPY_LIMIT (500 * 1024 *1024)
353static int size_limit_reached = 0;
354static unsigned file_cnt = 0;
355static unsigned size_cnt = 0;
356static char *check_dir_or_file(const char *name);
357
358int fs_copydir(const char *path, const struct stat *st, int ftype, struct FTW *sftw) {
359 (void) st;
360 (void) sftw;
361 if (size_limit_reached)
362 return 0;
363
364 struct stat s;
365 char *dest;
366 if (asprintf(&dest, "%s%s", RUN_HOME_DIR, path + strlen(cfg.homedir)) == -1)
367 errExit("asprintf");
368
369 // don't copy it if we already have the file
370 if (stat(dest, &s) == 0) {
371 free(dest);
372 return 0;
373 }
374
375 // extract mode and ownership
376 if (stat(path, &s) != 0) {
377 free(dest);
378 return 0;
379 }
380
381 // check uid
382 if (s.st_uid != firejail_uid || s.st_gid != firejail_gid) {
383 free(dest);
384 return 0;
385 }
386
387 if ((s.st_size + size_cnt) > PRIVATE_COPY_LIMIT) {
388 size_limit_reached = 1;
389 free(dest);
390 return 0;
391 }
392
393 file_cnt++;
394 size_cnt += s.st_size;
395
396 if(ftype == FTW_F)
397 copy_file(path, dest, firejail_uid, firejail_gid, s.st_mode);
398 else if (ftype == FTW_D) {
399 if (mkdir(dest, s.st_mode) == -1)
400 errExit("mkdir");
401 if (set_perms(dest, firejail_uid, firejail_gid, s.st_mode))
402 errExit("set_perms");
403#if 0
404struct stat s2;
405if (stat(dest, &s2) == 0) {
406 printf("%s\t", dest);
407 printf((S_ISDIR(s.st_mode)) ? "d" : "-");
408 printf((s.st_mode & S_IRUSR) ? "r" : "-");
409 printf((s.st_mode & S_IWUSR) ? "w" : "-");
410 printf((s.st_mode & S_IXUSR) ? "x" : "-");
411 printf((s.st_mode & S_IRGRP) ? "r" : "-");
412 printf((s.st_mode & S_IWGRP) ? "w" : "-");
413 printf((s.st_mode & S_IXGRP) ? "x" : "-");
414 printf((s.st_mode & S_IROTH) ? "r" : "-");
415 printf((s.st_mode & S_IWOTH) ? "w" : "-");
416 printf((s.st_mode & S_IXOTH) ? "x" : "-");
417 printf("\n");
418}
419#endif
420
421 fs_logger2("clone", path);
422 }
423
424 free(dest);
425 return(0);
426}
427
428static void duplicate(char *name) {
429 char *fname = check_dir_or_file(name);
430
431 if (arg_debug)
432 printf("Private home: duplicating %s\n", fname);
433 assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0);
434
435 struct stat s;
436 if (stat(fname, &s) == -1) {
437 free(fname);
438 return;
439 }
440
441 if(nftw(fname, fs_copydir, 1, FTW_PHYS) != 0) {
442 fprintf(stderr, "Error: unable to copy template dir\n");
443 exit(1);
444 }
445 fs_logger_print(); // save the current log
446
447 free(fname);
448}
449
450
451
452static char *check_dir_or_file(const char *name) { 352static char *check_dir_or_file(const char *name) {
453 assert(name); 353 assert(name);
454 struct stat s; 354 struct stat s;
@@ -461,10 +361,7 @@ static char *check_dir_or_file(const char *name) {
461 361
462 // expand home directory 362 // expand home directory
463 char *fname = expand_home(name, cfg.homedir); 363 char *fname = expand_home(name, cfg.homedir);
464 if (!fname) { 364 assert(fname);
465 fprintf(stderr, "Error: file %s not found.\n", name);
466 exit(1);
467 }
468 365
469 // If it doesn't start with '/', it must be relative to homedir 366 // If it doesn't start with '/', it must be relative to homedir
470 if (fname[0] != '/') { 367 if (fname[0] != '/') {
@@ -475,31 +372,19 @@ static char *check_dir_or_file(const char *name) {
475 fname = tmp; 372 fname = tmp;
476 } 373 }
477 374
478 // check the file is in user home directory 375 // check the file is in user home directory, a full home directory is not allowed
479 char *rname = realpath(fname, NULL); 376 char *rname = realpath(fname, NULL);
480 if (!rname) { 377 if (!rname ||
378 strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0 ||
379 strcmp(rname, cfg.homedir) == 0) {
481 fprintf(stderr, "Error: invalid file %s\n", name); 380 fprintf(stderr, "Error: invalid file %s\n", name);
482 exit(1); 381 exit(1);
483 } 382 }
484 if (strncmp(rname, cfg.homedir, strlen(cfg.homedir)) != 0) {
485 fprintf(stderr, "Error: file %s is not in user home directory\n", name);
486 exit(1);
487 }
488
489 // a full home directory is not allowed
490 if (strcmp(rname, cfg.homedir) == 0) {
491 fprintf(stderr, "Error: invalid directory %s\n", rname);
492 exit(1);
493 }
494 383
495 // only top files and directories in user home are allowed 384 // only top files and directories in user home are allowed
496 char *ptr = rname + strlen(cfg.homedir); 385 char *ptr = rname + strlen(cfg.homedir);
497 if (*ptr == '\0') { 386 assert(*ptr != '\0');
498 fprintf(stderr, "Error: invalid file %s\n", name); 387 ptr = strchr(++ptr, '/');
499 exit(1);
500 }
501 ptr++;
502 ptr = strchr(ptr, '/');
503 if (ptr) { 388 if (ptr) {
504 if (*ptr != '\0') { 389 if (*ptr != '\0') {
505 fprintf(stderr, "Error: only top files and directories in user home are allowed\n"); 390 fprintf(stderr, "Error: only top files and directories in user home are allowed\n");
@@ -507,55 +392,42 @@ static char *check_dir_or_file(const char *name) {
507 } 392 }
508 } 393 }
509 394
510 if (stat(fname, &s) == -1) { 395 free(fname);
511 fprintf(stderr, "Error: file %s not found.\n", fname); 396 return rname;
512 exit(1);
513 }
514
515 // check uid
516 uid_t uid = getuid();
517 gid_t gid = getgid();
518 if (s.st_uid != uid || s.st_gid != gid) {
519 fprintf(stderr, "Error: only files or directories created by the current user are allowed.\n");
520 exit(1);
521 }
522
523 // dir or regular file
524 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) {
525 free(fname);
526 return rname; // regular exit from the function
527 }
528
529 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
530 exit(1);
531} 397}
532 398
399static void duplicate(char *name) {
400 char *fname = check_dir_or_file(name);
401 char *dest = RUN_HOME_DIR;
533 402
534// check directory list specified by user (--private-home option) - exit if it fails 403 if (arg_debug)
535void fs_check_home_list(void) { 404 printf("Private home: duplicating %s\n", fname);
536 if (strstr(cfg.home_private_keep, "..")) { 405 assert(strncmp(fname, cfg.homedir, strlen(cfg.homedir)) == 0);
537 fprintf(stderr, "Error: invalid private-home list\n");
538 exit(1);
539 }
540
541 char *dlist = strdup(cfg.home_private_keep);
542 if (!dlist)
543 errExit("strdup");
544
545 char *ptr = strtok(dlist, ",");
546 char *tmp = check_dir_or_file(ptr);
547 free(tmp);
548 406
549 while ((ptr = strtok(NULL, ",")) != NULL) { 407 struct stat s;
550 tmp = check_dir_or_file(ptr); 408 if (stat(fname, &s) == -1) {
551 free(tmp); 409 free(fname);
410 return;
411 }
412 else if (S_ISDIR(s.st_mode)) {
413 // create the directory in RUN_HOME_DIR
414 char *name;
415 char *ptr = strrchr(fname, '/');
416 ptr++;
417 if (asprintf(&name, "%s/%s", RUN_HOME_DIR, ptr) == -1)
418 errExit("asprintf");
419 mkdir_attr(name, 0755, getuid(), getgid());
420 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, name);
421 free(name);
552 } 422 }
423 else
424 sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FCOPY, fname, RUN_HOME_DIR);
425 fs_logger2("clone", fname);
426 fs_logger_print(); // save the current log
553 427
554 free(dlist); 428 free(fname);
555} 429}
556 430
557
558
559// private mode (--private-home=list): 431// private mode (--private-home=list):
560// mount homedir on top of /home/user, 432// mount homedir on top of /home/user,
561// tmpfs on top of /root in nonroot mode, 433// tmpfs on top of /root in nonroot mode,
@@ -571,8 +443,8 @@ void fs_private_home_list(void) {
571 int xflag = store_xauthority(); 443 int xflag = store_xauthority();
572 int aflag = store_asoundrc(); 444 int aflag = store_asoundrc();
573 445
574 uid_t u = firejail_uid; 446 uid_t uid = getuid();
575 gid_t g = firejail_gid; 447 gid_t gid = getgid();
576 struct stat s; 448 struct stat s;
577 if (stat(homedir, &s) == -1) { 449 if (stat(homedir, &s) == -1) {
578 fprintf(stderr, "Error: cannot find user home directory\n"); 450 fprintf(stderr, "Error: cannot find user home directory\n");
@@ -580,59 +452,24 @@ void fs_private_home_list(void) {
580 } 452 }
581 453
582 // create /run/firejail/mnt/home directory 454 // create /run/firejail/mnt/home directory
583 int rv = mkdir(RUN_HOME_DIR, 0755); 455 mkdir_attr(RUN_HOME_DIR, 0755, uid, gid);
584 if (rv == -1)
585 errExit("mkdir");
586 if (set_perms(RUN_HOME_DIR, u, g, 0755))
587 errExit("set_perms");
588 ASSERT_PERMS(RUN_HOME_DIR, u, g, 0755);
589
590 fs_logger_print(); // save the current log 456 fs_logger_print(); // save the current log
591 457
458 if (arg_debug)
459 printf("Copying files in the new home:\n");
460
592 // copy the list of files in the new home directory 461 // copy the list of files in the new home directory
593 // using a new child process without root privileges 462 char *dlist = strdup(cfg.home_private_keep);
594 pid_t child = fork(); 463 if (!dlist)
595 if (child < 0) 464 errExit("strdup");
596 errExit("fork"); 465
597 if (child == 0) { 466 char *ptr = strtok(dlist, ",");
598 if (arg_debug) 467 duplicate(ptr);
599 printf("Copying files in the new home:\n"); 468 while ((ptr = strtok(NULL, ",")) != NULL)
600
601 // drop privileges
602 if (setgroups(0, NULL) < 0)
603 errExit("setgroups");
604 if (setgid(getgid()) < 0)
605 errExit("setgid/getgid");
606 if (setuid(getuid()) < 0)
607 errExit("setuid/getuid");
608
609 // copy the list of files in the new home directory
610 char *dlist = strdup(cfg.home_private_keep);
611 if (!dlist)
612 errExit("strdup");
613
614 char *ptr = strtok(dlist, ",");
615 duplicate(ptr); 469 duplicate(ptr);
616 while ((ptr = strtok(NULL, ",")) != NULL)
617 duplicate(ptr);
618
619 if (!arg_quiet) {
620 if (size_limit_reached)
621 fprintf(stderr, "Warning: private-home copy limit of %u MB reached, not all the files were copied\n",
622 PRIVATE_COPY_LIMIT / (1024 *1024));
623 else
624 printf("Private home: %u files, total size %u bytes\n", file_cnt, size_cnt);
625 }
626 470
627 fs_logger_print(); // save the current log 471 fs_logger_print(); // save the current log
628 free(dlist); 472 free(dlist);
629#ifdef HAVE_GCOV
630 __gcov_flush();
631#endif
632 _exit(0);
633 }
634 // wait for the child to finish
635 waitpid(child, NULL, 0);
636 473
637 if (arg_debug) 474 if (arg_debug)
638 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir); 475 printf("Mount-bind %s on top of %s\n", RUN_HOME_DIR, homedir);
@@ -640,7 +477,7 @@ void fs_private_home_list(void) {
640 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0) 477 if (mount(RUN_HOME_DIR, homedir, NULL, MS_BIND|MS_REC, NULL) < 0)
641 errExit("mount bind"); 478 errExit("mount bind");
642 479
643 if (u != 0) { 480 if (uid != 0) {
644 // mask /root 481 // mask /root
645 if (arg_debug) 482 if (arg_debug)
646 printf("Mounting a new /root directory\n"); 483 printf("Mounting a new /root directory\n");
@@ -655,7 +492,7 @@ void fs_private_home_list(void) {
655 errExit("mounting home directory"); 492 errExit("mounting home directory");
656 } 493 }
657 494
658 skel(homedir, u, g); 495 skel(homedir, uid, gid);
659 if (xflag) 496 if (xflag)
660 copy_xauthority(); 497 copy_xauthority();
661 if (aflag) 498 if (aflag)