aboutsummaryrefslogtreecommitdiffstats
path: root/src/firejail/fs_bin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/firejail/fs_bin.c')
-rw-r--r--src/firejail/fs_bin.c309
1 files changed, 0 insertions, 309 deletions
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
deleted file mode 100644
index 5625ed356..000000000
--- a/src/firejail/fs_bin.c
+++ /dev/null
@@ -1,309 +0,0 @@
1/*
2 * Copyright (C) 2014-2018 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#include "firejail.h"
21#include <sys/mount.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <unistd.h>
26#include <glob.h>
27
28static int prog_cnt = 0;
29
30static char *paths[] = {
31 "/usr/local/bin",
32 "/usr/bin",
33 "/bin",
34 "/usr/games",
35 "/usr/local/games",
36 "/usr/local/sbin",
37 "/usr/sbin",
38 "/sbin",
39 NULL
40};
41
42// return 1 if found, 0 if not found
43static char *check_dir_or_file(const char *name) {
44 assert(name);
45 struct stat s;
46 char *fname = NULL;
47
48 int i = 0;
49 while (paths[i]) {
50 // private-bin-no-local can be disabled in /etc/firejail/firejail.config
51 if (checkcfg(CFG_PRIVATE_BIN_NO_LOCAL) && strstr(paths[i], "local/")) {
52 i++;
53 continue;
54 }
55
56 // check file
57 if (asprintf(&fname, "%s/%s", paths[i], name) == -1)
58 errExit("asprintf");
59 if (arg_debug)
60 printf("Checking %s/%s\n", paths[i], name);
61 if (stat(fname, &s) == 0 && !S_ISDIR(s.st_mode)) { // do not allow directories
62 // check symlink to firejail executable in /usr/local/bin
63 if (strcmp(paths[i], "/usr/local/bin") == 0 && is_link(fname)) {
64 /* coverity[toctou] */
65 char *actual_path = realpath(fname, NULL);
66 if (actual_path) {
67 char *ptr = strstr(actual_path, "/firejail");
68 if (ptr && strlen(ptr) == strlen("/firejail")) {
69 if (arg_debug)
70 printf("firejail exec symlink detected\n");
71 free(actual_path);
72 free(fname);
73 fname = NULL;
74 i++;
75 continue;
76 }
77 free(actual_path);
78 }
79
80 }
81 break; // file found
82 }
83
84 free(fname);
85 fname = NULL;
86 i++;
87 }
88
89 if (!fname) {
90 if (arg_debug)
91 fwarning("file %s not found\n", name);
92 return NULL;
93 }
94
95 free(fname);
96 return paths[i];
97}
98
99// return 1 if the file is in paths[]
100static int valid_full_path_file(const char *name) {
101 assert(name);
102
103 if (*name != '/')
104 return 0;
105 if (strstr(name, ".."))
106 return 0;
107
108 // do we have a file?
109 struct stat s;
110 if (stat(name, &s) == -1)
111 return 0;
112 // directories not allowed
113 if (S_ISDIR(s.st_mode))
114 return 0;
115 // checking access
116 if (access(name, X_OK) == -1)
117 return 0;
118
119 // check standard paths
120 int i = 0;
121 while (paths[i]) {
122 // private-bin-no-local can be disabled in /etc/firejail/firejail.config
123 if (checkcfg(CFG_PRIVATE_BIN_NO_LOCAL) && strstr(paths[i], "local/")) {
124 i++;
125 continue;
126 }
127
128 int len = strlen(paths[i]);
129 if (strncmp(name, paths[i], len) == 0 && name[len] == '/' && name[len + 1] != '\0')
130 return 1;
131 i++;
132 }
133 if (arg_debug)
134 printf("file %s not found\n", name);
135 return 0;
136}
137
138static void report_duplication(const char *fname) {
139 // report the file on all bin paths
140 int i = 0;
141 while (paths[i]) {
142 char *p;
143 if (asprintf(&p, "%s/%s", paths[i], fname) == -1)
144 errExit("asprintf");
145 fs_logger2("clone", p);
146 free(p);
147 i++;
148 }
149}
150
151static void duplicate(char *fname) {
152 assert(fname);
153
154 if (*fname == '~' || strstr(fname, "..")) {
155 fprintf(stderr, "Error: \"%s\" is an invalid filename\n", fname);
156 exit(1);
157 }
158 invalid_filename(fname, 0); // no globbing
159
160 char *full_path;
161 if (*fname == '/') {
162 // If the absolute filename is indicated, directly use it. This
163 // is required for the following cases:
164 // - if user's $PATH order is not the same as the above
165 // paths[] variable order
166 if (!valid_full_path_file(fname)) {
167 fwarning("invalid private-bin path %s\n", fname);
168 return;
169 }
170
171 full_path = strdup(fname);
172 if (!full_path)
173 errExit("strdup");
174 }
175 else {
176 // Find the standard directory (by looping through paths[])
177 // where the filename fname is located
178 char *path = check_dir_or_file(fname);
179 if (!path)
180 return;
181 if (asprintf(&full_path, "%s/%s", path, fname) == -1)
182 errExit("asprintf");
183 }
184
185 // add to private-lib list
186 if (cfg.bin_private_lib == NULL) {
187 if (asprintf(&cfg.bin_private_lib, "%s,%s",fname, full_path) == -1)
188 errExit("asprinf");
189 }
190 else {
191 char *tmp;
192 if (asprintf(&tmp, "%s,%s,%s", cfg.bin_private_lib, fname, full_path) == -1)
193 errExit("asprinf");
194 free(cfg.bin_private_lib);
195 cfg.bin_private_lib = tmp;
196 }
197
198 // if full_path is symlink, and the link is in our path, copy both the file and the symlink
199 if (is_link(full_path)) {
200 char *actual_path = realpath(full_path, NULL);
201 if (actual_path) {
202 if (valid_full_path_file(actual_path)) {
203 // solving problems such as /bin/sh -> /bin/dash
204 // copy the real file pointed by symlink
205 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, actual_path, RUN_BIN_DIR);
206 prog_cnt++;
207 char *f = strrchr(actual_path, '/');
208 if (f && *(++f) !='\0')
209 report_duplication(f);
210 }
211 free(actual_path);
212 }
213 }
214
215 // copy a file or a symlink
216 sbox_run(SBOX_ROOT| SBOX_SECCOMP, 3, PATH_FCOPY, full_path, RUN_BIN_DIR);
217 prog_cnt++;
218 free(full_path);
219 report_duplication(fname);
220}
221
222static void globbing(char *fname) {
223 assert(fname);
224
225 // go directly to duplicate() if no globbing char is present - see man 7 glob
226 if (strrchr(fname, '*') == NULL &&
227 strrchr(fname, '[') == NULL &&
228 strrchr(fname, '?') == NULL)
229 return duplicate(fname);
230
231 // loop through paths[]
232 int i = 0;
233 while (paths[i]) {
234 // private-bin-no-local can be disabled in /etc/firejail/firejail.config
235 if (checkcfg(CFG_PRIVATE_BIN_NO_LOCAL) && strstr(paths[i], "local/")) {
236 i++;
237 continue;
238 }
239
240 // check file
241 char *pattern;
242 if (asprintf(&pattern, "%s/%s", paths[i], fname) == -1)
243 errExit("asprintf");
244
245 // globbing
246 glob_t globbuf;
247 int globerr = glob(pattern, GLOB_NOCHECK | GLOB_NOSORT | GLOB_PERIOD, NULL, &globbuf);
248 if (globerr) {
249 fprintf(stderr, "Error: failed to glob private-bin pattern %s\n", pattern);
250 exit(1);
251 }
252
253 size_t j;
254 for (j = 0; j < globbuf.gl_pathc; j++) {
255 assert(globbuf.gl_pathv[j]);
256 // testing for GLOB_NOCHECK - no pattern matched returns the original pattern
257 if (strcmp(globbuf.gl_pathv[j], pattern) == 0)
258 continue;
259
260 duplicate(globbuf.gl_pathv[j]);
261 }
262
263 globfree(&globbuf);
264 free(pattern);
265 i++;
266 }
267}
268
269void fs_private_bin_list(void) {
270 char *private_list = cfg.bin_private_keep;
271 assert(private_list);
272
273 // start timetrace
274 timetrace_start();
275
276 // create /run/firejail/mnt/bin directory
277 mkdir_attr(RUN_BIN_DIR, 0755, 0, 0);
278
279 if (arg_debug)
280 printf("Copying files in the new bin directory\n");
281
282 // copy the list of files in the new home directory
283 char *dlist = strdup(private_list);
284 if (!dlist)
285 errExit("strdup");
286
287 char *ptr = strtok(dlist, ",");
288 globbing(ptr);
289 while ((ptr = strtok(NULL, ",")) != NULL)
290 globbing(ptr);
291 free(dlist);
292 fs_logger_print();
293
294 // mount-bind
295 int i = 0;
296 while (paths[i]) {
297 struct stat s;
298 if (stat(paths[i], &s) == 0) {
299 if (arg_debug)
300 printf("Mount-bind %s on top of %s\n", RUN_BIN_DIR, paths[i]);
301 if (mount(RUN_BIN_DIR, paths[i], NULL, MS_BIND|MS_REC, NULL) < 0)
302 errExit("mount bind");
303 fs_logger2("tmpfs", paths[i]);
304 fs_logger2("mount", paths[i]);
305 }
306 i++;
307 }
308 fmessage("%d %s installed in %0.2f ms\n", prog_cnt, (prog_cnt == 1)? "program": "programs", timetrace_end());
309}