diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/firejail.h | 6 | ||||
-rw-r--r-- | src/firejail/fs_whitelist.c | 119 |
2 files changed, 114 insertions, 11 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index d853daa44..008f4ad08 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -81,6 +81,8 @@ | |||
81 | #define RUN_WHITELIST_DEV_DIR "/run/firejail/mnt/orig-dev" | 81 | #define RUN_WHITELIST_DEV_DIR "/run/firejail/mnt/orig-dev" |
82 | #define RUN_WHITELIST_OPT_DIR "/run/firejail/mnt/orig-opt" | 82 | #define RUN_WHITELIST_OPT_DIR "/run/firejail/mnt/orig-opt" |
83 | #define RUN_WHITELIST_SRV_DIR "/run/firejail/mnt/orig-srv" | 83 | #define RUN_WHITELIST_SRV_DIR "/run/firejail/mnt/orig-srv" |
84 | #define RUN_WHITELIST_ETC_DIR "/run/firejail/mnt/orig-etc" | ||
85 | #define RUN_WHITELIST_SHARE_DIR "/run/firejail/mnt/orig-share" | ||
84 | 86 | ||
85 | #define RUN_XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority" | 87 | #define RUN_XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority" |
86 | #define RUN_XAUTHORITY_SEC_FILE "/run/firejail/mnt/sec.Xauthority" | 88 | #define RUN_XAUTHORITY_SEC_FILE "/run/firejail/mnt/sec.Xauthority" |
@@ -197,7 +199,9 @@ typedef struct profile_entry_t { | |||
197 | unsigned var_dir:1; // whitelist in /var directory | 199 | unsigned var_dir:1; // whitelist in /var directory |
198 | unsigned dev_dir:1; // whitelist in /dev directory | 200 | unsigned dev_dir:1; // whitelist in /dev directory |
199 | unsigned opt_dir:1; // whitelist in /opt directory | 201 | unsigned opt_dir:1; // whitelist in /opt directory |
200 | unsigned srv_dir:1; // whitelist in /srv directory | 202 | unsigned srv_dir:1; // whitelist in /srv directory |
203 | unsigned etc_dir:1; // whitelist in /etc directory | ||
204 | unsigned share_dir:1; // whitelist in /usr/share directory | ||
201 | }ProfileEntry; | 205 | }ProfileEntry; |
202 | 206 | ||
203 | typedef struct config_t { | 207 | typedef struct config_t { |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index bfc773374..7928aaf3d 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -202,7 +202,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
202 | errExit("asprintf"); | 202 | errExit("asprintf"); |
203 | } | 203 | } |
204 | else if (entry->tmp_dir) { | 204 | else if (entry->tmp_dir) { |
205 | fname = path + 4; // strlen("/tmp") | 205 | fname = path + 5; // strlen("/tmp/") |
206 | if (*fname == '\0') | 206 | if (*fname == '\0') |
207 | goto errexit; | 207 | goto errexit; |
208 | 208 | ||
@@ -210,7 +210,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
210 | errExit("asprintf"); | 210 | errExit("asprintf"); |
211 | } | 211 | } |
212 | else if (entry->media_dir) { | 212 | else if (entry->media_dir) { |
213 | fname = path + 6; // strlen("/media") | 213 | fname = path + 7; // strlen("/media/") |
214 | if (*fname == '\0') | 214 | if (*fname == '\0') |
215 | goto errexit; | 215 | goto errexit; |
216 | 216 | ||
@@ -218,7 +218,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
218 | errExit("asprintf"); | 218 | errExit("asprintf"); |
219 | } | 219 | } |
220 | else if (entry->mnt_dir) { | 220 | else if (entry->mnt_dir) { |
221 | fname = path + 4; // strlen("/mnt") | 221 | fname = path + 5; // strlen("/mnt/") |
222 | if (*fname == '\0') | 222 | if (*fname == '\0') |
223 | goto errexit; | 223 | goto errexit; |
224 | 224 | ||
@@ -226,7 +226,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
226 | errExit("asprintf"); | 226 | errExit("asprintf"); |
227 | } | 227 | } |
228 | else if (entry->var_dir) { | 228 | else if (entry->var_dir) { |
229 | fname = path + 4; // strlen("/var") | 229 | fname = path + 5; // strlen("/var/") |
230 | if (*fname == '\0') | 230 | if (*fname == '\0') |
231 | goto errexit; | 231 | goto errexit; |
232 | 232 | ||
@@ -234,7 +234,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
234 | errExit("asprintf"); | 234 | errExit("asprintf"); |
235 | } | 235 | } |
236 | else if (entry->dev_dir) { | 236 | else if (entry->dev_dir) { |
237 | fname = path + 4; // strlen("/dev") | 237 | fname = path + 5; // strlen("/dev/") |
238 | if (*fname == '\0') | 238 | if (*fname == '\0') |
239 | goto errexit; | 239 | goto errexit; |
240 | 240 | ||
@@ -242,7 +242,7 @@ static void whitelist_path(ProfileEntry *entry) { | |||
242 | errExit("asprintf"); | 242 | errExit("asprintf"); |
243 | } | 243 | } |
244 | else if (entry->opt_dir) { | 244 | else if (entry->opt_dir) { |
245 | fname = path + 4; // strlen("/opt") | 245 | fname = path + 5; // strlen("/opt/") |
246 | if (*fname == '\0') | 246 | if (*fname == '\0') |
247 | goto errexit; | 247 | goto errexit; |
248 | 248 | ||
@@ -250,22 +250,39 @@ static void whitelist_path(ProfileEntry *entry) { | |||
250 | errExit("asprintf"); | 250 | errExit("asprintf"); |
251 | } | 251 | } |
252 | else if (entry->srv_dir) { | 252 | else if (entry->srv_dir) { |
253 | fname = path + 4; // strlen("/srv") | 253 | fname = path + 5; // strlen("/srv/") |
254 | if (*fname == '\0') | 254 | if (*fname == '\0') |
255 | goto errexit; | 255 | goto errexit; |
256 | 256 | ||
257 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SRV_DIR, fname) == -1) | 257 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SRV_DIR, fname) == -1) |
258 | errExit("asprintf"); | 258 | errExit("asprintf"); |
259 | } | 259 | } |
260 | else if (entry->etc_dir) { | ||
261 | fname = path + 5; // strlen("/etc/") | ||
262 | if (*fname == '\0') | ||
263 | goto errexit; | ||
264 | |||
265 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_ETC_DIR, fname) == -1) | ||
266 | errExit("asprintf"); | ||
267 | } | ||
268 | else if (entry->share_dir) { | ||
269 | fname = path + 11; // strlen("/usr/share/") | ||
270 | if (*fname == '\0') | ||
271 | goto errexit; | ||
272 | |||
273 | if (asprintf(&wfile, "%s/%s", RUN_WHITELIST_SHARE_DIR, fname) == -1) | ||
274 | errExit("asprintf"); | ||
275 | } | ||
276 | |||
260 | // check if the file exists | 277 | // check if the file exists |
278 | assert(wfile); | ||
261 | struct stat s; | 279 | struct stat s; |
262 | if (wfile && stat(wfile, &s) == 0) { | 280 | if (stat(wfile, &s) == 0) { |
263 | if (arg_debug || arg_debug_whitelists) | 281 | if (arg_debug || arg_debug_whitelists) |
264 | printf("Whitelisting %s\n", path); | 282 | printf("Whitelisting %s\n", path); |
265 | } | 283 | } |
266 | else { | 284 | else |
267 | return; | 285 | return; |
268 | } | ||
269 | 286 | ||
270 | // create the path if necessary | 287 | // create the path if necessary |
271 | mkpath(path, s.st_mode); | 288 | mkpath(path, s.st_mode); |
@@ -325,6 +342,8 @@ void fs_whitelist(void) { | |||
325 | int dev_dir = 0; // /dev directory flag | 342 | int dev_dir = 0; // /dev directory flag |
326 | int opt_dir = 0; // /opt directory flag | 343 | int opt_dir = 0; // /opt directory flag |
327 | int srv_dir = 0; // /srv directory flag | 344 | int srv_dir = 0; // /srv directory flag |
345 | int etc_dir = 0; // /etc directory flag | ||
346 | int share_dir = 0; // /usr/share directory flag | ||
328 | 347 | ||
329 | size_t nowhitelist_c = 0; | 348 | size_t nowhitelist_c = 0; |
330 | size_t nowhitelist_m = 32; | 349 | size_t nowhitelist_m = 32; |
@@ -414,6 +433,10 @@ void fs_whitelist(void) { | |||
414 | opt_dir = 1; | 433 | opt_dir = 1; |
415 | else if (strncmp(new_name, "/srv/", 5) == 0) | 434 | else if (strncmp(new_name, "/srv/", 5) == 0) |
416 | srv_dir = 1; | 435 | srv_dir = 1; |
436 | else if (strncmp(new_name, "/etc/", 5) == 0) | ||
437 | etc_dir = 1; | ||
438 | else if (strncmp(new_name, "/usr/share/", 11) == 0) | ||
439 | share_dir = 1; | ||
417 | } | 440 | } |
418 | 441 | ||
419 | entry->data = EMPTY_STRING; | 442 | entry->data = EMPTY_STRING; |
@@ -533,6 +556,26 @@ void fs_whitelist(void) { | |||
533 | goto errexit; | 556 | goto errexit; |
534 | } | 557 | } |
535 | } | 558 | } |
559 | else if (strncmp(new_name, "/etc/", 5) == 0) { | ||
560 | entry->etc_dir = 1; | ||
561 | etc_dir = 1; | ||
562 | // special handling for some of the symlinks | ||
563 | if (strcmp(new_name, "/etc/localtime") == 0); | ||
564 | else if (strcmp(new_name, "/etc/mtab") == 0); | ||
565 | else if (strcmp(new_name, "/etc/os-release") == 0); | ||
566 | // both path and absolute path are under /etc | ||
567 | else { | ||
568 | if (strncmp(fname, "/etc/", 5) != 0) | ||
569 | goto errexit; | ||
570 | } | ||
571 | } | ||
572 | else if (strncmp(new_name, "/usr/share/", 11) == 0) { | ||
573 | entry->share_dir = 1; | ||
574 | share_dir = 1; | ||
575 | // both path and absolute path are under /etc | ||
576 | if (strncmp(fname, "/usr/share/", 11) != 0) | ||
577 | goto errexit; | ||
578 | } | ||
536 | else { | 579 | else { |
537 | goto errexit; | 580 | goto errexit; |
538 | } | 581 | } |
@@ -718,6 +761,48 @@ void fs_whitelist(void) { | |||
718 | srv_dir = 0; | 761 | srv_dir = 0; |
719 | } | 762 | } |
720 | 763 | ||
764 | // /etc mountpoint | ||
765 | if (etc_dir) { | ||
766 | // check if /etc directory exists | ||
767 | struct stat s; | ||
768 | if (stat("/etc", &s) == 0) { | ||
769 | // keep a copy of real /etc directory in RUN_WHITELIST_ETC_DIR | ||
770 | mkdir_attr(RUN_WHITELIST_ETC_DIR, 0755, 0, 0); | ||
771 | if (mount("/etc", RUN_WHITELIST_ETC_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
772 | errExit("mount bind"); | ||
773 | |||
774 | // mount tmpfs on /srv | ||
775 | if (arg_debug || arg_debug_whitelists) | ||
776 | printf("Mounting tmpfs on /etc directory\n"); | ||
777 | if (mount("tmpfs", "/etc", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
778 | errExit("mounting tmpfs on /etc"); | ||
779 | fs_logger("tmpfs /etc"); | ||
780 | } | ||
781 | else | ||
782 | etc_dir = 0; | ||
783 | } | ||
784 | |||
785 | // /usr/share mountpoint | ||
786 | if (share_dir) { | ||
787 | // check if /usr/share directory exists | ||
788 | struct stat s; | ||
789 | if (stat("/usr/share", &s) == 0) { | ||
790 | // keep a copy of real /usr/share directory in RUN_WHITELIST_ETC_DIR | ||
791 | mkdir_attr(RUN_WHITELIST_SHARE_DIR, 0755, 0, 0); | ||
792 | if (mount("/usr/share", RUN_WHITELIST_SHARE_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) | ||
793 | errExit("mount bind"); | ||
794 | |||
795 | // mount tmpfs on /srv | ||
796 | if (arg_debug || arg_debug_whitelists) | ||
797 | printf("Mounting tmpfs on /usr/share directory\n"); | ||
798 | if (mount("tmpfs", "/usr/share", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
799 | errExit("mounting tmpfs on /usr/share"); | ||
800 | fs_logger("tmpfs /usr/share"); | ||
801 | } | ||
802 | else | ||
803 | share_dir = 0; | ||
804 | } | ||
805 | |||
721 | 806 | ||
722 | // go through profile rules again, and interpret whitelist commands | 807 | // go through profile rules again, and interpret whitelist commands |
723 | entry = cfg.profile; | 808 | entry = cfg.profile; |
@@ -817,6 +902,20 @@ void fs_whitelist(void) { | |||
817 | fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); | 902 | fs_logger2("tmpfs", RUN_WHITELIST_SRV_DIR); |
818 | } | 903 | } |
819 | 904 | ||
905 | // mask the real /etc directory, currently mounted on RUN_WHITELIST_ETC_DIR | ||
906 | if (etc_dir) { | ||
907 | if (mount("tmpfs", RUN_WHITELIST_ETC_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
908 | errExit("mount tmpfs"); | ||
909 | fs_logger2("tmpfs", RUN_WHITELIST_ETC_DIR); | ||
910 | } | ||
911 | |||
912 | // mask the real /usr/share directory, currently mounted on RUN_WHITELIST_SHARE_DIR | ||
913 | if (share_dir) { | ||
914 | if (mount("tmpfs", RUN_WHITELIST_SHARE_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) | ||
915 | errExit("mount tmpfs"); | ||
916 | fs_logger2("tmpfs", RUN_WHITELIST_SHARE_DIR); | ||
917 | } | ||
918 | |||
820 | if (new_name) | 919 | if (new_name) |
821 | free(new_name); | 920 | free(new_name); |
822 | 921 | ||