aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2015-09-01 08:27:02 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2015-09-01 08:27:02 -0400
commit38f13e822b3771d5d34d7a4319f0f4baafea8648 (patch)
treedfe36e62a2dd0aeaac4122ccd653a0d5006e0233
parentMerge pull request #51 from sarneaud/gitignore (diff)
parentAdd noblacklist command to firejail. (diff)
downloadfirejail-38f13e822b3771d5d34d7a4319f0f4baafea8648.tar.gz
firejail-38f13e822b3771d5d34d7a4319f0f4baafea8648.tar.zst
firejail-38f13e822b3771d5d34d7a4319f0f4baafea8648.zip
Merge pull request #53 from sarneaud/noblacklist
Noblacklist
-rw-r--r--etc/chromium.profile3
-rw-r--r--etc/filezilla.profile4
-rw-r--r--etc/firefox.profile3
-rw-r--r--etc/midori.profile5
-rw-r--r--etc/opera.profile3
-rw-r--r--etc/server.profile4
-rw-r--r--src/firejail/fs.c76
-rw-r--r--src/firejail/profile.c2
-rw-r--r--src/include/common.h1
-rw-r--r--src/man/firejail-profile.txt9
10 files changed, 81 insertions, 29 deletions
diff --git a/etc/chromium.profile b/etc/chromium.profile
index 13559a5a8..6c3a5f2f8 100644
--- a/etc/chromium.profile
+++ b/etc/chromium.profile
@@ -1,7 +1,8 @@
1# Chromium browser profile 1# Chromium browser profile
2noblacklist ${HOME}/.config/chromium
2include /etc/firejail/disable-mgmt.inc 3include /etc/firejail/disable-mgmt.inc
3include /etc/firejail/disable-secret.inc 4include /etc/firejail/disable-secret.inc
4include /etc/firejail/disable-common.inc chromium 5include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-history.inc 6include /etc/firejail/disable-history.inc
6netfilter 7netfilter
7 8
diff --git a/etc/filezilla.profile b/etc/filezilla.profile
index dc5086595..437fa6d43 100644
--- a/etc/filezilla.profile
+++ b/etc/filezilla.profile
@@ -1,7 +1,9 @@
1# FileZilla profile 1# FileZilla profile
2noblacklist ${HOME}/.filezilla
3noblacklist ${HOME}/.config/filezilla
2include /etc/firejail/disable-mgmt.inc 4include /etc/firejail/disable-mgmt.inc
3include /etc/firejail/disable-secret.inc 5include /etc/firejail/disable-secret.inc
4include /etc/firejail/disable-common.inc .filezilla 6include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-history.inc 7include /etc/firejail/disable-history.inc
6caps.drop all 8caps.drop all
7seccomp 9seccomp
diff --git a/etc/firefox.profile b/etc/firefox.profile
index cd504ab44..e5b820d39 100644
--- a/etc/firefox.profile
+++ b/etc/firefox.profile
@@ -1,7 +1,8 @@
1# Firejail profile for Mozilla Firefox (Iceweasel in Debian) 1# Firejail profile for Mozilla Firefox (Iceweasel in Debian)
2noblacklist ${HOME}/.mozilla
2include /etc/firejail/disable-mgmt.inc 3include /etc/firejail/disable-mgmt.inc
3include /etc/firejail/disable-secret.inc 4include /etc/firejail/disable-secret.inc
4include /etc/firejail/disable-common.inc .mozilla 5include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-history.inc 6include /etc/firejail/disable-history.inc
6caps.drop all 7caps.drop all
7seccomp 8seccomp
diff --git a/etc/midori.profile b/etc/midori.profile
index b21bc94ef..5bc864e31 100644
--- a/etc/midori.profile
+++ b/etc/midori.profile
@@ -1,7 +1,8 @@
1# Midory browser profile 1# Midori browser profile
2noblacklist ${HOME}/.config/midori
2include /etc/firejail/disable-mgmt.inc 3include /etc/firejail/disable-mgmt.inc
3include /etc/firejail/disable-secret.inc 4include /etc/firejail/disable-secret.inc
4include /etc/firejail/disable-common.inc midori 5include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-history.inc 6include /etc/firejail/disable-history.inc
6caps.drop all 7caps.drop all
7seccomp 8seccomp
diff --git a/etc/opera.profile b/etc/opera.profile
index 8f8dbc609..d55c0aaa3 100644
--- a/etc/opera.profile
+++ b/etc/opera.profile
@@ -1,7 +1,8 @@
1# Chromium browser profile 1# Chromium browser profile
2noblacklist ${HOME}/.config/opera
2include /etc/firejail/disable-mgmt.inc 3include /etc/firejail/disable-mgmt.inc
3include /etc/firejail/disable-secret.inc 4include /etc/firejail/disable-secret.inc
4include /etc/firejail/disable-common.inc opera 5include /etc/firejail/disable-common.inc
5include /etc/firejail/disable-history.inc 6include /etc/firejail/disable-history.inc
6netfilter 7netfilter
7noroot 8noroot
diff --git a/etc/server.profile b/etc/server.profile
index 1c6461094..5b706df9a 100644
--- a/etc/server.profile
+++ b/etc/server.profile
@@ -1,6 +1,8 @@
1# generic server profile 1# generic server profile
2# it allows /sbin and /usr/sbin directories - this is where servers are installed 2# it allows /sbin and /usr/sbin directories - this is where servers are installed
3include /etc/firejail/disable-mgmt.inc sbin 3noblacklist /sbin
4noblacklist /usr/sbin
5include /etc/firejail/disable-mgmt.inc
4private 6private
5private-dev 7private-dev
6seccomp 8seccomp
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 8a6dfc674..8632952a4 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -21,6 +21,7 @@
21#include <sys/mount.h> 21#include <sys/mount.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <linux/limits.h> 23#include <linux/limits.h>
24#include <fnmatch.h>
24#include <glob.h> 25#include <glob.h>
25#include <dirent.h> 26#include <dirent.h>
26#include <fcntl.h> 27#include <fcntl.h>
@@ -198,7 +199,7 @@ static void disable_file(OPERATION op, const char *filename, const char *emptydi
198} 199}
199 200
200// Treat pattern as a shell glob pattern and blacklist matching files 201// Treat pattern as a shell glob pattern and blacklist matching files
201static void globbing(OPERATION op, const char *pattern, const char *emptydir, const char *emptyfile) { 202static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len, const char *emptydir, const char *emptyfile) {
202 assert(pattern); 203 assert(pattern);
203 assert(emptydir); 204 assert(emptydir);
204 assert(emptyfile); 205 assert(emptyfile);
@@ -209,29 +210,34 @@ static void globbing(OPERATION op, const char *pattern, const char *emptydir, co
209 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT, NULL, &globbuf); 210 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT, NULL, &globbuf);
210 if (globerr) { 211 if (globerr) {
211 fprintf(stderr, "Error: failed to glob pattern %s\n", pattern); 212 fprintf(stderr, "Error: failed to glob pattern %s\n", pattern);
212 return; 213 exit(1);
213 } 214 }
214 215
215 size_t i; 216 size_t i, j;
216 for (i = 0; i < globbuf.gl_pathc; i++) { 217 for (i = 0; i < globbuf.gl_pathc; i++) {
217 char* match = globbuf.gl_pathv[i]; 218 char* path = globbuf.gl_pathv[i];
218 assert(match); 219 assert(path);
219 disable_file(op, match, emptydir, emptyfile); 220 // noblacklist is expected to be short in normal cases, so stupid and correct brute force is okay
221 bool okay_to_blacklist = true;
222 for (j = 0; j < noblacklist_len; j++) {
223 int result = fnmatch(noblacklist[j], path, FNM_PATHNAME);
224 if (result == FNM_NOMATCH)
225 continue;
226 else if (result == 0) {
227 okay_to_blacklist = false;
228 break;
229 }
230 else {
231 fprintf(stderr, "Error: failed to compare path %s with pattern %s\n", path, noblacklist[j]);
232 exit(1);
233 }
234 }
235 if (okay_to_blacklist)
236 disable_file(op, path, emptydir, emptyfile);
220 } 237 }
221 globfree(&globbuf); 238 globfree(&globbuf);
222} 239}
223 240
224static void expand_path(OPERATION op, const char *path, const char *fname, const char *emptydir, const char *emptyfile) {
225 assert(path);
226 assert(fname);
227 assert(emptydir);
228 assert(emptyfile);
229 char newname[strlen(path) + strlen(fname) + 1];
230 sprintf(newname, "%s%s", path, fname);
231
232 globbing(op, newname, emptydir, emptyfile);
233}
234
235// blacklist files or directoies by mounting empty files on top of them 241// blacklist files or directoies by mounting empty files on top of them
236void fs_blacklist(const char *homedir) { 242void fs_blacklist(const char *homedir) {
237 ProfileEntry *entry = cfg.profile; 243 ProfileEntry *entry = cfg.profile;
@@ -241,6 +247,12 @@ void fs_blacklist(const char *homedir) {
241 char *emptydir = create_empty_dir(); 247 char *emptydir = create_empty_dir();
242 char *emptyfile = create_empty_file(); 248 char *emptyfile = create_empty_file();
243 249
250 // a statically allocated buffer works for all current needs
251 // TODO: if dynamic allocation is ever needed, we should probably add
252 // libraries that make it easy to do without introducing security bugs
253 char *noblacklist[32];
254 size_t noblacklist_c = 0;
255
244 while (entry) { 256 while (entry) {
245 OPERATION op = OPERATION_MAX; 257 OPERATION op = OPERATION_MAX;
246 char *ptr; 258 char *ptr;
@@ -283,6 +295,18 @@ void fs_blacklist(const char *homedir) {
283 continue; 295 continue;
284 } 296 }
285 297
298 // Process noblacklist command
299 if (strncmp(entry->data, "noblacklist ", 12) == 0) {
300 if (noblacklist_c >= sizeof(noblacklist) / sizeof(noblacklist[0])) {
301 fputs("Error: out of memory for noblacklist entries\n", stderr);
302 exit(1);
303 }
304 else
305 noblacklist[noblacklist_c++] = expand_home(entry->data + 12, homedir);
306 entry = entry->next;
307 continue;
308 }
309
286 // process blacklist command 310 // process blacklist command
287 if (strncmp(entry->data, "blacklist ", 10) == 0) { 311 if (strncmp(entry->data, "blacklist ", 10) == 0) {
288 ptr = entry->data + 10; 312 ptr = entry->data + 10;
@@ -307,19 +331,27 @@ void fs_blacklist(const char *homedir) {
307 ptr = new_name; 331 ptr = new_name;
308 332
309 // expand path macro - look for the file in /bin, /usr/bin, /sbin and /usr/sbin directories 333 // expand path macro - look for the file in /bin, /usr/bin, /sbin and /usr/sbin directories
334 // TODO: should we look for more bin paths?
310 if (strncmp(ptr, "${PATH}", 7) == 0) { 335 if (strncmp(ptr, "${PATH}", 7) == 0) {
311 expand_path(op, "/bin", ptr + 7, emptydir, emptyfile); 336 char *fname = ptr + 7;
312 expand_path(op, "/sbin", ptr + 7, emptydir, emptyfile); 337 size_t fname_len = strlen(fname);
313 expand_path(op, "/usr/bin", ptr + 7, emptydir, emptyfile); 338 char **path, *paths[] = {"/bin", "/sbin", "/usr/bin", "/usr/sbin", NULL};
314 expand_path(op, "/usr/sbin", ptr + 7, emptydir, emptyfile); 339 for (path = &paths[0]; *path; path++) {
340 char newname[strlen(*path) + fname_len + 1];
341 sprintf(newname, "%s%s", *path, fname);
342 globbing(op, newname, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile);
343 }
315 } 344 }
316 else 345 else
317 globbing(op, ptr, emptydir, emptyfile); 346 globbing(op, ptr, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile);
318 347
319 if (new_name) 348 if (new_name)
320 free(new_name); 349 free(new_name);
321 entry = entry->next; 350 entry = entry->next;
322 } 351 }
352
353 size_t i;
354 for (i = 0; i < noblacklist_c; i++) free(noblacklist[i]);
323} 355}
324 356
325//*********************************************** 357//***********************************************
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 1093e1503..778478321 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -334,6 +334,8 @@ int profile_check_line(char *ptr, int lineno) {
334 // rest of filesystem 334 // rest of filesystem
335 if (strncmp(ptr, "blacklist ", 10) == 0) 335 if (strncmp(ptr, "blacklist ", 10) == 0)
336 ptr += 10; 336 ptr += 10;
337 else if (strncmp(ptr, "noblacklist ", 12) == 0)
338 ptr += 12;
337 else if (strncmp(ptr, "read-only ", 10) == 0) 339 else if (strncmp(ptr, "read-only ", 10) == 0)
338 ptr += 10; 340 ptr += 10;
339 else if (strncmp(ptr, "tmpfs ", 6) == 0) 341 else if (strncmp(ptr, "tmpfs ", 6) == 0)
diff --git a/src/include/common.h b/src/include/common.h
index 7ce1e9290..a42e7ad9e 100644
--- a/src/include/common.h
+++ b/src/include/common.h
@@ -25,6 +25,7 @@
25#include <sys/types.h> 25#include <sys/types.h>
26#include <unistd.h> 26#include <unistd.h>
27#include <stdlib.h> 27#include <stdlib.h>
28#include <stdbool.h>
28#include <stdint.h> 29#include <stdint.h>
29#include <stddef.h> 30#include <stddef.h>
30#include <string.h> 31#include <string.h>
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index 5167a4c42..64565ab0b 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -87,6 +87,7 @@ Example: "include ${HOME}/myprofiles/profile1" will load "~/myprofiles/profile1"
87These profile entries define a chroot filesystem built on top of the existing 87These profile entries define a chroot filesystem built on top of the existing
88host filesystem. Each line describes a file element that is removed from 88host filesystem. Each line describes a file element that is removed from
89the filesystem (\fBblacklist\fR), a read-only file or directory (\fBread-only\fR), 89the filesystem (\fBblacklist\fR), a read-only file or directory (\fBread-only\fR),
90a filter for finer control of blacklisting (\fBnoblacklist\fR),
90a tmpfs mounted on top of an existing directory (\fBtmpfs\fR), 91a tmpfs mounted on top of an existing directory (\fBtmpfs\fR),
91or mount-bind a directory or file on top of another directory or file (\fBbind\fR). 92or mount-bind a directory or file on top of another directory or file (\fBbind\fR).
92Use \fBprivate\fR to set private mode. 93Use \fBprivate\fR to set private mode.
@@ -117,6 +118,14 @@ Remove ifconfig command from the regular path directories.
117\f\blacklist ${HOME}/.ssh 118\f\blacklist ${HOME}/.ssh
118Remove .ssh directory from user home directory. 119Remove .ssh directory from user home directory.
119.TP 120.TP
121\f\ noblacklist ${HOME}/config/evince
122Prevent any new blacklist commands from blacklisting
123config/evince in the user home directory. Useful for defining
124exceptions before including a large blacklist from a file. Note
125that blacklisting ${HOME}/config can still make
126${HOME}/config/evince effectively unreachable through filesystem
127traversal.
128.TP
120\f\private 129\f\private
121Mount new /root and /home/user directories in temporary 130Mount new /root and /home/user directories in temporary
122filesystems. All modifications are discarded when the sandbox is 131filesystems. All modifications are discarded when the sandbox is