diff options
-rw-r--r-- | etc/chromium.profile | 3 | ||||
-rw-r--r-- | etc/firefox.profile | 3 | ||||
-rw-r--r-- | src/firejail/fs_whitelist.c | 94 | ||||
-rw-r--r-- | src/firejail/main.c | 2 | ||||
-rw-r--r-- | src/firejail/util.c | 4 | ||||
-rw-r--r-- | src/man/firejail.txt | 9 | ||||
-rwxr-xr-x | test/ignore.exp | 2 | ||||
-rwxr-xr-x | test/invalid_filename.exp | 28 |
8 files changed, 122 insertions, 23 deletions
diff --git a/etc/chromium.profile b/etc/chromium.profile index 980e539d5..03745c1ce 100644 --- a/etc/chromium.profile +++ b/etc/chromium.profile | |||
@@ -9,8 +9,7 @@ include /etc/firejail/disable-common.inc | |||
9 | # | 9 | # |
10 | 10 | ||
11 | netfilter | 11 | netfilter |
12 | whitelist ~/Downloads | 12 | whitelist ${DOWNLOADS} |
13 | whitelist ~/Загрузки | ||
14 | whitelist ~/.config/chromium | 13 | whitelist ~/.config/chromium |
15 | include /etc/firejail/whitelist-common.inc | 14 | include /etc/firejail/whitelist-common.inc |
16 | 15 | ||
diff --git a/etc/firefox.profile b/etc/firefox.profile index 7b3febbae..aa7808c37 100644 --- a/etc/firefox.profile +++ b/etc/firefox.profile | |||
@@ -9,9 +9,8 @@ seccomp | |||
9 | protocol unix,inet,inet6,netlink | 9 | protocol unix,inet,inet6,netlink |
10 | netfilter | 10 | netfilter |
11 | noroot | 11 | noroot |
12 | whitelist ${DOWNLOADS} | ||
12 | whitelist ~/.mozilla | 13 | whitelist ~/.mozilla |
13 | whitelist ~/Downloads | ||
14 | whitelist ~/Загрузки | ||
15 | whitelist ~/.cache/mozilla/firefox | 14 | whitelist ~/.cache/mozilla/firefox |
16 | whitelist ~/dwhelper | 15 | whitelist ~/dwhelper |
17 | whitelist ~/.zotero | 16 | whitelist ~/.zotero |
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c index d018554d5..95238a956 100644 --- a/src/firejail/fs_whitelist.c +++ b/src/firejail/fs_whitelist.c | |||
@@ -27,11 +27,84 @@ | |||
27 | #include <fcntl.h> | 27 | #include <fcntl.h> |
28 | #include <errno.h> | 28 | #include <errno.h> |
29 | 29 | ||
30 | static char *dentry[] = { | ||
31 | "Downloads", | ||
32 | "Загрузки", | ||
33 | "Téléchargement", | ||
34 | NULL | ||
35 | }; | ||
36 | |||
37 | #define MAXBUF 4098 | ||
38 | static char *resolve_downloads(void) { | ||
39 | char *fname; | ||
40 | struct stat s; | ||
41 | |||
42 | // try a well known download directory name | ||
43 | int i = 0; | ||
44 | while (dentry[i] != NULL) { | ||
45 | if (asprintf(&fname, "%s/%s", cfg.homedir, dentry[i]) == -1) | ||
46 | errExit("asprintf"); | ||
47 | |||
48 | if (stat(fname, &s) == 0) { | ||
49 | free(fname); | ||
50 | if (arg_debug) | ||
51 | printf("Downloads directory resolved as \"Downloads\"\n"); | ||
52 | |||
53 | char *rv; | ||
54 | if (asprintf(&rv, "whitelist ~/%s", dentry[i]) == -1) | ||
55 | errExit("asprintf"); | ||
56 | return rv; | ||
57 | } | ||
58 | free(fname); | ||
59 | i++; | ||
60 | } | ||
61 | |||
62 | // try a name form ~/.config/user-dirs.dirs | ||
63 | if (asprintf(&fname, "%s/.config/user-dirs.dirs", cfg.homedir) == -1) | ||
64 | errExit("asprintf"); | ||
65 | FILE *fp = fopen(fname, "r"); | ||
66 | if (!fp) { | ||
67 | free(fname); | ||
68 | return NULL; | ||
69 | } | ||
70 | free(fname); | ||
71 | |||
72 | // extract downloads directory | ||
73 | char buf[MAXBUF]; | ||
74 | while (fgets(buf, MAXBUF, fp)) { | ||
75 | char *ptr = buf; | ||
76 | |||
77 | // skip blanks | ||
78 | while (*ptr == ' ' || *ptr == '\t') | ||
79 | ptr++; | ||
80 | if (*ptr == '\0' || *ptr == '\n' || *ptr == '#') | ||
81 | continue; | ||
82 | |||
83 | if (strncmp(ptr, "XDG_DOWNLOAD_DIR=\"$HOME/", 24) == 0) { | ||
84 | char *ptr1 = strchr(ptr + 24, '"'); | ||
85 | if (ptr1) { | ||
86 | *ptr1 = '\0'; | ||
87 | fclose(fp); | ||
88 | if (arg_debug) | ||
89 | printf("Downloads directory resolved as \"%s\"\n", ptr + 24); | ||
90 | |||
91 | char *rv; | ||
92 | if (asprintf(&rv, "whitelist ~/%s", ptr + 24) == -1) | ||
93 | errExit("asprintf"); | ||
94 | return rv; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | fclose(fp); | ||
99 | |||
100 | return NULL; | ||
101 | } | ||
102 | |||
30 | static int mkpath(const char* path, mode_t mode) { | 103 | static int mkpath(const char* path, mode_t mode) { |
31 | assert(path && *path); | 104 | assert(path && *path); |
32 | 105 | ||
33 | mode |= 0111; | 106 | mode |= 0111; |
34 | 107 | ||
35 | // create directories with uid/gid as root or as current user if inside home directory | 108 | // create directories with uid/gid as root or as current user if inside home directory |
36 | uid_t uid = getuid(); | 109 | uid_t uid = getuid(); |
37 | gid_t gid = getgid(); | 110 | gid_t gid = getgid(); |
@@ -211,6 +284,25 @@ void fs_whitelist(void) { | |||
211 | continue; | 284 | continue; |
212 | } | 285 | } |
213 | 286 | ||
287 | // resolve ${DOWNLOADS} | ||
288 | if (strcmp(entry->data + 10, "${DOWNLOADS}") == 0) { | ||
289 | char *tmp = resolve_downloads(); | ||
290 | if (tmp) | ||
291 | entry->data = tmp; | ||
292 | else { | ||
293 | *entry->data = '\0'; | ||
294 | fprintf(stderr, "***\n"); | ||
295 | fprintf(stderr, "*** Error: cannot whitelist Downloads directory\n"); | ||
296 | fprintf(stderr, "***\n"); | ||
297 | fprintf(stderr, "*** Any file saved in this directory will be lost when the sandbox is closed.\n"); | ||
298 | fprintf(stderr, "*** Please contact the developer. Workaround:\n"); | ||
299 | fprintf(stderr, "***\n"); | ||
300 | fprintf(stderr, "*** firejail --ignore=whitelist program-name\n"); | ||
301 | fprintf(stderr, "***\n"); | ||
302 | continue; | ||
303 | } | ||
304 | } | ||
305 | |||
214 | // replace ~/ or ${HOME} into /home/username | 306 | // replace ~/ or ${HOME} into /home/username |
215 | new_name = expand_home(entry->data + 10, cfg.homedir); | 307 | new_name = expand_home(entry->data + 10, cfg.homedir); |
216 | assert(new_name); | 308 | assert(new_name); |
diff --git a/src/firejail/main.c b/src/firejail/main.c index 02eab1a86..2981683aa 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -737,7 +737,7 @@ int main(int argc, char **argv) { | |||
737 | } | 737 | } |
738 | else if (strncmp(argv[i], "--ignore=", 9) == 0) { | 738 | else if (strncmp(argv[i], "--ignore=", 9) == 0) { |
739 | if (custom_profile) { | 739 | if (custom_profile) { |
740 | fprintf(stderr, "Error: please use --profile after --include\n"); | 740 | fprintf(stderr, "Error: please use --profile after --ignore\n"); |
741 | exit(1); | 741 | exit(1); |
742 | } | 742 | } |
743 | 743 | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index 0d9479a02..45f7ec364 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -574,13 +574,15 @@ void invalid_filename(const char *fname) { | |||
574 | assert(fname); | 574 | assert(fname); |
575 | const char *ptr = fname; | 575 | const char *ptr = fname; |
576 | 576 | ||
577 | if (arg_debug && arg_debug_check_filename) | 577 | if (arg_debug_check_filename) |
578 | printf("Checking filename %s\n", fname); | 578 | printf("Checking filename %s\n", fname); |
579 | 579 | ||
580 | if (strncmp(ptr, "${HOME}", 7) == 0) | 580 | if (strncmp(ptr, "${HOME}", 7) == 0) |
581 | ptr = fname + 7; | 581 | ptr = fname + 7; |
582 | else if (strncmp(ptr, "${PATH}", 7) == 0) | 582 | else if (strncmp(ptr, "${PATH}", 7) == 0) |
583 | ptr = fname + 7; | 583 | ptr = fname + 7; |
584 | else if (strcmp(fname, "${DOWNLOADS}") == 0) | ||
585 | return; | ||
584 | 586 | ||
585 | int len = strlen(ptr); | 587 | int len = strlen(ptr); |
586 | // file globbing ('*') is allowed | 588 | // file globbing ('*') is allowed |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 39e0dbaf7..4f9f0cba9 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -155,8 +155,15 @@ Define a custom whitelist Linux capabilities filter. | |||
155 | Example: | 155 | Example: |
156 | .br | 156 | .br |
157 | $ sudo firejail \-\-caps.keep=chown,net_bind_service,setgid,\\ | 157 | $ sudo firejail \-\-caps.keep=chown,net_bind_service,setgid,\\ |
158 | setuid "/etc/init.d/nginx start && sleep inf" | 158 | setuid /etc/init.d/nginx start |
159 | .br | ||
159 | 160 | ||
161 | .br | ||
162 | A short note about mixing \-\-whitelist and \-\-read-only options. Whitelisted directories | ||
163 | should be made read-only independently. Making a parent directory read-only, will not | ||
164 | make the whitelist read-only. Example: | ||
165 | .br | ||
166 | $ firejail --whitelist=~/work --read-only=~/ --read-only=~/work | ||
160 | .TP | 167 | .TP |
161 | \fB\-\-caps.print=name | 168 | \fB\-\-caps.print=name |
162 | Print the caps filter for the sandbox identified by name. | 169 | Print the caps filter for the sandbox identified by name. |
diff --git a/test/ignore.exp b/test/ignore.exp index 8f8076fb3..c5ea25684 100755 --- a/test/ignore.exp +++ b/test/ignore.exp | |||
@@ -7,7 +7,7 @@ match_max 100000 | |||
7 | send -- "firejail --profile=ignore.profile --ignore=seccomp \r" | 7 | send -- "firejail --profile=ignore.profile --ignore=seccomp \r" |
8 | expect { | 8 | expect { |
9 | timeout {puts "TESTING ERROR 0\n";exit} | 9 | timeout {puts "TESTING ERROR 0\n";exit} |
10 | "Error: please use --profile after --include" | 10 | "Error: please use --profile after --ignore" |
11 | } | 11 | } |
12 | 12 | ||
13 | send -- "firejail --debug --ignore=seccomp\r" | 13 | send -- "firejail --debug --ignore=seccomp\r" |
diff --git a/test/invalid_filename.exp b/test/invalid_filename.exp index 93beff8a1..e496e4aaf 100755 --- a/test/invalid_filename.exp +++ b/test/invalid_filename.exp | |||
@@ -23,7 +23,7 @@ set timeout 10 | |||
23 | spawn $env(SHELL) | 23 | spawn $env(SHELL) |
24 | match_max 100000 | 24 | match_max 100000 |
25 | 25 | ||
26 | send -- "firejail --debug --noprofile --blacklist=\"bla&&bla\"\r" | 26 | send -- "firejail --debug-check-filename --noprofile --blacklist=\"bla&&bla\"\r" |
27 | expect { | 27 | expect { |
28 | timeout {puts "TESTING ERROR 1.1\n";exit} | 28 | timeout {puts "TESTING ERROR 1.1\n";exit} |
29 | "Checking filename bla&&bla" | 29 | "Checking filename bla&&bla" |
@@ -38,7 +38,7 @@ expect { | |||
38 | } | 38 | } |
39 | after 100 | 39 | after 100 |
40 | 40 | ||
41 | send -- "firejail --debug --noprofile --cgroup=\"bla&&bla\"\r" | 41 | send -- "firejail --debug-check-filename --noprofile --cgroup=\"bla&&bla\"\r" |
42 | expect { | 42 | expect { |
43 | timeout {puts "TESTING ERROR 2.1\n";exit} | 43 | timeout {puts "TESTING ERROR 2.1\n";exit} |
44 | "Checking filename bla&&bla" | 44 | "Checking filename bla&&bla" |
@@ -53,7 +53,7 @@ expect { | |||
53 | } | 53 | } |
54 | after 100 | 54 | after 100 |
55 | 55 | ||
56 | send -- "firejail --debug --noprofile --chroot=\"bla&&bla\"\r" | 56 | send -- "firejail --debug-check-filename --noprofile --chroot=\"bla&&bla\"\r" |
57 | expect { | 57 | expect { |
58 | timeout {puts "TESTING ERROR 3.1\n";exit} | 58 | timeout {puts "TESTING ERROR 3.1\n";exit} |
59 | "Checking filename bla&&bla" | 59 | "Checking filename bla&&bla" |
@@ -68,7 +68,7 @@ expect { | |||
68 | } | 68 | } |
69 | after 100 | 69 | after 100 |
70 | 70 | ||
71 | send -- "firejail --debug --noprofile --netfilter=\"bla&&bla\"\r" | 71 | send -- "firejail --debug-check-filename --noprofile --netfilter=\"bla&&bla\"\r" |
72 | expect { | 72 | expect { |
73 | timeout {puts "TESTING ERROR 4.1\n";exit} | 73 | timeout {puts "TESTING ERROR 4.1\n";exit} |
74 | "Checking filename bla&&bla" | 74 | "Checking filename bla&&bla" |
@@ -83,7 +83,7 @@ expect { | |||
83 | } | 83 | } |
84 | after 100 | 84 | after 100 |
85 | 85 | ||
86 | send -- "firejail --debug --noprofile --output=\"bla&&bla\"\r" | 86 | send -- "firejail --debug-check-filename --noprofile --output=\"bla&&bla\"\r" |
87 | expect { | 87 | expect { |
88 | timeout {puts "TESTING ERROR 5.2\n";exit} | 88 | timeout {puts "TESTING ERROR 5.2\n";exit} |
89 | "Error:" | 89 | "Error:" |
@@ -94,7 +94,7 @@ expect { | |||
94 | } | 94 | } |
95 | after 100 | 95 | after 100 |
96 | 96 | ||
97 | send -- "firejail --debug --noprofile --private=\"bla&&bla\"\r" | 97 | send -- "firejail --debug-check-filename --noprofile --private=\"bla&&bla\"\r" |
98 | expect { | 98 | expect { |
99 | timeout {puts "TESTING ERROR 6.1\n";exit} | 99 | timeout {puts "TESTING ERROR 6.1\n";exit} |
100 | "Checking filename bla&&bla" | 100 | "Checking filename bla&&bla" |
@@ -109,7 +109,7 @@ expect { | |||
109 | } | 109 | } |
110 | after 100 | 110 | after 100 |
111 | 111 | ||
112 | send -- "firejail --debug --noprofile --private-bin=\"bla&&bla\"\r" | 112 | send -- "firejail --debug-check-filename --noprofile --private-bin=\"bla&&bla\"\r" |
113 | expect { | 113 | expect { |
114 | timeout {puts "TESTING ERROR 7.1\n";exit} | 114 | timeout {puts "TESTING ERROR 7.1\n";exit} |
115 | "Checking filename bla&&bla" | 115 | "Checking filename bla&&bla" |
@@ -124,7 +124,7 @@ expect { | |||
124 | } | 124 | } |
125 | after 100 | 125 | after 100 |
126 | 126 | ||
127 | send -- "firejail --debug --noprofile --private-home=\"bla&&bla\"\r" | 127 | send -- "firejail --debug-check-filename --noprofile --private-home=\"bla&&bla\"\r" |
128 | expect { | 128 | expect { |
129 | timeout {puts "TESTING ERROR 8.1\n";exit} | 129 | timeout {puts "TESTING ERROR 8.1\n";exit} |
130 | "Checking filename bla&&bla" | 130 | "Checking filename bla&&bla" |
@@ -140,7 +140,7 @@ expect { | |||
140 | after 100 | 140 | after 100 |
141 | 141 | ||
142 | 142 | ||
143 | send -- "firejail --debug --noprofile --private-etc=\"bla&&bla\"\r" | 143 | send -- "firejail --debug-check-filename --noprofile --private-etc=\"bla&&bla\"\r" |
144 | expect { | 144 | expect { |
145 | timeout {puts "TESTING ERROR 9.1\n";exit} | 145 | timeout {puts "TESTING ERROR 9.1\n";exit} |
146 | "Checking filename bla&&bla" | 146 | "Checking filename bla&&bla" |
@@ -155,7 +155,7 @@ expect { | |||
155 | } | 155 | } |
156 | after 100 | 156 | after 100 |
157 | 157 | ||
158 | send -- "firejail --debug --profile=\"bla&&bla\"\r" | 158 | send -- "firejail --debug-check-filename --profile=\"bla&&bla\"\r" |
159 | expect { | 159 | expect { |
160 | timeout {puts "TESTING ERROR 10.1\n";exit} | 160 | timeout {puts "TESTING ERROR 10.1\n";exit} |
161 | "Checking filename bla&&bla" | 161 | "Checking filename bla&&bla" |
@@ -170,7 +170,7 @@ expect { | |||
170 | } | 170 | } |
171 | after 100 | 171 | after 100 |
172 | 172 | ||
173 | send -- "firejail --debug --read-only=\"bla&&bla\"\r" | 173 | send -- "firejail --debug-check-filename --read-only=\"bla&&bla\"\r" |
174 | expect { | 174 | expect { |
175 | timeout {puts "TESTING ERROR 11.1\n";exit} | 175 | timeout {puts "TESTING ERROR 11.1\n";exit} |
176 | "Checking filename bla&&bla" | 176 | "Checking filename bla&&bla" |
@@ -185,7 +185,7 @@ expect { | |||
185 | } | 185 | } |
186 | after 100 | 186 | after 100 |
187 | 187 | ||
188 | send -- "firejail --debug --shell=\"bla&&bla\"\r" | 188 | send -- "firejail --debug-check-filename --shell=\"bla&&bla\"\r" |
189 | expect { | 189 | expect { |
190 | timeout {puts "TESTING ERROR 12.1\n";exit} | 190 | timeout {puts "TESTING ERROR 12.1\n";exit} |
191 | "Checking filename bla&&bla" | 191 | "Checking filename bla&&bla" |
@@ -200,7 +200,7 @@ expect { | |||
200 | } | 200 | } |
201 | after 100 | 201 | after 100 |
202 | 202 | ||
203 | send -- "firejail --debug --tmpfs=\"bla&&bla\"\r" | 203 | send -- "firejail --debug-check-filename --tmpfs=\"bla&&bla\"\r" |
204 | expect { | 204 | expect { |
205 | timeout {puts "TESTING ERROR 13.1\n";exit} | 205 | timeout {puts "TESTING ERROR 13.1\n";exit} |
206 | "Checking filename bla&&bla" | 206 | "Checking filename bla&&bla" |
@@ -215,7 +215,7 @@ expect { | |||
215 | } | 215 | } |
216 | after 100 | 216 | after 100 |
217 | 217 | ||
218 | send -- "firejail --debug --whitelist=\"bla&&bla\"\r" | 218 | send -- "firejail --debug-check-filename --whitelist=\"bla&&bla\"\r" |
219 | expect { | 219 | expect { |
220 | timeout {puts "TESTING ERROR 14.1\n";exit} | 220 | timeout {puts "TESTING ERROR 14.1\n";exit} |
221 | "Checking filename bla&&bla" | 221 | "Checking filename bla&&bla" |