diff options
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/fs_home.c | 15 | ||||
-rw-r--r-- | src/firejail/main.c | 15 | ||||
-rw-r--r-- | src/firejail/profile.c | 14 | ||||
-rw-r--r-- | src/firejail/sandbox.c | 4 | ||||
-rw-r--r-- | src/firejail/usage.c | 2 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 6 | ||||
-rw-r--r-- | src/man/firejail.txt | 42 | ||||
-rwxr-xr-x | test/fs/fs.sh | 3 | ||||
-rwxr-xr-x | test/fs/private-cwd.exp | 52 |
10 files changed, 155 insertions, 1 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index e0f3a6a16..bbdf279ce 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -283,6 +283,7 @@ extern int arg_private_srv; // private srv directory | |||
283 | extern int arg_private_bin; // private bin directory | 283 | extern int arg_private_bin; // private bin directory |
284 | extern int arg_private_tmp; // private tmp directory | 284 | extern int arg_private_tmp; // private tmp directory |
285 | extern int arg_private_lib; // private lib directory | 285 | extern int arg_private_lib; // private lib directory |
286 | extern int arg_private_cwd; // private working directory | ||
286 | extern int arg_scan; // arp-scan all interfaces | 287 | extern int arg_scan; // arp-scan all interfaces |
287 | extern int arg_whitelist; // whitelist command | 288 | extern int arg_whitelist; // whitelist command |
288 | extern int arg_nosound; // disable sound | 289 | extern int arg_nosound; // disable sound |
@@ -521,6 +522,8 @@ void fs_private(void); | |||
521 | void fs_private_homedir(void); | 522 | void fs_private_homedir(void); |
522 | // check new private home directory (--private= option) - exit if it fails | 523 | // check new private home directory (--private= option) - exit if it fails |
523 | void fs_check_private_dir(void); | 524 | void fs_check_private_dir(void); |
525 | // check new private working directory (--private-cwd= option) - exit if it fails | ||
526 | void fs_check_private_cwd(void); | ||
524 | void fs_private_home_list(void); | 527 | void fs_private_home_list(void); |
525 | 528 | ||
526 | 529 | ||
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c index b44d09acc..a1a16841a 100644 --- a/src/firejail/fs_home.c +++ b/src/firejail/fs_home.c | |||
@@ -370,6 +370,21 @@ void fs_check_private_dir(void) { | |||
370 | } | 370 | } |
371 | } | 371 | } |
372 | 372 | ||
373 | // check new private working directory (--private-cwd= option) - exit if it fails | ||
374 | void fs_check_private_cwd(void) { | ||
375 | EUID_ASSERT(); | ||
376 | invalid_filename(cfg.cwd, 0); // no globbing | ||
377 | |||
378 | // Expand the working directory | ||
379 | cfg.cwd = expand_macros(cfg.cwd); | ||
380 | |||
381 | // realpath/is_dir not used because path may not exist outside of jail | ||
382 | if (!cfg.cwd) { | ||
383 | fprintf(stderr, "Error: invalid private working directory\n"); | ||
384 | exit(1); | ||
385 | } | ||
386 | } | ||
387 | |||
373 | //*********************************************************************************** | 388 | //*********************************************************************************** |
374 | // --private-home | 389 | // --private-home |
375 | //*********************************************************************************** | 390 | //*********************************************************************************** |
diff --git a/src/firejail/main.c b/src/firejail/main.c index f3dc72944..2c7290854 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -92,6 +92,7 @@ int arg_private_srv = 0; // private srv directory | |||
92 | int arg_private_bin = 0; // private bin directory | 92 | int arg_private_bin = 0; // private bin directory |
93 | int arg_private_tmp = 0; // private tmp directory | 93 | int arg_private_tmp = 0; // private tmp directory |
94 | int arg_private_lib = 0; // private lib directory | 94 | int arg_private_lib = 0; // private lib directory |
95 | int arg_private_cwd = 0; // private working directory | ||
95 | int arg_scan = 0; // arp-scan all interfaces | 96 | int arg_scan = 0; // arp-scan all interfaces |
96 | int arg_whitelist = 0; // whitelist command | 97 | int arg_whitelist = 0; // whitelist command |
97 | int arg_nosound = 0; // disable sound | 98 | int arg_nosound = 0; // disable sound |
@@ -1773,6 +1774,20 @@ int main(int argc, char **argv) { | |||
1773 | else | 1774 | else |
1774 | exit_err_feature("private-cache"); | 1775 | exit_err_feature("private-cache"); |
1775 | } | 1776 | } |
1777 | else if (strcmp(argv[i], "--private-cwd") == 0) { | ||
1778 | cfg.cwd = NULL; | ||
1779 | arg_private_cwd = 1; | ||
1780 | } | ||
1781 | else if (strncmp(argv[i], "--private-cwd=", 14) == 0) { | ||
1782 | cfg.cwd = argv[i] + 14; | ||
1783 | if (*cfg.cwd == '\0') { | ||
1784 | fprintf(stderr, "Error: invalid private-cwd option\n"); | ||
1785 | exit(1); | ||
1786 | } | ||
1787 | |||
1788 | fs_check_private_cwd(); | ||
1789 | arg_private_cwd = 1; | ||
1790 | } | ||
1776 | 1791 | ||
1777 | //************************************* | 1792 | //************************************* |
1778 | // hostname, etc | 1793 | // hostname, etc |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index c8619f7e2..801c8ba4c 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -338,7 +338,7 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
338 | arg_private = 1; | 338 | arg_private = 1; |
339 | return 0; | 339 | return 0; |
340 | } | 340 | } |
341 | if (strncmp(ptr, "private-home ", 13) == 0) { | 341 | else if (strncmp(ptr, "private-home ", 13) == 0) { |
342 | #ifdef HAVE_PRIVATE_HOME | 342 | #ifdef HAVE_PRIVATE_HOME |
343 | if (checkcfg(CFG_PRIVATE_HOME)) { | 343 | if (checkcfg(CFG_PRIVATE_HOME)) { |
344 | if (cfg.home_private_keep) { | 344 | if (cfg.home_private_keep) { |
@@ -353,6 +353,18 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
353 | #endif | 353 | #endif |
354 | return 0; | 354 | return 0; |
355 | } | 355 | } |
356 | else if (strcmp(ptr, "private-cwd") == 0) { | ||
357 | cfg.cwd = NULL; | ||
358 | arg_private_cwd = 1; | ||
359 | return 0; | ||
360 | } | ||
361 | else if (strncmp(ptr, "private-cwd ", 12) == 0) { | ||
362 | cfg.cwd = strdup(ptr + 12); | ||
363 | |||
364 | fs_check_private_cwd(); | ||
365 | arg_private_cwd = 1; | ||
366 | return 0; | ||
367 | } | ||
356 | else if (strcmp(ptr, "allusers") == 0) { | 368 | else if (strcmp(ptr, "allusers") == 0) { |
357 | arg_allusers = 1; | 369 | arg_allusers = 1; |
358 | return 0; | 370 | return 0; |
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c index 9f0a5f25c..250247f8a 100644 --- a/src/firejail/sandbox.c +++ b/src/firejail/sandbox.c | |||
@@ -1016,6 +1016,10 @@ int sandbox(void* sandbox_arg) { | |||
1016 | if (cfg.cwd) { | 1016 | if (cfg.cwd) { |
1017 | if (chdir(cfg.cwd) == 0) | 1017 | if (chdir(cfg.cwd) == 0) |
1018 | cwd = 1; | 1018 | cwd = 1; |
1019 | else if (arg_private_cwd) { | ||
1020 | fprintf(stderr, "Error: unabled to enter private working directory: %s: %s\n", cfg.cwd, strerror(errno)); | ||
1021 | exit(1); | ||
1022 | } | ||
1019 | } | 1023 | } |
1020 | 1024 | ||
1021 | if (!cwd) { | 1025 | if (!cwd) { |
diff --git a/src/firejail/usage.c b/src/firejail/usage.c index 7620bba82..a8d5bfdda 100644 --- a/src/firejail/usage.c +++ b/src/firejail/usage.c | |||
@@ -162,6 +162,8 @@ static char *usage_str = | |||
162 | " --private-etc=file,directory - build a new /etc in a temporary\n" | 162 | " --private-etc=file,directory - build a new /etc in a temporary\n" |
163 | "\tfilesystem, and copy the files and directories in the list.\n" | 163 | "\tfilesystem, and copy the files and directories in the list.\n" |
164 | " --private-tmp - mount a tmpfs on top of /tmp directory.\n" | 164 | " --private-tmp - mount a tmpfs on top of /tmp directory.\n" |
165 | " --private-cwd - do not inherit working directory inside jail.\n" | ||
166 | " --private-cwd=directory - set working directory inside jail.\n" | ||
165 | " --private-opt=file,directory - build a new /opt in a temporary filesystem.\n" | 167 | " --private-opt=file,directory - build a new /opt in a temporary filesystem.\n" |
166 | " --private-srv=file,directory - build a new /srv in a temporary filesystem.\n" | 168 | " --private-srv=file,directory - build a new /srv in a temporary filesystem.\n" |
167 | " --profile=filename|profile_name - use a custom profile.\n" | 169 | " --profile=filename|profile_name - use a custom profile.\n" |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 703fac30f..23007725a 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -288,6 +288,12 @@ All modifications are discarded when the sandbox is closed. | |||
288 | \fBprivate-tmp | 288 | \fBprivate-tmp |
289 | Mount an empty temporary filesystem on top of /tmp directory whitelisting /tmp/.X11-unix. | 289 | Mount an empty temporary filesystem on top of /tmp directory whitelisting /tmp/.X11-unix. |
290 | .TP | 290 | .TP |
291 | \fBprivate-cwd | ||
292 | Set working directory inside jail to the home directory, and failing that, the root directory. | ||
293 | .TP | ||
294 | \fBprivate-cwd directory | ||
295 | Set working directory inside the jail. | ||
296 | .TP | ||
291 | \fBread-only file_or_directory | 297 | \fBread-only file_or_directory |
292 | Make directory or file read-only. | 298 | Make directory or file read-only. |
293 | .TP | 299 | .TP |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index e6826448b..1fa2a6546 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -1568,6 +1568,48 @@ drwx------ 2 nobody nogroup 4096 Apr 30 10:52 pulse-PKdhtXMmr18n | |||
1568 | drwxrwxrwt 2 nobody nogroup 4096 Apr 30 10:52 .X11-unix | 1568 | drwxrwxrwt 2 nobody nogroup 4096 Apr 30 10:52 .X11-unix |
1569 | .br | 1569 | .br |
1570 | 1570 | ||
1571 | .TP | ||
1572 | \fB\-\-private-cwd | ||
1573 | Set working directory inside jail to the home directory, and failing that, the root directory. | ||
1574 | .br | ||
1575 | Does not impact working directory of profile include paths. | ||
1576 | .br | ||
1577 | |||
1578 | .br | ||
1579 | Example: | ||
1580 | .br | ||
1581 | $ pwd | ||
1582 | .br | ||
1583 | /tmp | ||
1584 | .br | ||
1585 | $ firejail \-\-private-cwd | ||
1586 | .br | ||
1587 | $ pwd | ||
1588 | .br | ||
1589 | /home/user | ||
1590 | .br | ||
1591 | |||
1592 | .TP | ||
1593 | \fB\-\-private-cwd=directory | ||
1594 | Set working directory inside the jail. | ||
1595 | .br | ||
1596 | Does not impact working directory of profile include paths. | ||
1597 | .br | ||
1598 | |||
1599 | .br | ||
1600 | Example: | ||
1601 | .br | ||
1602 | $ pwd | ||
1603 | .br | ||
1604 | /tmp | ||
1605 | .br | ||
1606 | $ firejail \-\-private-cwd=/opt | ||
1607 | .br | ||
1608 | $ pwd | ||
1609 | .br | ||
1610 | /opt | ||
1611 | .br | ||
1612 | |||
1571 | 1613 | ||
1572 | .TP | 1614 | .TP |
1573 | \fB\-\-profile=filename_or_profilename | 1615 | \fB\-\-profile=filename_or_profilename |
diff --git a/test/fs/fs.sh b/test/fs/fs.sh index 0fc216b20..7e1d46f0a 100755 --- a/test/fs/fs.sh +++ b/test/fs/fs.sh | |||
@@ -69,6 +69,9 @@ echo "TESTING: empty private-etc (test/fs/private-etc-empty.exp)" | |||
69 | echo "TESTING: private-bin (test/fs/private-bin.exp)" | 69 | echo "TESTING: private-bin (test/fs/private-bin.exp)" |
70 | ./private-bin.exp | 70 | ./private-bin.exp |
71 | 71 | ||
72 | echo "TESTING: private-cwd (test/fs/private-cwd.exp)" | ||
73 | ./private-cwd.exp | ||
74 | |||
72 | echo "TESTING: macros (test/fs/macro.exp)" | 75 | echo "TESTING: macros (test/fs/macro.exp)" |
73 | ./macro.exp | 76 | ./macro.exp |
74 | 77 | ||
diff --git a/test/fs/private-cwd.exp b/test/fs/private-cwd.exp new file mode 100755 index 000000000..0fa87a92f --- /dev/null +++ b/test/fs/private-cwd.exp | |||
@@ -0,0 +1,52 @@ | |||
1 | #!/usr/bin/expect -f | ||
2 | # This file is part of Firejail project | ||
3 | # Copyright (C) 2014-2019 Firejail Authors | ||
4 | # License GPL v2 | ||
5 | |||
6 | set timeout 10 | ||
7 | spawn $env(SHELL) | ||
8 | match_max 100000 | ||
9 | |||
10 | send -- "cd /tmp\r" | ||
11 | after 100 | ||
12 | |||
13 | # testing profile and private | ||
14 | send -- "firejail --private-cwd\r" | ||
15 | expect { | ||
16 | timeout {puts "TESTING ERROR 0\n";exit} | ||
17 | "Child process initialized" | ||
18 | } | ||
19 | sleep 1 | ||
20 | |||
21 | send -- "pwd\r" | ||
22 | expect { | ||
23 | timeout {puts "TESTING ERROR 1\n";exit} | ||
24 | "$env(HOME)" | ||
25 | } | ||
26 | after 100 | ||
27 | |||
28 | send -- "exit\r" | ||
29 | sleep 1 | ||
30 | |||
31 | send -- "cd /\r" | ||
32 | after 100 | ||
33 | |||
34 | # testing profile and private | ||
35 | send -- "firejail --private-cwd=/tmp\r" | ||
36 | expect { | ||
37 | timeout {puts "TESTING ERROR 3\n";exit} | ||
38 | "Child process initialized" | ||
39 | } | ||
40 | sleep 1 | ||
41 | |||
42 | send -- "pwd\r" | ||
43 | expect { | ||
44 | timeout {puts "TESTING ERROR 4\n";exit} | ||
45 | "/tmp" | ||
46 | } | ||
47 | after 100 | ||
48 | |||
49 | send -- "exit\r" | ||
50 | sleep 1 | ||
51 | |||
52 | puts "all done\n" | ||