diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/cmdline.c | 151 | ||||
-rw-r--r-- | src/firejail/fs_mkdir.c | 39 | ||||
-rw-r--r-- | src/firejail/join.c | 24 | ||||
-rw-r--r-- | src/firejail/main.c | 104 | ||||
-rw-r--r-- | src/libtrace/libtrace.c | 29 | ||||
-rw-r--r-- | src/libtracelog/libtracelog.c | 4 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 8 |
7 files changed, 219 insertions, 140 deletions
diff --git a/src/firejail/cmdline.c b/src/firejail/cmdline.c new file mode 100644 index 000000000..517124d9e --- /dev/null +++ b/src/firejail/cmdline.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2016 Firejail Authors | ||
3 | * | ||
4 | * This file is part of firejail project | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "firejail.h" | ||
22 | #include <string.h> | ||
23 | #include <stdbool.h> | ||
24 | #include <stdio.h> | ||
25 | #include <linux/limits.h> | ||
26 | #include <assert.h> | ||
27 | #include <errno.h> | ||
28 | |||
29 | int cmdline_length(int argc, char **argv, int index) { | ||
30 | int i,j; | ||
31 | int len = 0; | ||
32 | int argcnt = argc - index; | ||
33 | bool in_quotes = false; | ||
34 | |||
35 | for (i = 0; i < argcnt; i++) { | ||
36 | in_quotes = false; | ||
37 | for (j = 0; j < strlen(argv[i + index]); j++) { | ||
38 | if (argv[i + index][j] == '\'') { | ||
39 | if (in_quotes) | ||
40 | len++; | ||
41 | if (j > 0 && argv[i + index][j-1] == '\'') | ||
42 | len++; | ||
43 | else | ||
44 | len += 3; | ||
45 | in_quotes = false; | ||
46 | } else { | ||
47 | if (!in_quotes) | ||
48 | len++; | ||
49 | len++; | ||
50 | in_quotes = true; | ||
51 | } | ||
52 | } | ||
53 | if (in_quotes) { | ||
54 | len++; | ||
55 | } | ||
56 | if (strlen(argv[i + index]) == 0) { | ||
57 | len += 2; | ||
58 | } | ||
59 | len++; | ||
60 | } | ||
61 | |||
62 | return len; | ||
63 | } | ||
64 | |||
65 | void quote_cmdline(char *command_line, char *window_title, int len, int argc, char **argv, int index) { | ||
66 | int i,j; | ||
67 | int argcnt = argc - index; | ||
68 | bool in_quotes = false; | ||
69 | char *ptr1 = command_line; | ||
70 | char *ptr2 = window_title; | ||
71 | |||
72 | for (i = 0; i < argcnt; i++) { | ||
73 | |||
74 | // enclose args by single quotes, | ||
75 | // and since single quote can't be represented in single quoted text | ||
76 | // each occurence of it should be enclosed by double quotes | ||
77 | in_quotes = false; | ||
78 | for (j = 0; j < strlen(argv[i + index]); j++) { | ||
79 | // single quote | ||
80 | if (argv[i + index][j] == '\'') { | ||
81 | if (in_quotes) { | ||
82 | // close quotes | ||
83 | ptr1[0] = '\''; | ||
84 | ptr1++; | ||
85 | } | ||
86 | // previous char was single quote too | ||
87 | if (j > 0 && argv[i + index][j-1] == '\'') { | ||
88 | ptr1--; | ||
89 | sprintf(ptr1, "\'\""); | ||
90 | } | ||
91 | // this first in series | ||
92 | else | ||
93 | { | ||
94 | sprintf(ptr1, "\"\'\""); | ||
95 | } | ||
96 | ptr1 += strlen(ptr1); | ||
97 | in_quotes = false; | ||
98 | } | ||
99 | // anything other | ||
100 | else | ||
101 | { | ||
102 | if (!in_quotes) { | ||
103 | // open quotes | ||
104 | ptr1[0] = '\''; | ||
105 | ptr1++; | ||
106 | } | ||
107 | ptr1[0] = argv[i + index][j]; | ||
108 | ptr1++; | ||
109 | in_quotes = true; | ||
110 | } | ||
111 | } | ||
112 | // close quotes | ||
113 | if (in_quotes) { | ||
114 | ptr1[0] = '\''; | ||
115 | ptr1++; | ||
116 | } | ||
117 | // handle empty argument case | ||
118 | if (strlen(argv[i + index]) == 0) { | ||
119 | sprintf(ptr1, "\'\'"); | ||
120 | ptr1 += strlen(ptr1); | ||
121 | } | ||
122 | // add space | ||
123 | sprintf(ptr1, " "); | ||
124 | ptr1 += strlen(ptr1); | ||
125 | |||
126 | sprintf(ptr2, "%s ", argv[i + index]); | ||
127 | ptr2 += strlen(ptr2); | ||
128 | } | ||
129 | |||
130 | assert(len == strlen(command_line)); | ||
131 | } | ||
132 | |||
133 | void build_cmdline(char **command_line, char **window_title, int argc, char **argv, int index) { | ||
134 | int len = cmdline_length(argc, argv, index); | ||
135 | if (len > ARG_MAX) { | ||
136 | errno = E2BIG; | ||
137 | errExit("cmdline_length"); | ||
138 | } | ||
139 | |||
140 | *command_line = malloc(len + 1); | ||
141 | if (!*command_line) | ||
142 | errExit("malloc"); | ||
143 | *window_title = malloc(len + 1); | ||
144 | if (!*window_title) | ||
145 | errExit("malloc"); | ||
146 | |||
147 | quote_cmdline(*command_line, *window_title, len, argc, argv, index); | ||
148 | |||
149 | assert(*command_line); | ||
150 | assert(*window_title); | ||
151 | } | ||
diff --git a/src/firejail/fs_mkdir.c b/src/firejail/fs_mkdir.c index 50bcc613b..5bc2df2cc 100644 --- a/src/firejail/fs_mkdir.c +++ b/src/firejail/fs_mkdir.c | |||
@@ -22,8 +22,38 @@ | |||
22 | #include <sys/stat.h> | 22 | #include <sys/stat.h> |
23 | #include <unistd.h> | 23 | #include <unistd.h> |
24 | #include <grp.h> | 24 | #include <grp.h> |
25 | #include <sys/wait.h> | 25 | #include <sys/wait.h> |
26 | 26 | #include <string.h> | |
27 | |||
28 | static void mkdir_recursive(char *path) { | ||
29 | char *subdir = NULL; | ||
30 | struct stat s; | ||
31 | |||
32 | if (chdir("/")) { | ||
33 | fprintf(stderr, "Error: can't chdir to /"); | ||
34 | return; | ||
35 | } | ||
36 | |||
37 | subdir = strtok(path, "/"); | ||
38 | while(subdir) { | ||
39 | if (stat(subdir, &s) == -1) { | ||
40 | if (mkdir(subdir, 0700) == -1) { | ||
41 | fprintf(stderr, "Warning: cannot create %s directory\n", subdir); | ||
42 | return; | ||
43 | } | ||
44 | } else if (!S_ISDIR(s.st_mode)) { | ||
45 | fprintf(stderr, "Warning: '%s' exists, but is no directory\n", subdir); | ||
46 | return; | ||
47 | } | ||
48 | if (chdir(subdir)) { | ||
49 | fprintf(stderr, "Error: can't chdir to %s", subdir); | ||
50 | return; | ||
51 | } | ||
52 | |||
53 | subdir = strtok(NULL, "/"); | ||
54 | } | ||
55 | } | ||
56 | |||
27 | void fs_mkdir(const char *name) { | 57 | void fs_mkdir(const char *name) { |
28 | EUID_ASSERT(); | 58 | EUID_ASSERT(); |
29 | 59 | ||
@@ -50,8 +80,7 @@ void fs_mkdir(const char *name) { | |||
50 | drop_privs(0); | 80 | drop_privs(0); |
51 | 81 | ||
52 | // create directory | 82 | // create directory |
53 | if (mkdir(expanded, 0700) == -1) | 83 | mkdir_recursive(expanded); |
54 | fprintf(stderr, "Warning: cannot create %s directory\n", expanded); | ||
55 | exit(0); | 84 | exit(0); |
56 | } | 85 | } |
57 | // wait for the child to finish | 86 | // wait for the child to finish |
@@ -101,4 +130,4 @@ void fs_mkfile(const char *name) { | |||
101 | 130 | ||
102 | doexit: | 131 | doexit: |
103 | free(expanded); | 132 | free(expanded); |
104 | } \ No newline at end of file | 133 | } |
diff --git a/src/firejail/join.c b/src/firejail/join.c index c14108986..0b5b6a34a 100644 --- a/src/firejail/join.c +++ b/src/firejail/join.c | |||
@@ -49,29 +49,9 @@ static void extract_command(int argc, char **argv, int index) { | |||
49 | exit(1); | 49 | exit(1); |
50 | } | 50 | } |
51 | 51 | ||
52 | |||
53 | int len = 0; | ||
54 | int i; | ||
55 | // calculate command length | ||
56 | for (i = index; i < argc; i++) { | ||
57 | len += strlen(argv[i]) + 3; | ||
58 | } | ||
59 | assert(len > 0); | ||
60 | |||
61 | // build command | 52 | // build command |
62 | cfg.command_line = malloc(len + 1); | 53 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, index); |
63 | *cfg.command_line = '\0'; | 54 | |
64 | for (i = index; i < argc; i++) { | ||
65 | if (strchr(argv[i], '&')) { | ||
66 | strcat(cfg.command_line, "\'"); | ||
67 | strcat(cfg.command_line, argv[i]); | ||
68 | strcat(cfg.command_line, "\' "); | ||
69 | } | ||
70 | else { | ||
71 | strcat(cfg.command_line, argv[i]); | ||
72 | strcat(cfg.command_line, " "); | ||
73 | } | ||
74 | } | ||
75 | if (arg_debug) | 55 | if (arg_debug) |
76 | printf("Extracted command #%s#\n", cfg.command_line); | 56 | printf("Extracted command #%s#\n", cfg.command_line); |
77 | } | 57 | } |
diff --git a/src/firejail/main.c b/src/firejail/main.c index cbc3d57cf..e86d78ff1 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -2004,109 +2004,7 @@ int main(int argc, char **argv) { | |||
2004 | cfg.window_title = "appimage"; | 2004 | cfg.window_title = "appimage"; |
2005 | } | 2005 | } |
2006 | else { | 2006 | else { |
2007 | // calculate the length of the command | 2007 | build_cmdline(&cfg.command_line, &cfg.window_title, argc, argv, prog_index); |
2008 | int i; | ||
2009 | int len = 0; | ||
2010 | int argcnt = argc - prog_index; | ||
2011 | int j; | ||
2012 | bool in_quotes = false; | ||
2013 | |||
2014 | for (i = 0; i < argcnt; i++) { | ||
2015 | in_quotes = false; | ||
2016 | for (j = 0; j < strlen(argv[i + prog_index]); j++) { | ||
2017 | if (argv[i + prog_index][j] == '\'') { | ||
2018 | if (in_quotes) | ||
2019 | len++; | ||
2020 | if (j > 0 && argv[i + prog_index][j-1] == '\'') | ||
2021 | len++; | ||
2022 | else | ||
2023 | len += 3; | ||
2024 | in_quotes = false; | ||
2025 | } else { | ||
2026 | if (!in_quotes) | ||
2027 | len++; | ||
2028 | len++; | ||
2029 | in_quotes = true; | ||
2030 | } | ||
2031 | } | ||
2032 | if (in_quotes) { | ||
2033 | len++; | ||
2034 | } | ||
2035 | if (strlen(argv[i + prog_index]) == 0) { | ||
2036 | len += 2; | ||
2037 | } | ||
2038 | len++; | ||
2039 | } | ||
2040 | |||
2041 | // build the string | ||
2042 | cfg.command_line = malloc(len + 1); // + '\0' | ||
2043 | if (!cfg.command_line) | ||
2044 | errExit("malloc"); | ||
2045 | cfg.window_title = malloc(len + 1); // + '\0' | ||
2046 | if (!cfg.window_title) | ||
2047 | errExit("malloc"); | ||
2048 | |||
2049 | char *ptr1 = cfg.command_line; | ||
2050 | char *ptr2 = cfg.window_title; | ||
2051 | for (i = 0; i < argcnt; i++) { | ||
2052 | |||
2053 | // enclose args by single quotes, | ||
2054 | // and since single quote can't be represented in single quoted text | ||
2055 | // each occurence of it should be enclosed by double quotes | ||
2056 | in_quotes = false; | ||
2057 | for (j = 0; j < strlen(argv[i + prog_index]); j++) { | ||
2058 | // single quote | ||
2059 | if (argv[i + prog_index][j] == '\'') { | ||
2060 | if (in_quotes) { | ||
2061 | // close quotes | ||
2062 | ptr1[0] = '\''; | ||
2063 | ptr1++; | ||
2064 | } | ||
2065 | // previous char was single quote too | ||
2066 | if (j > 0 && argv[i + prog_index][j-1] == '\'') { | ||
2067 | ptr1--; | ||
2068 | sprintf(ptr1, "\'\""); | ||
2069 | } | ||
2070 | // this first in series | ||
2071 | else | ||
2072 | { | ||
2073 | sprintf(ptr1, "\"\'\""); | ||
2074 | } | ||
2075 | ptr1 += strlen(ptr1); | ||
2076 | in_quotes = false; | ||
2077 | } | ||
2078 | // anything other | ||
2079 | else | ||
2080 | { | ||
2081 | if (!in_quotes) { | ||
2082 | // open quotes | ||
2083 | ptr1[0] = '\''; | ||
2084 | ptr1++; | ||
2085 | } | ||
2086 | ptr1[0] = argv[i + prog_index][j]; | ||
2087 | ptr1++; | ||
2088 | in_quotes = true; | ||
2089 | } | ||
2090 | } | ||
2091 | // close quotes | ||
2092 | if (in_quotes) { | ||
2093 | ptr1[0] = '\''; | ||
2094 | ptr1++; | ||
2095 | } | ||
2096 | // handle empty argument case | ||
2097 | if (strlen(argv[i + prog_index]) == 0) { | ||
2098 | sprintf(ptr1, "\'\'"); | ||
2099 | ptr1 += strlen(ptr1); | ||
2100 | } | ||
2101 | // add space | ||
2102 | sprintf(ptr1, " "); | ||
2103 | ptr1 += strlen(ptr1); | ||
2104 | |||
2105 | sprintf(ptr2, "%s ", argv[i + prog_index]); | ||
2106 | ptr2 += strlen(ptr2); | ||
2107 | } | ||
2108 | |||
2109 | assert(len == strlen(cfg.command_line)); | ||
2110 | } | 2008 | } |
2111 | 2009 | ||
2112 | assert(cfg.command_name); | 2010 | assert(cfg.command_name); |
diff --git a/src/libtrace/libtrace.c b/src/libtrace/libtrace.c index a3d1571f7..dde3df2ea 100644 --- a/src/libtrace/libtrace.c +++ b/src/libtrace/libtrace.c | |||
@@ -423,11 +423,36 @@ int stat(const char *pathname, struct stat *buf) { | |||
423 | typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); | 423 | typedef int (*orig_stat64_t)(const char *pathname, struct stat64 *buf); |
424 | static orig_stat64_t orig_stat64 = NULL; | 424 | static orig_stat64_t orig_stat64 = NULL; |
425 | int stat64(const char *pathname, struct stat64 *buf) { | 425 | int stat64(const char *pathname, struct stat64 *buf) { |
426 | if (!orig_stat) | 426 | if (!orig_stat64) |
427 | orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); | 427 | orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); |
428 | 428 | ||
429 | int rv = orig_stat64(pathname, buf); | 429 | int rv = orig_stat64(pathname, buf); |
430 | printf("%u:%s:stat %s:%d\n", pid(), name(), pathname, rv); | 430 | printf("%u:%s:stat64 %s:%d\n", pid(), name(), pathname, rv); |
431 | return rv; | ||
432 | } | ||
433 | #endif /* __GLIBC__ */ | ||
434 | |||
435 | // lstat | ||
436 | typedef int (*orig_lstat_t)(const char *pathname, struct stat *buf); | ||
437 | static orig_lstat_t orig_lstat = NULL; | ||
438 | int lstat(const char *pathname, struct stat *buf) { | ||
439 | if (!orig_lstat) | ||
440 | orig_lstat = (orig_lstat_t)dlsym(RTLD_NEXT, "lstat"); | ||
441 | |||
442 | int rv = orig_lstat(pathname, buf); | ||
443 | printf("%u:%s:lstat %s:%d\n", pid(), name(), pathname, rv); | ||
444 | return rv; | ||
445 | } | ||
446 | |||
447 | #ifdef __GLIBC__ | ||
448 | typedef int (*orig_lstat64_t)(const char *pathname, struct stat64 *buf); | ||
449 | static orig_lstat64_t orig_lstat64 = NULL; | ||
450 | int lstat64(const char *pathname, struct stat64 *buf) { | ||
451 | if (!orig_lstat64) | ||
452 | orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64"); | ||
453 | |||
454 | int rv = orig_lstat64(pathname, buf); | ||
455 | printf("%u:%s:lstat64 %s:%d\n", pid(), name(), pathname, rv); | ||
431 | return rv; | 456 | return rv; |
432 | } | 457 | } |
433 | #endif /* __GLIBC__ */ | 458 | #endif /* __GLIBC__ */ |
diff --git a/src/libtracelog/libtracelog.c b/src/libtracelog/libtracelog.c index 3e65587c4..dedba5513 100644 --- a/src/libtracelog/libtracelog.c +++ b/src/libtracelog/libtracelog.c | |||
@@ -562,7 +562,7 @@ int stat64(const char *pathname, struct stat64 *buf) { | |||
562 | #ifdef DEBUG | 562 | #ifdef DEBUG |
563 | printf("%s %s\n", __FUNCTION__, pathname); | 563 | printf("%s %s\n", __FUNCTION__, pathname); |
564 | #endif | 564 | #endif |
565 | if (!orig_stat) | 565 | if (!orig_stat64) |
566 | orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); | 566 | orig_stat64 = (orig_stat64_t)dlsym(RTLD_NEXT, "stat64"); |
567 | if (!blacklist_loaded) | 567 | if (!blacklist_loaded) |
568 | load_blacklist(); | 568 | load_blacklist(); |
@@ -598,7 +598,7 @@ int lstat64(const char *pathname, struct stat64 *buf) { | |||
598 | #ifdef DEBUG | 598 | #ifdef DEBUG |
599 | printf("%s %s\n", __FUNCTION__, pathname); | 599 | printf("%s %s\n", __FUNCTION__, pathname); |
600 | #endif | 600 | #endif |
601 | if (!orig_lstat) | 601 | if (!orig_lstat64) |
602 | orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64"); | 602 | orig_lstat64 = (orig_lstat64_t)dlsym(RTLD_NEXT, "lstat64"); |
603 | if (!blacklist_loaded) | 603 | if (!blacklist_loaded) |
604 | load_blacklist(); | 604 | load_blacklist(); |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 504842a9e..7e33a6b45 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -136,7 +136,7 @@ The directory is created if it doesn't already exist. | |||
136 | .br | 136 | .br |
137 | Use this command for whitelisted directories you need to preserve | 137 | Use this command for whitelisted directories you need to preserve |
138 | when the sandbox is closed. Without it, the application will create the directory, and the directory | 138 | when the sandbox is closed. Without it, the application will create the directory, and the directory |
139 | will be deleted when the sandbox is closed. Subdirectories also need to be created using mkdir. Example from | 139 | will be deleted when the sandbox is closed. Subdirectories are recursively created. Example from |
140 | firefox profile: | 140 | firefox profile: |
141 | .br | 141 | .br |
142 | 142 | ||
@@ -145,17 +145,13 @@ mkdir ~/.mozilla | |||
145 | .br | 145 | .br |
146 | whitelist ~/.mozilla | 146 | whitelist ~/.mozilla |
147 | .br | 147 | .br |
148 | mkdir ~/.cache | ||
149 | .br | ||
150 | mkdir ~/.cache/mozilla | ||
151 | .br | ||
152 | mkdir ~/.cache/mozilla/firefox | 148 | mkdir ~/.cache/mozilla/firefox |
153 | .br | 149 | .br |
154 | whitelist ~/.cache/mozilla/firefox | 150 | whitelist ~/.cache/mozilla/firefox |
155 | .TP | 151 | .TP |
156 | \fBmkfile file | 152 | \fBmkfile file |
157 | Similar to mkdir, this command creates a file in user home before the sandbox is started. | 153 | Similar to mkdir, this command creates a file in user home before the sandbox is started. |
158 | The file is created if it doesn't already exist. | 154 | The file is created if it doesn't already exist, but it's target directory has to exist. |
159 | .TP | 155 | .TP |
160 | \fBnoexec file_or_directory | 156 | \fBnoexec file_or_directory |
161 | Remount the file or the directory noexec, nodev and nosuid. | 157 | Remount the file or the directory noexec, nodev and nosuid. |