aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/fs.c76
-rw-r--r--src/firejail/profile.c2
-rw-r--r--src/include/common.h1
3 files changed, 57 insertions, 22 deletions
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>