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.c219
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
38static char *check_dir_or_file(const char *name) { 40static 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
68void fs_check_bin_list(void) { 97static 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
129static 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