aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firecfg/firecfg.config8
-rw-r--r--src/firejail/firejail.h4
-rw-r--r--src/firejail/fs.c204
-rw-r--r--src/firejail/profile.c5
-rw-r--r--src/man/firejail-profile.txt2
-rw-r--r--src/profstats/Makefile.in14
-rw-r--r--src/profstats/main.c240
7 files changed, 396 insertions, 81 deletions
diff --git a/src/firecfg/firecfg.config b/src/firecfg/firecfg.config
index 4cd4fad6c..2798605d5 100644
--- a/src/firecfg/firecfg.config
+++ b/src/firecfg/firecfg.config
@@ -23,6 +23,7 @@ Natron
23PPSSPPQt 23PPSSPPQt
24QMediathekView 24QMediathekView
25QOwnNotes 25QOwnNotes
26Screenshot
26Telegram 27Telegram
27Viber 28Viber
28VirtualBox 29VirtualBox
@@ -148,6 +149,7 @@ desktopeditors
148devhelp 149devhelp
149dex2jar 150dex2jar
150dia 151dia
152dig
151digikam 153digikam
152dillo 154dillo
153dino 155dino
@@ -275,6 +277,7 @@ gnome-passwordsafe
275gnome-photos 277gnome-photos
276gnome-recipes 278gnome-recipes
277gnome-schedule 279gnome-schedule
280gnome-screenshot
278gnome-system-log 281gnome-system-log
279gnome-twitch 282gnome-twitch
280gnome-weather 283gnome-weather
@@ -303,6 +306,7 @@ hashcat
303hedgewars 306hedgewars
304hexchat 307hexchat
305highlight 308highlight
309host
306hugin 310hugin
307icecat 311icecat
308icedove 312icedove
@@ -466,6 +470,7 @@ nitroshare-nmh
466nitroshare-send 470nitroshare-send
467nitroshare-ui 471nitroshare-ui
468nomacs 472nomacs
473nslookup
469nylas 474nylas
470nyx 475nyx
471obs 476obs
@@ -479,6 +484,7 @@ ooviewdoc
479open-invaders 484open-invaders
480openarena 485openarena
481opencity 486opencity
487openclonk
482openoffice.org 488openoffice.org
483openshot 489openshot
484openshot-qt 490openshot-qt
@@ -546,6 +552,7 @@ rhythmbox-client
546ricochet 552ricochet
547riot-desktop 553riot-desktop
548riot-web 554riot-web
555ripperx
549ristretto 556ristretto
550rocketchat 557rocketchat
551rtorrent 558rtorrent
@@ -578,6 +585,7 @@ smtube
578snox 585snox
579soffice 586soffice
580sol 587sol
588sound-juicer
581soundconverter 589soundconverter
582spotify 590spotify
583sqlitebrowser 591sqlitebrowser
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 0e4fcea6a..7391a8994 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -395,6 +395,7 @@ typedef enum {
395 MOUNT_TMPFS, 395 MOUNT_TMPFS,
396 MOUNT_NOEXEC, 396 MOUNT_NOEXEC,
397 MOUNT_RDWR, 397 MOUNT_RDWR,
398 MOUNT_RDWR_NOCHECK, // no check of ownership
398 OPERATION_MAX 399 OPERATION_MAX
399} OPERATION; 400} OPERATION;
400 401
@@ -403,8 +404,7 @@ void fs_blacklist(void);
403// mount a writable tmpfs 404// mount a writable tmpfs
404void fs_tmpfs(const char *dir, unsigned check_owner); 405void fs_tmpfs(const char *dir, unsigned check_owner);
405// remount noexec/nodev/nosuid or read-only or read-write 406// remount noexec/nodev/nosuid or read-only or read-write
406void fs_remount(const char *dir, OPERATION op, unsigned check_mnt); 407void fs_remount(const char *dir, OPERATION op, int rec);
407void fs_remount_rec(const char *dir, OPERATION op, unsigned check_mnt);
408// mount /proc and /sys directories 408// mount /proc and /sys directories
409void fs_proc_sys_dev_boot(void); 409void fs_proc_sys_dev_boot(void);
410// blacklist firejail configuration and runtime directories 410// blacklist firejail configuration and runtime directories
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index c7dd91b06..b642329bf 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -28,10 +28,9 @@
28#include <dirent.h> 28#include <dirent.h>
29#include <errno.h> 29#include <errno.h>
30 30
31
32#include <fcntl.h> 31#include <fcntl.h>
33#ifndef O_PATH 32#ifndef O_PATH
34# define O_PATH 010000000 33#define O_PATH 010000000
35#endif 34#endif
36 35
37#define MAX_BUF 4096 36#define MAX_BUF 4096
@@ -43,6 +42,8 @@
43//*********************************************** 42//***********************************************
44// process profile file 43// process profile file
45//*********************************************** 44//***********************************************
45static void fs_remount_rec(const char *dir, OPERATION op);
46
46static char *opstr[] = { 47static char *opstr[] = {
47 [BLACKLIST_FILE] = "blacklist", 48 [BLACKLIST_FILE] = "blacklist",
48 [BLACKLIST_NOLOG] = "blacklist-nolog", 49 [BLACKLIST_NOLOG] = "blacklist-nolog",
@@ -50,6 +51,7 @@ static char *opstr[] = {
50 [MOUNT_TMPFS] = "tmpfs", 51 [MOUNT_TMPFS] = "tmpfs",
51 [MOUNT_NOEXEC] = "noexec", 52 [MOUNT_NOEXEC] = "noexec",
52 [MOUNT_RDWR] = "read-write", 53 [MOUNT_RDWR] = "read-write",
54 [MOUNT_RDWR_NOCHECK] = "read-write",
53}; 55};
54 56
55typedef enum { 57typedef enum {
@@ -148,7 +150,7 @@ static void disable_file(OPERATION op, const char *filename) {
148 } 150 }
149 } 151 }
150 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) { 152 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) {
151 fs_remount_rec(fname, op, 1); 153 fs_remount_rec(fname, op);
152 // todo: last_disable = SUCCESSFUL; 154 // todo: last_disable = SUCCESSFUL;
153 } 155 }
154 else if (op == MOUNT_TMPFS) { 156 else if (op == MOUNT_TMPFS) {
@@ -425,21 +427,11 @@ void fs_blacklist(void) {
425 free(noblacklist); 427 free(noblacklist);
426} 428}
427 429
428static int get_mount_flags(const char *path, unsigned long *flags) {
429 struct statvfs buf;
430
431 if (statvfs(path, &buf) < 0)
432 return -errno;
433 *flags = buf.f_flag;
434 return 0;
435}
436
437//*********************************************** 430//***********************************************
438// mount namespace 431// mount namespace
439// - functions need fully resolved paths
440//*********************************************** 432//***********************************************
441 433
442// mount a writable tmpfs on directory 434// mount a writable tmpfs on directory; requires a resolved path
443void fs_tmpfs(const char *dir, unsigned check_owner) { 435void fs_tmpfs(const char *dir, unsigned check_owner) {
444 assert(dir); 436 assert(dir);
445 if (arg_debug) 437 if (arg_debug)
@@ -480,71 +472,114 @@ void fs_tmpfs(const char *dir, unsigned check_owner) {
480 close(fd); 472 close(fd);
481} 473}
482 474
483void fs_remount(const char *dir, OPERATION op, unsigned check_mnt) { 475// remount path, but preserve existing mount flags; requires a resolved path
484 assert(dir); 476static void fs_remount_simple(const char *path, OPERATION op) {
485 // check directory exists 477 assert(path);
478
479 // open path without following symbolic links
480 int fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
481 if (fd == -1)
482 goto out;
483 // identify file owner
486 struct stat s; 484 struct stat s;
487 int rv = stat(dir, &s); 485 if (fstat(fd, &s) == -1) {
488 if (rv == 0) { 486 // fstat can fail with EACCES if path is a FUSE mount,
489 unsigned long flags = 0; 487 // mounted without 'allow_root' or 'allow_other'
490 if (get_mount_flags(dir, &flags) != 0) { 488 if (errno != EACCES)
491 fwarning("cannot remount %s\n", dir); 489 errExit("fstat");
490 close(fd);
491 goto out;
492 }
493 // get mount flags
494 struct statvfs buf;
495 if (fstatvfs(fd, &buf) == -1)
496 errExit("fstatvfs");
497 unsigned long flags = buf.f_flag;
498
499 // read-write option
500 if (op == MOUNT_RDWR || op == MOUNT_RDWR_NOCHECK) {
501 // nothing to do if there is no read-only flag
502 if ((flags & MS_RDONLY) == 0) {
503 close(fd);
492 return; 504 return;
493 } 505 }
494 if (op == MOUNT_RDWR) { 506 // allow only user owned directories, except the user is root
495 // allow only user owned directories, except the user is root 507 if (op == MOUNT_RDWR && getuid() != 0 && s.st_uid != getuid()) {
496 if (getuid() != 0 && s.st_uid != getuid()) { 508 fwarning("you are not allowed to change %s to read-write\n", path);
497 fwarning("you are not allowed to change %s to read-write\n", dir); 509 close(fd);
498 return; 510 return;
499 }
500 if ((flags & MS_RDONLY) == 0)
501 return;
502 flags &= ~MS_RDONLY;
503 }
504 else if (op == MOUNT_NOEXEC) {
505 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID))
506 return;
507 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
508 } 511 }
509 else if (op == MOUNT_READONLY) { 512 flags &= ~MS_RDONLY;
510 if ((flags & MS_RDONLY) == MS_RDONLY) 513 }
511 return; 514 // noexec option
512 flags |= MS_RDONLY; 515 else if (op == MOUNT_NOEXEC) {
516 // nothing to do if path is mounted noexec already
517 if ((flags & (MS_NOEXEC|MS_NODEV|MS_NOSUID)) == (MS_NOEXEC|MS_NODEV|MS_NOSUID)) {
518 close(fd);
519 return;
513 } 520 }
514 else 521 flags |= MS_NOEXEC|MS_NODEV|MS_NOSUID;
515 assert(0); 522 }
516 523 // read-only option
517 if (arg_debug) 524 else if (op == MOUNT_READONLY) {
518 printf("Mounting %s %s\n", opstr[op], dir); 525 // nothing to do if path is mounted read-only already
519 // mount --bind /bin /bin 526 if ((flags & MS_RDONLY) == MS_RDONLY) {
520 // mount --bind -o remount,rw /bin 527 close(fd);
521 if (mount(dir, dir, NULL, MS_BIND|MS_REC, NULL) < 0 || 528 return;
522 mount(NULL, dir, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
523 errExit("remounting");
524 // run a sanity check on /proc/self/mountinfo
525 if (check_mnt) {
526 // confirm target of the last mount operation was dir; if there are other
527 // mount points contained inside dir, one of those will show up as target
528 // of the last mount operation instead
529 MountData *mptr = get_last_mount();
530 size_t len = strlen(dir);
531 if ((strncmp(mptr->dir, dir, len) != 0 ||
532 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
533 && strcmp(dir, "/") != 0) // support read-only=/
534 errLogExit("invalid %s mount", opstr[op]);
535 } 529 }
536 fs_logger2(opstr[op], dir); 530 flags |= MS_RDONLY;
537 } 531 }
532 else
533 assert(0);
534
535 if (arg_debug)
536 printf("Mounting %s %s\n", opstr[op], path);
537 // mount --bind /bin /bin
538 char *proc;
539 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
540 errExit("asprintf");
541 if (mount(proc, proc, NULL, MS_BIND|MS_REC, NULL) < 0)
542 errExit("mount");
543 free(proc);
544 close(fd);
545
546 // mount --bind -o remount,ro /bin
547 // we need to open path again
548 fd = safe_fd(path, O_PATH|O_NOFOLLOW|O_CLOEXEC);
549 if (fd == -1)
550 errExit("open");
551 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1)
552 errExit("asprintf");
553 if (mount(NULL, proc, NULL, flags|MS_BIND|MS_REMOUNT, NULL) < 0)
554 errExit("mount");
555
556 // run a sanity check on /proc/self/mountinfo and confirm that target of the last
557 // mount operation was path; if there are other mount points contained inside path,
558 // one of those will show up as target of the last mount operation instead
559 MountData *mptr = get_last_mount();
560 size_t len = strlen(path);
561 if ((strncmp(mptr->dir, path, len) != 0 ||
562 (*(mptr->dir + len) != '\0' && *(mptr->dir + len) != '/'))
563 && strcmp(path, "/") != 0) // support read-only=/
564 errLogExit("invalid %s mount", opstr[op]);
565 fs_logger2(opstr[op], path);
566 free(proc);
567 close(fd);
568 return;
569
570out:
571 fwarning("not remounting %s\n", path);
538} 572}
539 573
540void fs_remount_rec(const char *dir, OPERATION op, unsigned check_mnt) { 574// remount recursively; requires a resolved path
575static void fs_remount_rec(const char *dir, OPERATION op) {
541 assert(dir); 576 assert(dir);
542 struct stat s; 577 struct stat s;
543 if (stat(dir, &s) != 0) 578 if (stat(dir, &s) != 0)
544 return; 579 return;
545 if (!S_ISDIR(s.st_mode)) { 580 if (!S_ISDIR(s.st_mode)) {
546 // no need to search in /proc/self/mountinfo for submounts if not a directory 581 // no need to search in /proc/self/mountinfo for submounts if not a directory
547 fs_remount(dir, op, check_mnt); 582 fs_remount_simple(dir, op);
548 return; 583 return;
549 } 584 }
550 // get mount point of the directory 585 // get mount point of the directory
@@ -558,7 +593,7 @@ void fs_remount_rec(const char *dir, OPERATION op, unsigned check_mnt) {
558 fwarning("read-only, read-write and noexec options are not applied recursively\n"); 593 fwarning("read-only, read-write and noexec options are not applied recursively\n");
559 mount_warning = 1; 594 mount_warning = 1;
560 } 595 }
561 fs_remount(dir, op, check_mnt); 596 fs_remount_simple(dir, op);
562 return; 597 return;
563 } 598 }
564 // build array with all mount points that need to get remounted 599 // build array with all mount points that need to get remounted
@@ -567,12 +602,25 @@ void fs_remount_rec(const char *dir, OPERATION op, unsigned check_mnt) {
567 // remount 602 // remount
568 char **tmp = arr; 603 char **tmp = arr;
569 while (*tmp) { 604 while (*tmp) {
570 fs_remount(*tmp, op, check_mnt); 605 fs_remount_simple(*tmp, op);
571 free(*tmp++); 606 free(*tmp++);
572 } 607 }
573 free(arr); 608 free(arr);
574} 609}
575 610
611// resolve a path and remount it
612void fs_remount(const char *path, OPERATION op, int rec) {
613 assert(path);
614 char *rpath = realpath(path, NULL);
615 if (rpath) {
616 if (rec)
617 fs_remount_rec(rpath, op);
618 else
619 fs_remount_simple(rpath, op);
620 free(rpath);
621 }
622}
623
576// Disable /mnt, /media, /run/mount and /run/media access 624// Disable /mnt, /media, /run/mount and /run/media access
577void fs_mnt(const int enforce) { 625void fs_mnt(const int enforce) {
578 if (enforce) { 626 if (enforce) {
@@ -749,22 +797,22 @@ void fs_basic_fs(void) {
749 if (arg_debug) 797 if (arg_debug)
750 printf("Basic read-only filesystem:\n"); 798 printf("Basic read-only filesystem:\n");
751 if (!arg_writable_etc) { 799 if (!arg_writable_etc) {
752 fs_remount("/etc", MOUNT_READONLY, 0); 800 fs_remount("/etc", MOUNT_READONLY, 1);
753 if (uid) 801 if (uid)
754 fs_remount("/etc", MOUNT_NOEXEC, 0); 802 fs_remount("/etc", MOUNT_NOEXEC, 1);
755 } 803 }
756 if (!arg_writable_var) { 804 if (!arg_writable_var) {
757 fs_remount("/var", MOUNT_READONLY, 0); 805 fs_remount("/var", MOUNT_READONLY, 1);
758 if (uid) 806 if (uid)
759 fs_remount("/var", MOUNT_NOEXEC, 0); 807 fs_remount("/var", MOUNT_NOEXEC, 1);
760 } 808 }
761 fs_remount("/bin", MOUNT_READONLY, 0); 809 fs_remount("/usr", MOUNT_READONLY, 1);
762 fs_remount("/sbin", MOUNT_READONLY, 0); 810 fs_remount("/bin", MOUNT_READONLY, 1);
763 fs_remount("/lib", MOUNT_READONLY, 0); 811 fs_remount("/sbin", MOUNT_READONLY, 1);
764 fs_remount("/lib64", MOUNT_READONLY, 0); 812 fs_remount("/lib", MOUNT_READONLY, 1);
765 fs_remount("/lib32", MOUNT_READONLY, 0); 813 fs_remount("/lib64", MOUNT_READONLY, 1);
766 fs_remount("/libx32", MOUNT_READONLY, 0); 814 fs_remount("/lib32", MOUNT_READONLY, 1);
767 fs_remount("/usr", MOUNT_READONLY, 0); 815 fs_remount("/libx32", MOUNT_READONLY, 1);
768 816
769 // update /var directory in order to support multiple sandboxes running on the same root directory 817 // update /var directory in order to support multiple sandboxes running on the same root directory
770 fs_var_lock(); 818 fs_var_lock();
@@ -773,7 +821,7 @@ void fs_basic_fs(void) {
773 if (!arg_writable_var_log) 821 if (!arg_writable_var_log)
774 fs_var_log(); 822 fs_var_log();
775 else 823 else
776 fs_remount("/var/log", MOUNT_RDWR, 0); 824 fs_remount("/var/log", MOUNT_RDWR_NOCHECK, 0);
777 825
778 fs_var_lib(); 826 fs_var_lib();
779 fs_var_cache(); 827 fs_var_cache();
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 969209869..c7269857d 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -151,6 +151,10 @@ static int check_nodbus(void) {
151 return arg_nodbus != 0; 151 return arg_nodbus != 0;
152} 152}
153 153
154static int check_nosound(void) {
155 return arg_nosound != 0;
156}
157
154static int check_x11(void) { 158static int check_x11(void) {
155 return (arg_x11_block || arg_x11_xorg || getenv("FIREJAIL_X11")); 159 return (arg_x11_block || arg_x11_xorg || getenv("FIREJAIL_X11"));
156} 160}
@@ -167,6 +171,7 @@ Cond conditionals[] = {
167 {"HAS_APPIMAGE", check_appimage}, 171 {"HAS_APPIMAGE", check_appimage},
168 {"HAS_NET", check_netoptions}, 172 {"HAS_NET", check_netoptions},
169 {"HAS_NODBUS", check_nodbus}, 173 {"HAS_NODBUS", check_nodbus},
174 {"HAS_NOSOUND", check_nosound},
170 {"HAS_X11", check_x11}, 175 {"HAS_X11", check_x11},
171 {"BROWSER_DISABLE_U2F", check_disable_u2f}, 176 {"BROWSER_DISABLE_U2F", check_disable_u2f},
172 {"BROWSER_ALLOW_DRM", check_allow_drm}, 177 {"BROWSER_ALLOW_DRM", check_allow_drm},
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 84aed41a4..9af25bf63 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -103,7 +103,7 @@ Example: "?HAS_APPIMAGE: whitelist ${HOME}/special/appimage/dir"
103 103
104This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line. 104This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line.
105 105
106Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS and HAS_X11. The conditionals BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM 106Currently the only conditionals supported this way are HAS_APPIMAGE, HAS_NET, HAS_NODBUS, HAS_NOSOUND and HAS_X11. The conditionals BROWSER_DISABLE_U2F and BROWSER_ALLOW_DRM
107can be enabled or disabled globally in Firejail's configuration file. 107can be enabled or disabled globally in Firejail's configuration file.
108 108
109The profile line may be any profile line that you would normally use in a profile \fBexcept\fR for "quiet" and "include" lines. 109The profile line may be any profile line that you would normally use in a profile \fBexcept\fR for "quiet" and "include" lines.
diff --git a/src/profstats/Makefile.in b/src/profstats/Makefile.in
new file mode 100644
index 000000000..4ada23c23
--- /dev/null
+++ b/src/profstats/Makefile.in
@@ -0,0 +1,14 @@
1all: ../../etc/profstats
2
3include ../common.mk
4
5%.o : %.c $(H_FILE_LIST)
6 $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(INCLUDE) -c $< -o $@
7
8../../etc/profstats: $(OBJS)
9 $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
10
11clean:; rm -fr *.o ../../etc/profstats *.gcov *.gcda *.gcno *.plist
12
13distclean: clean
14 rm -fr Makefile
diff --git a/src/profstats/main.c b/src/profstats/main.c
new file mode 100644
index 000000000..775142643
--- /dev/null
+++ b/src/profstats/main.c
@@ -0,0 +1,240 @@
1 /*
2 * Copyright (C) 2014-2020 Firejail Authors
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
23#include <assert.h>
24
25#define MAXBUF 2048
26// stats
27static int cnt_profiles = 0;
28static int cnt_apparmor = 0;
29static int cnt_seccomp = 0;
30static int cnt_caps = 0;
31static int cnt_dotlocal = 0;
32static int cnt_globalsdotlocal = 0;
33static int cnt_netnone = 0;
34static int cnt_noexec = 0; // include disable-exec.inc
35static int cnt_privatedev = 0;
36static int cnt_privatetmp = 0;
37static int cnt_whitelistvar = 0; // include whitelist-var-common.inc
38static int cnt_ssh = 0;
39
40static int level = 0;
41static int arg_debug = 0;
42static int arg_apparmor = 0;
43static int arg_caps = 0;
44static int arg_seccomp = 0;
45static int arg_noexec = 0;
46static int arg_privatedev = 0;
47static int arg_privatetmp = 0;
48static int arg_whitelistvar = 0;
49static int arg_ssh = 0;
50
51static void usage(void) {
52 printf("proftool - print profile statistics\n");
53 printf("Usage: proftool [options] file[s]\n");
54 printf("Options:\n");
55 printf(" --apparmor - print profiles without apparmor\n");
56 printf(" --caps - print profiles without caps\n");
57 printf(" --ssh - print profiles without \"include disable-common.inc\"\n");
58 printf(" --noexec - print profiles without \"include disable-exec.inc\"\n");
59 printf(" --private-dev - print profiles without private-dev\n");
60 printf(" --private-tmp - print profiles without private-tmp\n");
61 printf(" --seccomp - print profiles without seccomp\n");
62 printf(" --whitelist-var - print profiles without \"include whitelist-var-common.inc\"\n");
63 printf(" --debug\n");
64 printf("\n");
65}
66
67void process_file(const char *fname) {
68 assert(fname);
69
70 if (arg_debug)
71 printf("processing #%s#\n", fname);
72 level++;
73 assert(level < 32); // to do - check in firejail code
74
75 FILE *fp = fopen(fname, "r");
76 if (!fp) {
77 fprintf(stderr, "Error: cannot open %s\n", fname);
78 exit(1);
79 }
80
81 char buf[MAXBUF];
82 while (fgets(buf, MAXBUF, fp)) {
83 char *ptr = strchr(buf, '\n');
84 if (ptr)
85 *ptr = '\0';
86 ptr = buf;
87
88 while (*ptr == ' ' || *ptr == '\t')
89 ptr++;
90 if (*ptr == '\n' || *ptr == '#')
91 continue;
92
93 if (strncmp(ptr, "seccomp", 7) == 0)
94 cnt_seccomp++;
95 else if (strncmp(ptr, "caps", 4) == 0)
96 cnt_caps++;
97 else if (strncmp(ptr, "include disable-exec.inc", 24) == 0)
98 cnt_noexec++;
99 else if (strncmp(ptr, "include whitelist-var-common.inc", 32) == 0)
100 cnt_whitelistvar++;
101 else if (strncmp(ptr, "include disable-common.inc", 26) == 0)
102 cnt_ssh++;
103 else if (strncmp(ptr, "net none", 8) == 0)
104 cnt_netnone++;
105 else if (strncmp(ptr, "apparmor", 8) == 0)
106 cnt_apparmor++;
107 else if (strncmp(ptr, "private-dev", 11) == 0)
108 cnt_privatedev++;
109 else if (strncmp(ptr, "private-tmp", 11) == 0)
110 cnt_privatetmp++;
111 else if (strncmp(ptr, "include ", 8) == 0) {
112 // not processing .local files
113 if (strstr(ptr, ".local")) {
114//printf("dotlocal %d, level %d - #%s#, redirect #%s#\n", cnt_dotlocal, level, fname, buf + 8);
115 if (strstr(ptr, "globals.local"))
116 cnt_globalsdotlocal++;
117 else
118 cnt_dotlocal++;
119 continue;
120 }
121 process_file(buf + 8);
122 }
123 }
124
125 fclose(fp);
126 level--;
127}
128
129int main(int argc, char **argv) {
130 if (argc <= 1) {
131 usage();
132 return 1;
133 }
134
135 int start = 1;
136 int i;
137 for (i = 1; i < argc; i++) {
138 if (strcmp(argv[i], "--help") == 0) {
139 usage();
140 return 0;
141 }
142 else if (strcmp(argv[i], "--debug") == 0)
143 arg_debug = 1;
144 else if (strcmp(argv[i], "--apparmor") == 0)
145 arg_apparmor = 1;
146 else if (strcmp(argv[i], "--caps") == 0)
147 arg_caps = 1;
148 else if (strcmp(argv[i], "--seccomp") == 0)
149 arg_seccomp = 1;
150 else if (strcmp(argv[i], "--noexec") == 0)
151 arg_noexec = 1;
152 else if (strcmp(argv[i], "--private-dev") == 0)
153 arg_privatedev = 1;
154 else if (strcmp(argv[i], "--private-tmp") == 0)
155 arg_privatetmp = 1;
156 else if (strcmp(argv[i], "--whitelist-var") == 0)
157 arg_whitelistvar = 1;
158 else if (strcmp(argv[i], "--ssh") == 0)
159 arg_ssh = 1;
160 else if (*argv[i] == '-') {
161 fprintf(stderr, "Error: invalid option %s\n", argv[i]);
162 return 1;
163 }
164 else
165 break;
166 }
167
168 start = i;
169 if (i == argc) {
170 fprintf(stderr, "Error: no porfile file specified\n");
171 return 1;
172 }
173
174 for (i = start; i < argc; i++) {
175 cnt_profiles++;
176
177 // watch seccomp
178 int seccomp = cnt_seccomp;
179 int caps = cnt_caps;
180 int apparmor = cnt_apparmor;
181 int noexec = cnt_noexec;
182 int privatetmp = cnt_privatetmp;
183 int privatedev = cnt_privatedev;
184 int dotlocal = cnt_dotlocal;
185 int globalsdotlocal = cnt_globalsdotlocal;
186 int whitelistvar = cnt_whitelistvar;
187 int ssh = cnt_ssh;
188
189 // process file
190 process_file(argv[i]);
191
192 // warnings
193 if ((caps + 2) <= cnt_caps) {
194 printf("Warning: multiple caps in %s\n", argv[i]);
195 cnt_caps = caps + 1;
196 }
197
198 // fix redirections
199 if (cnt_dotlocal > (dotlocal + 1))
200 cnt_dotlocal = dotlocal + 1;
201 if (cnt_globalsdotlocal > (globalsdotlocal + 1))
202 cnt_globalsdotlocal = globalsdotlocal + 1;
203
204 if (arg_apparmor && apparmor == cnt_apparmor)
205 printf("No apparmor found in %s\n", argv[i]);
206 if (arg_caps && caps == cnt_caps)
207 printf("No caps found in %s\n", argv[i]);
208 if (arg_seccomp && seccomp == cnt_seccomp)
209 printf("No seccomp found in %s\n", argv[i]);
210 if (arg_noexec && noexec == cnt_noexec)
211 printf("No include disable-exec.inc found in %s\n", argv[i]);
212 if (arg_privatedev && privatedev == cnt_privatedev)
213 printf("No private-dev found in %s\n", argv[i]);
214 if (arg_privatetmp && privatetmp == cnt_privatetmp)
215 printf("No private-tmp found in %s\n", argv[i]);
216 if (arg_whitelistvar && whitelistvar == cnt_whitelistvar)
217 printf("No include whitelist-var-common.inc found in %s\n", argv[i]);
218 if (arg_ssh && ssh == cnt_ssh)
219 printf("No include disable-common.inc found in %s\n", argv[i]);
220
221 assert(level == 0);
222 }
223
224 printf("\n");
225 printf("Stats:\n");
226 printf(" profiles\t\t\t%d\n", cnt_profiles);
227 printf(" include local profile\t%d (include profile-name.local)\n", cnt_dotlocal);
228 printf(" include globals\t\t%d (include globals.local)\n", cnt_dotlocal);
229 printf(" blacklist ~/.ssh\t\t%d (include disable-common.inc)\n", cnt_ssh);
230 printf(" seccomp\t\t\t%d\n", cnt_seccomp);
231 printf(" capabilities\t\t%d\n", cnt_caps);
232 printf(" noexec\t\t\t%d (include disable-exec.inc)\n", cnt_noexec);
233 printf(" apparmor\t\t\t%d\n", cnt_apparmor);
234 printf(" private-dev\t\t\t%d\n", cnt_privatedev);
235 printf(" private-tmp\t\t\t%d\n", cnt_privatetmp);
236 printf(" whitelist var directory\t%d (include whitelist-var-common.inc)\n", cnt_whitelistvar);
237 printf(" net none\t\t\t%d\n", cnt_netnone);
238 printf("\n");
239 return 0;
240} \ No newline at end of file