diff options
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | RELNOTES | 1 | ||||
-rw-r--r-- | src/firejail/firejail.h | 2 | ||||
-rw-r--r-- | src/firejail/main.c | 44 | ||||
-rw-r--r-- | src/firejail/preproc.c | 80 | ||||
-rw-r--r-- | src/firejail/profile.c | 23 | ||||
-rw-r--r-- | src/firejail/usage.c | 1 | ||||
-rw-r--r-- | src/man/firejail.txt | 13 | ||||
-rwxr-xr-x | test/profiles/test-profile.exp | 1 |
9 files changed, 168 insertions, 6 deletions
@@ -174,6 +174,15 @@ Check the status of the latest build here: https://travis-ci.org/netblue30/firej | |||
174 | amd64, i386 and x32 system calls are blocked as well as chang‐ | 174 | amd64, i386 and x32 system calls are blocked as well as chang‐ |
175 | ing the execution domain with personality(2) system call. | 175 | ing the execution domain with personality(2) system call. |
176 | 176 | ||
177 | --profile.print=name|pid | ||
178 | Print the name of the profile file for the sandbox identified | ||
179 | by name or or PID. | ||
180 | |||
181 | Example: | ||
182 | $ firejail --profile.print=browser | ||
183 | /etc/firejail/firefox.profile | ||
184 | |||
185 | |||
177 | ````` | 186 | ````` |
178 | 187 | ||
179 | ## /etc/firejail/firejail.config | 188 | ## /etc/firejail/firejail.config |
@@ -6,6 +6,7 @@ firejail (0.9.50~rc1) baseline; urgency=low | |||
6 | * feature: private /lib directory (--private-lib) | 6 | * feature: private /lib directory (--private-lib) |
7 | * feature: disable CDROM/DVD drive (--nodvd) | 7 | * feature: disable CDROM/DVD drive (--nodvd) |
8 | * feature: disable DVB devices (--notv) | 8 | * feature: disable DVB devices (--notv) |
9 | * feature: --profile.print | ||
9 | * enhancement: print all seccomp filters under --debug | 10 | * enhancement: print all seccomp filters under --debug |
10 | * enhancement: /proc/sys mounting | 11 | * enhancement: /proc/sys mounting |
11 | * enhancement: rework IP address assingment for --net options | 12 | * enhancement: rework IP address assingment for --net options |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 60a43a600..75450fe0f 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -34,6 +34,7 @@ | |||
34 | #define RUN_FIREJAIL_X11_DIR "/run/firejail/x11" | 34 | #define RUN_FIREJAIL_X11_DIR "/run/firejail/x11" |
35 | #define RUN_FIREJAIL_NETWORK_DIR "/run/firejail/network" | 35 | #define RUN_FIREJAIL_NETWORK_DIR "/run/firejail/network" |
36 | #define RUN_FIREJAIL_BANDWIDTH_DIR "/run/firejail/bandwidth" | 36 | #define RUN_FIREJAIL_BANDWIDTH_DIR "/run/firejail/bandwidth" |
37 | #define RUN_FIREJAIL_PROFILE_DIR "/run/firejail/profile" | ||
37 | #define RUN_NETWORK_LOCK_FILE "/run/firejail/firejail.lock" | 38 | #define RUN_NETWORK_LOCK_FILE "/run/firejail/firejail.lock" |
38 | #define RUN_RO_DIR "/run/firejail/firejail.ro.dir" | 39 | #define RUN_RO_DIR "/run/firejail/firejail.ro.dir" |
39 | #define RUN_RO_FILE "/run/firejail/firejail.ro.file" | 40 | #define RUN_RO_FILE "/run/firejail/firejail.ro.file" |
@@ -410,6 +411,7 @@ void net_config_interface(const char *dev, uint32_t ip, uint32_t mask, int mtu); | |||
410 | // preproc.c | 411 | // preproc.c |
411 | void preproc_build_firejail_dir(void); | 412 | void preproc_build_firejail_dir(void); |
412 | void preproc_mount_mnt_dir(void); | 413 | void preproc_mount_mnt_dir(void); |
414 | void preproc_clean_run(void); | ||
413 | 415 | ||
414 | // fs.c | 416 | // fs.c |
415 | // blacklist files or directoies by mounting empty files on top of them | 417 | // blacklist files or directoies by mounting empty files on top of them |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 3f805a7e0..c317aa477 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -130,15 +130,22 @@ unsigned long long start_timestamp; | |||
130 | 130 | ||
131 | static void set_name_file(pid_t pid); | 131 | static void set_name_file(pid_t pid); |
132 | static void delete_name_file(pid_t pid); | 132 | static void delete_name_file(pid_t pid); |
133 | static void delete_profile_file(pid_t pid); | ||
133 | static void delete_x11_file(pid_t pid); | 134 | static void delete_x11_file(pid_t pid); |
134 | 135 | ||
135 | void clear_run_files(pid_t pid) { | 136 | void clear_run_files(pid_t pid) { |
136 | bandwidth_del_run_file(pid); // bandwidth file | 137 | bandwidth_del_run_file(pid); // bandwidth file |
137 | network_del_run_file(pid); // network map file | 138 | network_del_run_file(pid); // network map file |
138 | delete_name_file(pid); | 139 | delete_name_file(pid); |
140 | delete_profile_file(pid); | ||
139 | delete_x11_file(pid); | 141 | delete_x11_file(pid); |
140 | } | 142 | } |
141 | 143 | ||
144 | static void clear_atexit(void) { | ||
145 | EUID_ROOT(); | ||
146 | clear_run_files(getpid()); | ||
147 | } | ||
148 | |||
142 | static void myexit(int rv) { | 149 | static void myexit(int rv) { |
143 | logmsg("exiting..."); | 150 | logmsg("exiting..."); |
144 | if (!arg_command && !arg_quiet) | 151 | if (!arg_command && !arg_quiet) |
@@ -465,6 +472,26 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
465 | exit(0); | 472 | exit(0); |
466 | } | 473 | } |
467 | #endif | 474 | #endif |
475 | else if (strncmp(argv[i], "--profile.print=", 16) == 0) { | ||
476 | pid_t pid = read_pid(argv[i] + 16); | ||
477 | |||
478 | // print /run/firejail/profile/<PID> file | ||
479 | char *fname; | ||
480 | if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1) | ||
481 | errExit("asprintf"); | ||
482 | FILE *fp = fopen(fname, "r"); | ||
483 | if (!fp) { | ||
484 | fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16); | ||
485 | exit(1); | ||
486 | } | ||
487 | #define MAXBUF 4096 | ||
488 | char buf[MAXBUF]; | ||
489 | if (fgets(buf, MAXBUF, fp)) | ||
490 | printf("%s", buf); | ||
491 | fclose(fp); | ||
492 | exit(0); | ||
493 | |||
494 | } | ||
468 | else if (strncmp(argv[i], "--cpu.print=", 12) == 0) { | 495 | else if (strncmp(argv[i], "--cpu.print=", 12) == 0) { |
469 | // join sandbox by pid or by name | 496 | // join sandbox by pid or by name |
470 | pid_t pid = read_pid(argv[i] + 12); | 497 | pid_t pid = read_pid(argv[i] + 12); |
@@ -738,6 +765,15 @@ static void delete_name_file(pid_t pid) { | |||
738 | free(fname); | 765 | free(fname); |
739 | } | 766 | } |
740 | 767 | ||
768 | static void delete_profile_file(pid_t pid) { | ||
769 | char *fname; | ||
770 | if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_PROFILE_DIR, pid) == -1) | ||
771 | errExit("asprintf"); | ||
772 | int rv = unlink(fname); | ||
773 | (void) rv; | ||
774 | free(fname); | ||
775 | } | ||
776 | |||
741 | void set_x11_file(pid_t pid, int display) { | 777 | void set_x11_file(pid_t pid, int display) { |
742 | char *fname; | 778 | char *fname; |
743 | if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1) | 779 | if (asprintf(&fname, "%s/%d", RUN_FIREJAIL_X11_DIR, pid) == -1) |
@@ -825,12 +861,14 @@ int main(int argc, char **argv) { | |||
825 | char *custom_profile_dir = NULL; // custom profile directory | 861 | char *custom_profile_dir = NULL; // custom profile directory |
826 | 862 | ||
827 | 863 | ||
864 | atexit(clear_atexit); | ||
865 | |||
828 | // get starting timestamp | 866 | // get starting timestamp |
829 | start_timestamp = getticks(); | 867 | start_timestamp = getticks(); |
830 | 868 | ||
831 | |||
832 | // build /run/firejail directory structure | 869 | // build /run/firejail directory structure |
833 | preproc_build_firejail_dir(); | 870 | preproc_build_firejail_dir(); |
871 | preproc_clean_run(); | ||
834 | 872 | ||
835 | if (check_arg(argc, argv, "--quiet")) | 873 | if (check_arg(argc, argv, "--quiet")) |
836 | arg_quiet = 1; | 874 | arg_quiet = 1; |
@@ -2554,14 +2592,10 @@ int main(int argc, char **argv) { | |||
2554 | close(lockfd); | 2592 | close(lockfd); |
2555 | } | 2593 | } |
2556 | 2594 | ||
2557 | // create name file under /run/firejail | ||
2558 | |||
2559 | |||
2560 | // handle CTRL-C in parent | 2595 | // handle CTRL-C in parent |
2561 | signal (SIGINT, my_handler); | 2596 | signal (SIGINT, my_handler); |
2562 | signal (SIGTERM, my_handler); | 2597 | signal (SIGTERM, my_handler); |
2563 | 2598 | ||
2564 | |||
2565 | // wait for the child to finish | 2599 | // wait for the child to finish |
2566 | EUID_USER(); | 2600 | EUID_USER(); |
2567 | int status = 0; | 2601 | int status = 0; |
diff --git a/src/firejail/preproc.c b/src/firejail/preproc.c index 0b447e03b..42502008e 100644 --- a/src/firejail/preproc.c +++ b/src/firejail/preproc.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include "firejail.h" | 20 | #include "firejail.h" |
21 | #include <sys/mount.h> | 21 | #include <sys/mount.h> |
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <sys/types.h> | ||
24 | #include <dirent.h> | ||
23 | 25 | ||
24 | static int tmpfs_mounted = 0; | 26 | static int tmpfs_mounted = 0; |
25 | 27 | ||
@@ -48,6 +50,10 @@ void preproc_build_firejail_dir(void) { | |||
48 | create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755); | 50 | create_empty_dir_as_root(RUN_FIREJAIL_NAME_DIR, 0755); |
49 | } | 51 | } |
50 | 52 | ||
53 | if (stat(RUN_FIREJAIL_PROFILE_DIR, &s)) { | ||
54 | create_empty_dir_as_root(RUN_FIREJAIL_PROFILE_DIR, 0755); | ||
55 | } | ||
56 | |||
51 | if (stat(RUN_FIREJAIL_X11_DIR, &s)) { | 57 | if (stat(RUN_FIREJAIL_X11_DIR, &s)) { |
52 | create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755); | 58 | create_empty_dir_as_root(RUN_FIREJAIL_X11_DIR, 0755); |
53 | } | 59 | } |
@@ -98,3 +104,77 @@ void preproc_mount_mnt_dir(void) { | |||
98 | errExit("set_perms"); | 104 | errExit("set_perms"); |
99 | } | 105 | } |
100 | } | 106 | } |
107 | |||
108 | // clean run directory | ||
109 | void preproc_clean_run(void) { | ||
110 | int max_pids=32769; | ||
111 | int start_pid = 100; | ||
112 | // extract real max_pids | ||
113 | FILE *fp = fopen("/proc/sys/kernel/pid_max", "r"); | ||
114 | if (fp) { | ||
115 | int val; | ||
116 | if (fscanf(fp, "%d", &val) == 1) { | ||
117 | if (val >= max_pids) | ||
118 | max_pids = val + 1; | ||
119 | } | ||
120 | fclose(fp); | ||
121 | } | ||
122 | int *pidarr = malloc(max_pids * sizeof(int)); | ||
123 | if (!pidarr) | ||
124 | errExit("malloc"); | ||
125 | |||
126 | memset(pidarr, 0, max_pids * sizeof(int)); | ||
127 | |||
128 | // open /proc directory | ||
129 | DIR *dir; | ||
130 | if (!(dir = opendir("/proc"))) { | ||
131 | // sleep 2 seconds and try again | ||
132 | sleep(2); | ||
133 | if (!(dir = opendir("/proc"))) { | ||
134 | fprintf(stderr, "Error: cannot open /proc directory\n"); | ||
135 | exit(1); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | // read /proc and populate pidarr with all active processes | ||
140 | struct dirent *entry; | ||
141 | char *end; | ||
142 | while ((entry = readdir(dir)) != NULL) { | ||
143 | pid_t pid = strtol(entry->d_name, &end, 10); | ||
144 | pid %= max_pids; | ||
145 | if (end == entry->d_name || *end) | ||
146 | continue; | ||
147 | |||
148 | if (pid < start_pid) | ||
149 | continue; | ||
150 | pidarr[pid] = 1; | ||
151 | } | ||
152 | closedir(dir); | ||
153 | |||
154 | // open /run/firejail/profile directory | ||
155 | if (!(dir = opendir(RUN_FIREJAIL_PROFILE_DIR))) { | ||
156 | // sleep 2 seconds and try again | ||
157 | sleep(2); | ||
158 | if (!(dir = opendir(RUN_FIREJAIL_PROFILE_DIR))) { | ||
159 | fprintf(stderr, "Error: cannot open %s directory\n", RUN_FIREJAIL_PROFILE_DIR); | ||
160 | exit(1); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // read /run/firejail/profile directory and clean leftover files | ||
165 | while ((entry = readdir(dir)) != NULL) { | ||
166 | pid_t pid = strtol(entry->d_name, &end, 10); | ||
167 | pid %= max_pids; | ||
168 | if (end == entry->d_name || *end) | ||
169 | continue; | ||
170 | |||
171 | if (pid < start_pid) | ||
172 | continue; | ||
173 | if (pidarr[pid] == 0) | ||
174 | clear_run_files(pid); | ||
175 | } | ||
176 | closedir(dir); | ||
177 | |||
178 | free(pidarr); | ||
179 | } | ||
180 | |||
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index fc390c83a..e61f59f46 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1193,6 +1193,29 @@ void profile_read(const char *fname) { | |||
1193 | exit(1); | 1193 | exit(1); |
1194 | } | 1194 | } |
1195 | 1195 | ||
1196 | // save the name of the file for --profile.print option | ||
1197 | if (include_level == 0) { | ||
1198 | char *runfile; | ||
1199 | if (asprintf(&runfile, "%s/%d", RUN_FIREJAIL_PROFILE_DIR, getpid()) == -1) | ||
1200 | errExit("asprintf"); | ||
1201 | |||
1202 | EUID_ROOT(); | ||
1203 | // the file is deleted first | ||
1204 | FILE *fp = fopen(runfile, "w"); | ||
1205 | if (!fp) { | ||
1206 | fprintf(stderr, "Error: cannot create %s\n", runfile); | ||
1207 | exit(1); | ||
1208 | } | ||
1209 | fprintf(fp, "%s\n", fname); | ||
1210 | |||
1211 | // mode and ownership | ||
1212 | SET_PERMS_STREAM(fp, 0, 0, 0644); | ||
1213 | fclose(fp); | ||
1214 | EUID_USER(); | ||
1215 | free(runfile); | ||
1216 | } | ||
1217 | |||
1218 | |||
1196 | int msg_printed = 0; | 1219 | int msg_printed = 0; |
1197 | 1220 | ||
1198 | // read the file line by line | 1221 | // read the file line by line |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 10e6ab687..fc7dbd69c 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -159,6 +159,7 @@ void usage(void) { | |||
159 | printf(" --private-tmp - mount a tmpfs on top of /tmp directory.\n"); | 159 | printf(" --private-tmp - mount a tmpfs on top of /tmp directory.\n"); |
160 | printf(" --private-opt=file,directory - build a new /opt in a temporary filesystem.\n"); | 160 | printf(" --private-opt=file,directory - build a new /opt in a temporary filesystem.\n"); |
161 | printf(" --profile=filename - use a custom profile.\n"); | 161 | printf(" --profile=filename - use a custom profile.\n"); |
162 | printf(" --profile.print=name|pid - print the name of profile file.\n"); | ||
162 | printf(" --profile-path=directory - use this directory to look for profile files.\n"); | 163 | printf(" --profile-path=directory - use this directory to look for profile files.\n"); |
163 | printf(" --protocol=protocol,protocol,protocol - enable protocol filter.\n"); | 164 | printf(" --protocol=protocol,protocol,protocol - enable protocol filter.\n"); |
164 | printf(" --protocol.print=name|pid - print the protocol filter.\n"); | 165 | printf(" --protocol.print=name|pid - print the protocol filter.\n"); |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 9ae5d6782..a70f662fd 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1424,6 +1424,19 @@ Example: | |||
1424 | $ firejail \-\-profile=myprofile | 1424 | $ firejail \-\-profile=myprofile |
1425 | 1425 | ||
1426 | .TP | 1426 | .TP |
1427 | \fB\-\-profile.print=name|pid | ||
1428 | Print the name of the profile file for the sandbox identified by name or or PID. | ||
1429 | .br | ||
1430 | |||
1431 | .br | ||
1432 | Example: | ||
1433 | .br | ||
1434 | $ firejail \-\-profile.print=browser | ||
1435 | .br | ||
1436 | /etc/firejail/firefox.profile | ||
1437 | .br | ||
1438 | |||
1439 | .TP | ||
1427 | \fB\-\-profile-path=directory | 1440 | \fB\-\-profile-path=directory |
1428 | Use this directory to look for profile files. Use an absolute path or a path in the home directory starting with ~/. | 1441 | Use this directory to look for profile files. Use an absolute path or a path in the home directory starting with ~/. |
1429 | For more information, see \fBSECURITY PROFILES\fR section below and \fBRELOCATING PROFILE FILES\fR in | 1442 | For more information, see \fBSECURITY PROFILES\fR section below and \fBRELOCATING PROFILE FILES\fR in |
diff --git a/test/profiles/test-profile.exp b/test/profiles/test-profile.exp index 6bc47f33f..63fb3a150 100755 --- a/test/profiles/test-profile.exp +++ b/test/profiles/test-profile.exp | |||
@@ -18,6 +18,5 @@ expect { | |||
18 | timeout {puts "TESTING ERROR 0\n";exit} | 18 | timeout {puts "TESTING ERROR 0\n";exit} |
19 | "done" | 19 | "done" |
20 | } | 20 | } |
21 | send -- "exit\r" | ||
22 | after 100 | 21 | after 100 |
23 | puts "\n" | 22 | puts "\n" |