aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h6
-rw-r--r--src/firejail/fs_whitelist.c119
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
203typedef struct config_t { 207typedef 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