diff options
Diffstat (limited to 'src/firejail/fs_bin.c')
-rw-r--r-- | src/firejail/fs_bin.c | 219 |
1 files changed, 52 insertions, 167 deletions
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c index c3d24aaac..7c56d524e 100644 --- a/src/firejail/fs_bin.c +++ b/src/firejail/fs_bin.c | |||
@@ -28,6 +28,8 @@ static char *paths[] = { | |||
28 | "/usr/local/bin", | 28 | "/usr/local/bin", |
29 | "/usr/bin", | 29 | "/usr/bin", |
30 | "/bin", | 30 | "/bin", |
31 | "/usr/games", | ||
32 | "/usr/local/games", | ||
31 | "/usr/local/sbin", | 33 | "/usr/local/sbin", |
32 | "/usr/sbin", | 34 | "/usr/sbin", |
33 | "/sbin", | 35 | "/sbin", |
@@ -37,19 +39,45 @@ static char *paths[] = { | |||
37 | // return 1 if found, 0 if not found | 39 | // return 1 if found, 0 if not found |
38 | static char *check_dir_or_file(const char *name) { | 40 | static char *check_dir_or_file(const char *name) { |
39 | assert(name); | 41 | assert(name); |
40 | invalid_filename(name); | ||
41 | 42 | ||
42 | struct stat s; | 43 | struct stat s; |
43 | char *fname = NULL; | 44 | char *fname = NULL; |
44 | 45 | ||
45 | int i = 0; | 46 | int i = 0; |
46 | while (paths[i]) { | 47 | while (paths[i]) { |
48 | // private-bin-no-local can be disabled in /etc/firejail/firejail.config | ||
49 | if (checkcfg(CFG_PRIVATE_BIN_NO_LOCAL) && strstr(paths[i], "local/")) { | ||
50 | i++; | ||
51 | continue; | ||
52 | } | ||
53 | |||
54 | // check file | ||
47 | if (asprintf(&fname, "%s/%s", paths[i], name) == -1) | 55 | if (asprintf(&fname, "%s/%s", paths[i], name) == -1) |
48 | errExit("asprintf"); | 56 | errExit("asprintf"); |
49 | if (arg_debug) | 57 | if (arg_debug) |
50 | printf("Checking %s/%s\n", paths[i], name); | 58 | printf("Checking %s/%s\n", paths[i], name); |
51 | if (stat(fname, &s) == 0 && !S_ISDIR(s.st_mode)) // do not allow directories | 59 | if (stat(fname, &s) == 0 && !S_ISDIR(s.st_mode)) { // do not allow directories |
60 | // check symlink to firejail executable in /usr/local/bin | ||
61 | if (strcmp(paths[i], "/usr/local/bin") == 0 && is_link(fname)) { | ||
62 | /* coverity[toctou] */ | ||
63 | char *actual_path = realpath(fname, NULL); | ||
64 | if (actual_path) { | ||
65 | char *ptr = strstr(actual_path, "/firejail"); | ||
66 | if (ptr && strlen(ptr) == strlen("/firejail")) { | ||
67 | if (arg_debug) | ||
68 | printf("firejail exec symlink detected\n"); | ||
69 | free(actual_path); | ||
70 | free(fname); | ||
71 | fname = NULL; | ||
72 | i++; | ||
73 | continue; | ||
74 | } | ||
75 | free(actual_path); | ||
76 | } | ||
77 | |||
78 | } | ||
52 | break; // file found | 79 | break; // file found |
80 | } | ||
53 | 81 | ||
54 | free(fname); | 82 | free(fname); |
55 | fname = NULL; | 83 | fname = NULL; |
@@ -57,7 +85,8 @@ static char *check_dir_or_file(const char *name) { | |||
57 | } | 85 | } |
58 | 86 | ||
59 | if (!fname) { | 87 | if (!fname) { |
60 | // fprintf(stderr, "Warning: file %s not found\n", name); | 88 | if (arg_debug) |
89 | fprintf(stderr, "Warning: file %s not found\n", name); | ||
61 | return NULL; | 90 | return NULL; |
62 | } | 91 | } |
63 | 92 | ||
@@ -65,69 +94,13 @@ static char *check_dir_or_file(const char *name) { | |||
65 | return paths[i]; | 94 | return paths[i]; |
66 | } | 95 | } |
67 | 96 | ||
68 | void fs_check_bin_list(void) { | 97 | static void duplicate(char *fname) { |
69 | EUID_ASSERT(); | 98 | if (*fname == '~' || *fname == '/' || strstr(fname, "..")) { |
70 | if (strstr(cfg.bin_private_keep, "..")) { | 99 | fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname); |
71 | fprintf(stderr, "Error: invalid private bin list\n"); | ||
72 | exit(1); | 100 | exit(1); |
73 | } | 101 | } |
74 | 102 | invalid_filename(fname); | |
75 | char *dlist = strdup(cfg.bin_private_keep); | ||
76 | if (!dlist) | ||
77 | errExit("strdup"); | ||
78 | |||
79 | // create a new list removing files not found | ||
80 | char *newlist = malloc(strlen(dlist) + 1 + 1); // +',' + '\0' | ||
81 | if (!newlist) | ||
82 | errExit("malloc"); | ||
83 | *newlist = '\0'; | ||
84 | char *newlistptr = newlist; | ||
85 | |||
86 | // check the first file | ||
87 | char *ptr = strtok(dlist, ","); | ||
88 | int notfound = 0; | ||
89 | if (check_dir_or_file(ptr)) { | ||
90 | // file found, copy the name in the new list | ||
91 | strcpy(newlistptr, ptr); | ||
92 | strcat(newlistptr, ","); | ||
93 | newlistptr += strlen(newlistptr); | ||
94 | } | ||
95 | else | ||
96 | notfound = 1; | ||
97 | |||
98 | // check the rest of the list | ||
99 | while ((ptr = strtok(NULL, ",")) != NULL) { | ||
100 | if (check_dir_or_file(ptr)) { | ||
101 | // file found, copy the name in the new list | ||
102 | strcpy(newlistptr, ptr); | ||
103 | strcat(newlistptr, ","); | ||
104 | newlistptr += strlen(newlistptr); | ||
105 | } | ||
106 | else | ||
107 | notfound = 1; | ||
108 | } | ||
109 | |||
110 | if (*newlist == '\0') { | ||
111 | fprintf(stderr, "Warning: no --private-bin list executable found, option disabled\n"); | ||
112 | cfg.bin_private_keep = NULL; | ||
113 | arg_private_bin = 0; | ||
114 | free(newlist); | ||
115 | } | ||
116 | else { | ||
117 | ptr = strrchr(newlist, ','); | ||
118 | assert(ptr); | ||
119 | *ptr = '\0'; | ||
120 | if (notfound) | ||
121 | fprintf(stderr, "Warning: not all executables from --private-bin list were found. The current list is %s\n", newlist); | ||
122 | |||
123 | cfg.bin_private_keep = newlist; | ||
124 | } | ||
125 | |||
126 | free(dlist); | ||
127 | } | ||
128 | 103 | ||
129 | static void duplicate(char *fname) { | ||
130 | char *cmd; | ||
131 | char *path = check_dir_or_file(fname); | 104 | char *path = check_dir_or_file(fname); |
132 | if (!path) | 105 | if (!path) |
133 | return; | 106 | return; |
@@ -137,33 +110,9 @@ static void duplicate(char *fname) { | |||
137 | if (asprintf(&full_path, "%s/%s", path, fname) == -1) | 110 | if (asprintf(&full_path, "%s/%s", path, fname) == -1) |
138 | errExit("asprintf"); | 111 | errExit("asprintf"); |
139 | 112 | ||
140 | char *actual_path = realpath(full_path, NULL); | 113 | // copy the file |
141 | if (actual_path) { | 114 | sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, full_path, RUN_BIN_DIR); |
142 | // if the file is a symbolic link not under path, make a symbolic link | 115 | fs_logger2("clone", fname); |
143 | if (is_link(full_path) && strncmp(actual_path, path, strlen(path))) { | ||
144 | char *lnkname; | ||
145 | if (asprintf(&lnkname, "%s/%s", RUN_BIN_DIR, fname) == -1) | ||
146 | errExit("asprintf"); | ||
147 | int rv = symlink(actual_path, lnkname); | ||
148 | if (rv) | ||
149 | fprintf(stderr, "Warning cannot create symbolic link %s\n", lnkname); | ||
150 | else if (arg_debug) | ||
151 | printf("Created symbolic link %s -> %s\n", lnkname, actual_path); | ||
152 | free(lnkname); | ||
153 | } | ||
154 | else { | ||
155 | // copy the file | ||
156 | if (asprintf(&cmd, "%s -a %s %s/%s", RUN_CP_COMMAND, actual_path, RUN_BIN_DIR, fname) == -1) | ||
157 | errExit("asprintf"); | ||
158 | if (arg_debug) | ||
159 | printf("%s\n", cmd); | ||
160 | if (system(cmd)) | ||
161 | errExit("system cp -a"); | ||
162 | free(cmd); | ||
163 | } | ||
164 | free(actual_path); | ||
165 | } | ||
166 | |||
167 | free(full_path); | 116 | free(full_path); |
168 | } | 117 | } |
169 | 118 | ||
@@ -172,66 +121,26 @@ void fs_private_bin_list(void) { | |||
172 | char *private_list = cfg.bin_private_keep; | 121 | char *private_list = cfg.bin_private_keep; |
173 | assert(private_list); | 122 | assert(private_list); |
174 | 123 | ||
175 | // check bin paths | 124 | // create /run/firejail/mnt/bin directory |
176 | int i = 0; | 125 | mkdir_attr(RUN_BIN_DIR, 0755, 0, 0); |
177 | #if 0 | ||
178 | while (paths[i]) { | ||
179 | struct stat s; | ||
180 | if (stat(paths[i], &s) == -1) { | ||
181 | fprintf(stderr, "Error: cannot find %s directory\n", paths[i]); | ||
182 | exit(1); | ||
183 | } | ||
184 | i++; | ||
185 | } | ||
186 | #endif | ||
187 | |||
188 | // create /tmp/firejail/mnt/bin directory | ||
189 | fs_build_mnt_dir(); | ||
190 | int rv = mkdir(RUN_BIN_DIR, 0755); | ||
191 | if (rv == -1) | ||
192 | errExit("mkdir"); | ||
193 | if (chown(RUN_BIN_DIR, 0, 0) < 0) | ||
194 | errExit("chown"); | ||
195 | if (chmod(RUN_BIN_DIR, 0755) < 0) | ||
196 | errExit("chmod"); | ||
197 | 126 | ||
198 | 127 | if (arg_debug) | |
199 | // copy the list of files in the new etc directory | 128 | printf("Copying files in the new bin directory\n"); |
200 | // using a new child process without root privileges | ||
201 | fs_logger_print(); // save the current log | ||
202 | pid_t child = fork(); | ||
203 | if (child < 0) | ||
204 | errExit("fork"); | ||
205 | if (child == 0) { | ||
206 | if (arg_debug) | ||
207 | printf("Copying files in the new home:\n"); | ||
208 | 129 | ||
209 | // elevate privileges - files in the new /bin directory belong to root | 130 | // copy the list of files in the new home directory |
210 | if (setreuid(0, 0) < 0) | 131 | char *dlist = strdup(private_list); |
211 | errExit("setreuid"); | 132 | if (!dlist) |
212 | if (setregid(0, 0) < 0) | 133 | errExit("strdup"); |
213 | errExit("setregid"); | ||
214 | |||
215 | // copy the list of files in the new home directory | ||
216 | char *dlist = strdup(private_list); | ||
217 | if (!dlist) | ||
218 | errExit("strdup"); | ||
219 | |||
220 | 134 | ||
221 | char *ptr = strtok(dlist, ","); | 135 | char *ptr = strtok(dlist, ","); |
136 | duplicate(ptr); | ||
137 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
222 | duplicate(ptr); | 138 | duplicate(ptr); |
223 | 139 | free(dlist); | |
224 | while ((ptr = strtok(NULL, ",")) != NULL) | ||
225 | duplicate(ptr); | ||
226 | free(dlist); | ||
227 | fs_logger_print(); | 140 | fs_logger_print(); |
228 | exit(0); | ||
229 | } | ||
230 | // wait for the child to finish | ||
231 | waitpid(child, NULL, 0); | ||
232 | 141 | ||
233 | // mount-bind | 142 | // mount-bind |
234 | i = 0; | 143 | int i = 0; |
235 | while (paths[i]) { | 144 | while (paths[i]) { |
236 | struct stat s; | 145 | struct stat s; |
237 | if (stat(paths[i], &s) == 0) { | 146 | if (stat(paths[i], &s) == 0) { |
@@ -244,29 +153,5 @@ void fs_private_bin_list(void) { | |||
244 | } | 153 | } |
245 | i++; | 154 | i++; |
246 | } | 155 | } |
247 | |||
248 | // log cloned files | ||
249 | char *dlist = strdup(private_list); | ||
250 | if (!dlist) | ||
251 | errExit("strdup"); | ||
252 | |||
253 | |||
254 | char *ptr = strtok(dlist, ","); | ||
255 | while (ptr) { | ||
256 | i = 0; | ||
257 | while (paths[i]) { | ||
258 | struct stat s; | ||
259 | if (stat(paths[i], &s) == 0) { | ||
260 | char *fname; | ||
261 | if (asprintf(&fname, "%s/%s", paths[i], ptr) == -1) | ||
262 | errExit("asprintf"); | ||
263 | fs_logger2("clone", fname); | ||
264 | free(fname); | ||
265 | } | ||
266 | i++; | ||
267 | } | ||
268 | ptr = strtok(NULL, ","); | ||
269 | } | ||
270 | free(dlist); | ||
271 | } | 156 | } |
272 | 157 | ||