diff options
author | 2015-11-09 06:49:12 -0500 | |
---|---|---|
committer | 2015-11-09 06:49:12 -0500 | |
commit | b2671e94086fb123698a556e96c2a7ec1ceb6f36 (patch) | |
tree | 0f8d85e6888163daadf4605d720ddabe49cc3f78 | |
parent | move firejail directory form /tmp to /run (diff) | |
download | firejail-b2671e94086fb123698a556e96c2a7ec1ceb6f36.tar.gz firejail-b2671e94086fb123698a556e96c2a7ec1ceb6f36.tar.zst firejail-b2671e94086fb123698a556e96c2a7ec1ceb6f36.zip |
fix for broken --tmpfs=/tmp
-rw-r--r-- | src/firejail/fs.c | 99 |
1 files changed, 47 insertions, 52 deletions
diff --git a/src/firejail/fs.c b/src/firejail/fs.c index ca44a2d5d..56aab8871 100644 --- a/src/firejail/fs.c +++ b/src/firejail/fs.c | |||
@@ -27,6 +27,35 @@ | |||
27 | #include <fcntl.h> | 27 | #include <fcntl.h> |
28 | #include <errno.h> | 28 | #include <errno.h> |
29 | 29 | ||
30 | static void create_empty_dir(void) { | ||
31 | struct stat s; | ||
32 | |||
33 | if (stat(RO_DIR, &s)) { | ||
34 | /* coverity[toctou] */ | ||
35 | int rv = mkdir(RO_DIR, S_IRUSR | S_IXUSR); | ||
36 | if (rv == -1) | ||
37 | errExit("mkdir"); | ||
38 | if (chown(RO_DIR, 0, 0) < 0) | ||
39 | errExit("chown"); | ||
40 | } | ||
41 | } | ||
42 | |||
43 | static void create_empty_file(void) { | ||
44 | struct stat s; | ||
45 | |||
46 | if (stat(RO_FILE, &s)) { | ||
47 | /* coverity[toctou] */ | ||
48 | FILE *fp = fopen(RO_FILE, "w"); | ||
49 | if (!fp) | ||
50 | errExit("fopen"); | ||
51 | fclose(fp); | ||
52 | if (chown(RO_FILE, 0, 0) < 0) | ||
53 | errExit("chown"); | ||
54 | if (chmod(RO_FILE, S_IRUSR) < 0) | ||
55 | errExit("chown"); | ||
56 | } | ||
57 | } | ||
58 | |||
30 | // build /tmp/firejail directory | 59 | // build /tmp/firejail directory |
31 | void fs_build_firejail_dir(void) { | 60 | void fs_build_firejail_dir(void) { |
32 | struct stat s; | 61 | struct stat s; |
@@ -49,6 +78,9 @@ void fs_build_firejail_dir(void) { | |||
49 | exit(1); | 78 | exit(1); |
50 | } | 79 | } |
51 | } | 80 | } |
81 | |||
82 | create_empty_dir(); | ||
83 | create_empty_file(); | ||
52 | } | 84 | } |
53 | 85 | ||
54 | 86 | ||
@@ -126,47 +158,16 @@ typedef enum { | |||
126 | } OPERATION; | 158 | } OPERATION; |
127 | 159 | ||
128 | 160 | ||
129 | static char *create_empty_dir(void) { | ||
130 | struct stat s; | ||
131 | fs_build_firejail_dir(); | ||
132 | |||
133 | if (stat(RO_DIR, &s)) { | ||
134 | /* coverity[toctou] */ | ||
135 | int rv = mkdir(RO_DIR, S_IRUSR | S_IXUSR); | ||
136 | if (rv == -1) | ||
137 | errExit("mkdir"); | ||
138 | if (chown(RO_DIR, 0, 0) < 0) | ||
139 | errExit("chown"); | ||
140 | } | ||
141 | |||
142 | return RO_DIR; | ||
143 | } | ||
144 | 161 | ||
145 | static char *create_empty_file(void) { | ||
146 | struct stat s; | ||
147 | fs_build_firejail_dir(); | ||
148 | |||
149 | if (stat(RO_FILE, &s)) { | ||
150 | /* coverity[toctou] */ | ||
151 | FILE *fp = fopen(RO_FILE, "w"); | ||
152 | if (!fp) | ||
153 | errExit("fopen"); | ||
154 | fclose(fp); | ||
155 | if (chown(RO_FILE, 0, 0) < 0) | ||
156 | errExit("chown"); | ||
157 | if (chmod(RO_FILE, S_IRUSR) < 0) | ||
158 | errExit("chown"); | ||
159 | } | ||
160 | |||
161 | return RO_FILE; | ||
162 | } | ||
163 | 162 | ||
164 | static void disable_file(OPERATION op, const char *filename, const char *emptydir, const char *emptyfile) { | 163 | static void disable_file(OPERATION op, const char *filename) { |
165 | assert(filename); | 164 | assert(filename); |
166 | assert(emptydir); | ||
167 | assert(emptyfile); | ||
168 | assert(op <OPERATION_MAX); | 165 | assert(op <OPERATION_MAX); |
169 | 166 | ||
167 | |||
168 | // rebuild /run/firejail directory in case tmpfs was mounted on top of /run | ||
169 | fs_build_firejail_dir(); | ||
170 | |||
170 | // Resolve all symlinks | 171 | // Resolve all symlinks |
171 | char* fname = realpath(filename, NULL); | 172 | char* fname = realpath(filename, NULL); |
172 | if (fname == NULL) { | 173 | if (fname == NULL) { |
@@ -196,11 +197,11 @@ static void disable_file(OPERATION op, const char *filename, const char *emptydi | |||
196 | if (arg_debug) | 197 | if (arg_debug) |
197 | printf("Disable %s\n", fname); | 198 | printf("Disable %s\n", fname); |
198 | if (S_ISDIR(s.st_mode)) { | 199 | if (S_ISDIR(s.st_mode)) { |
199 | if (mount(emptydir, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 200 | if (mount(RO_DIR, fname, "none", MS_BIND, "mode=400,gid=0") < 0) |
200 | errExit("disable file"); | 201 | errExit("disable file"); |
201 | } | 202 | } |
202 | else { | 203 | else { |
203 | if (mount(emptyfile, fname, "none", MS_BIND, "mode=400,gid=0") < 0) | 204 | if (mount(RO_FILE, fname, "none", MS_BIND, "mode=400,gid=0") < 0) |
204 | errExit("disable file"); | 205 | errExit("disable file"); |
205 | } | 206 | } |
206 | } | 207 | } |
@@ -231,10 +232,8 @@ static void disable_file(OPERATION op, const char *filename, const char *emptydi | |||
231 | } | 232 | } |
232 | 233 | ||
233 | // Treat pattern as a shell glob pattern and blacklist matching files | 234 | // Treat pattern as a shell glob pattern and blacklist matching files |
234 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len, const char *emptydir, const char *emptyfile) { | 235 | static void globbing(OPERATION op, const char *pattern, const char *noblacklist[], size_t noblacklist_len) { |
235 | assert(pattern); | 236 | assert(pattern); |
236 | assert(emptydir); | ||
237 | assert(emptyfile); | ||
238 | 237 | ||
239 | glob_t globbuf; | 238 | glob_t globbuf; |
240 | // Profiles contain blacklists for files that might not exist on a user's machine. | 239 | // Profiles contain blacklists for files that might not exist on a user's machine. |
@@ -269,7 +268,7 @@ static void globbing(OPERATION op, const char *pattern, const char *noblacklist[ | |||
269 | } | 268 | } |
270 | } | 269 | } |
271 | if (okay_to_blacklist) | 270 | if (okay_to_blacklist) |
272 | disable_file(op, path, emptydir, emptyfile); | 271 | disable_file(op, path); |
273 | } | 272 | } |
274 | globfree(&globbuf); | 273 | globfree(&globbuf); |
275 | } | 274 | } |
@@ -283,9 +282,6 @@ void fs_blacklist(void) { | |||
283 | if (!entry) | 282 | if (!entry) |
284 | return; | 283 | return; |
285 | 284 | ||
286 | char *emptydir = create_empty_dir(); | ||
287 | char *emptyfile = create_empty_file(); | ||
288 | |||
289 | // a statically allocated buffer works for all current needs | 285 | // a statically allocated buffer works for all current needs |
290 | // TODO: if dynamic allocation is ever needed, we should probably add | 286 | // TODO: if dynamic allocation is ever needed, we should probably add |
291 | // libraries that make it easy to do without introducing security bugs | 287 | // libraries that make it easy to do without introducing security bugs |
@@ -385,11 +381,11 @@ void fs_blacklist(void) { | |||
385 | for (path = &paths[0]; *path; path++) { | 381 | for (path = &paths[0]; *path; path++) { |
386 | char newname[strlen(*path) + fname_len + 1]; | 382 | char newname[strlen(*path) + fname_len + 1]; |
387 | sprintf(newname, "%s%s", *path, fname); | 383 | sprintf(newname, "%s%s", *path, fname); |
388 | globbing(op, newname, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile); | 384 | globbing(op, newname, (const char**)noblacklist, noblacklist_c); |
389 | } | 385 | } |
390 | } | 386 | } |
391 | else | 387 | else |
392 | globbing(op, ptr, (const char**)noblacklist, noblacklist_c, emptydir, emptyfile); | 388 | globbing(op, ptr, (const char**)noblacklist, noblacklist_c); |
393 | } | 389 | } |
394 | 390 | ||
395 | if (new_name) | 391 | if (new_name) |
@@ -516,10 +512,10 @@ void fs_proc_sys_dev_boot(void) { | |||
516 | fs_rdonly_noexit("/proc/bus"); | 512 | fs_rdonly_noexit("/proc/bus"); |
517 | 513 | ||
518 | // disable /proc/kcore | 514 | // disable /proc/kcore |
519 | disable_file(BLACKLIST_FILE, "/proc/kcore", "not used", "/dev/null"); | 515 | disable_file(BLACKLIST_FILE, "/proc/kcore"); |
520 | 516 | ||
521 | // disable /proc/kallsyms | 517 | // disable /proc/kallsyms |
522 | disable_file(BLACKLIST_FILE, "/proc/kallsyms", "not used", "/dev/null"); | 518 | disable_file(BLACKLIST_FILE, "/proc/kallsyms"); |
523 | 519 | ||
524 | // disable /boot | 520 | // disable /boot |
525 | if (stat("/boot", &s) == 0) { | 521 | if (stat("/boot", &s) == 0) { |
@@ -531,7 +527,7 @@ void fs_proc_sys_dev_boot(void) { | |||
531 | 527 | ||
532 | // disable /dev/port | 528 | // disable /dev/port |
533 | if (stat("/dev/port", &s) == 0) { | 529 | if (stat("/dev/port", &s) == 0) { |
534 | disable_file(BLACKLIST_FILE, "/dev/port", "not used", "/dev/null"); | 530 | disable_file(BLACKLIST_FILE, "/dev/port"); |
535 | } | 531 | } |
536 | } | 532 | } |
537 | 533 | ||
@@ -542,7 +538,6 @@ static void sanitize_home(void) { | |||
542 | if (d == NULL) | 538 | if (d == NULL) |
543 | return; | 539 | return; |
544 | 540 | ||
545 | char *emptydir = create_empty_dir(); | ||
546 | while ((dir = readdir(d))) { | 541 | while ((dir = readdir(d))) { |
547 | if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) | 542 | if(strcmp(dir->d_name, "." ) == 0 || strcmp(dir->d_name, ".." ) == 0) |
548 | continue; | 543 | continue; |
@@ -570,7 +565,7 @@ static void sanitize_home(void) { | |||
570 | // name); | 565 | // name); |
571 | 566 | ||
572 | // disable directory | 567 | // disable directory |
573 | disable_file(BLACKLIST_FILE, name, emptydir, "not used"); | 568 | disable_file(BLACKLIST_FILE, name); |
574 | free(name); | 569 | free(name); |
575 | } | 570 | } |
576 | } | 571 | } |