From 829d9e0c4c9ae700ab02e2809ac1d5eb72532357 Mon Sep 17 00:00:00 2001 From: sarneaud Date: Tue, 1 Sep 2015 14:29:26 +1000 Subject: Simple implementation of noblacklist command. --- src/firejail/fs.c | 76 +++++++++++++++++++++++++++++++++++--------------- src/firejail/profile.c | 2 ++ src/include/common.h | 1 + 3 files changed, 57 insertions(+), 22 deletions(-) (limited to 'src') 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 @@ #include #include #include +#include #include #include #include @@ -198,7 +199,7 @@ static void disable_file(OPERATION op, const char *filename, const char *emptydi } // Treat pattern as a shell glob pattern and blacklist matching files -static void globbing(OPERATION op, const char *pattern, const char *emptydir, const char *emptyfile) { +static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len, const char *emptydir, const char *emptyfile) { assert(pattern); assert(emptydir); assert(emptyfile); @@ -209,29 +210,34 @@ static void globbing(OPERATION op, const char *pattern, const char *emptydir, co int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT, NULL, &globbuf); if (globerr) { fprintf(stderr, "Error: failed to glob pattern %s\n", pattern); - return; + exit(1); } - size_t i; + size_t i, j; for (i = 0; i < globbuf.gl_pathc; i++) { - char* match = globbuf.gl_pathv[i]; - assert(match); - disable_file(op, match, emptydir, emptyfile); + char* path = globbuf.gl_pathv[i]; + assert(path); + // noblacklist is expected to be short in normal cases, so stupid and correct brute force is okay + bool okay_to_blacklist = true; + for (j = 0; j < noblacklist_len; j++) { + int result = fnmatch(noblacklist[j], path, FNM_PATHNAME); + if (result == FNM_NOMATCH) + continue; + else if (result == 0) { + okay_to_blacklist = false; + break; + } + else { + fprintf(stderr, "Error: failed to compare path %s with pattern %s\n", path, noblacklist[j]); + exit(1); + } + } + if (okay_to_blacklist) + disable_file(op, path, emptydir, emptyfile); } globfree(&globbuf); } -static void expand_path(OPERATION op, const char *path, const char *fname, const char *emptydir, const char *emptyfile) { - assert(path); - assert(fname); - assert(emptydir); - assert(emptyfile); - char newname[strlen(path) + strlen(fname) + 1]; - sprintf(newname, "%s%s", path, fname); - - globbing(op, newname, emptydir, emptyfile); -} - // blacklist files or directoies by mounting empty files on top of them void fs_blacklist(const char *homedir) { ProfileEntry *entry = cfg.profile; @@ -241,6 +247,12 @@ void fs_blacklist(const char *homedir) { char *emptydir = create_empty_dir(); char *emptyfile = create_empty_file(); + // a statically allocated buffer works for all current needs + // TODO: if dynamic allocation is ever needed, we should probably add + // libraries that make it easy to do without introducing security bugs + char *noblacklist[32]; + size_t noblacklist_c = 0; + while (entry) { OPERATION op = OPERATION_MAX; char *ptr; @@ -283,6 +295,18 @@ void fs_blacklist(const char *homedir) { continue; } + // Process noblacklist command + if (strncmp(entry->data, "noblacklist ", 12) == 0) { + if (noblacklist_c >= sizeof(noblacklist) / sizeof(noblacklist[0])) { + fputs("Error: out of memory for noblacklist entries\n", stderr); + exit(1); + } + else + noblacklist[noblacklist_c++] = expand_home(entry->data + 12, homedir); + entry = entry->next; + continue; + } + // process blacklist command if (strncmp(entry->data, "blacklist ", 10) == 0) { ptr = entry->data + 10; @@ -307,19 +331,27 @@ void fs_blacklist(const char *homedir) { ptr = new_name; // expand path macro - look for the file in /bin, /usr/bin, /sbin and /usr/sbin directories + // TODO: should we look for more bin paths? if (strncmp(ptr, "${PATH}", 7) == 0) { - expand_path(op, "/bin", ptr + 7, emptydir, emptyfile); - expand_path(op, "/sbin", ptr + 7, emptydir, emptyfile); - expand_path(op, "/usr/bin", ptr + 7, emptydir, emptyfile); - expand_path(op, "/usr/sbin", ptr + 7, emptydir, emptyfile); + char *fname = ptr + 7; + size_t fname_len = strlen(fname); + char **path, *paths[] = {"/bin", "/sbin", "/usr/bin", "/usr/sbin", NULL}; + for (path = &paths[0]; *path; path++) { + char newname[strlen(*path) + fname_len + 1]; + sprintf(newname, "%s%s", *path, fname); + globbing(op, newname, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile); + } } else - globbing(op, ptr, emptydir, emptyfile); + globbing(op, ptr, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile); if (new_name) free(new_name); entry = entry->next; } + + size_t i; + for (i = 0; i < noblacklist_c; i++) free(noblacklist[i]); } //*********************************************** 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) { // rest of filesystem if (strncmp(ptr, "blacklist ", 10) == 0) ptr += 10; + else if (strncmp(ptr, "noblacklist ", 12) == 0) + ptr += 12; else if (strncmp(ptr, "read-only ", 10) == 0) ptr += 10; 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 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-54-g00ecf