aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2021-07-14 11:28:58 -0400
committerLibravatar netblue30 <netblue30@protonmail.com>2021-07-14 11:28:58 -0400
commitba9c9699e79f2a2e3298b01f65799c96d2b0cd27 (patch)
treedcbf29860a6d41b71ffb20ec0f995162b936467d /src
parentdisable-common.inc update (diff)
downloadfirejail-ba9c9699e79f2a2e3298b01f65799c96d2b0cd27.tar.gz
firejail-ba9c9699e79f2a2e3298b01f65799c96d2b0cd27.tar.zst
firejail-ba9c9699e79f2a2e3298b01f65799c96d2b0cd27.zip
Removing blacklisted files from top level /etc directory if the filse were blacklisted
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h4
-rw-r--r--src/firejail/fs.c13
-rw-r--r--src/firejail/fs_etc.c126
-rw-r--r--src/firejail/fs_hostname.c103
-rw-r--r--src/firejail/sandbox.c2
5 files changed, 143 insertions, 105 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 6c9d70c0b..545573c08 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -156,6 +156,8 @@ typedef struct config_t {
156 156
157 // filesystem 157 // filesystem
158 ProfileEntry *profile; 158 ProfileEntry *profile;
159 ProfileEntry *profile_rebuild_etc; // blacklist files in /etc directory used by fs_rebuild_etc()
160
159#define MAX_PROFILE_IGNORE 32 161#define MAX_PROFILE_IGNORE 32
160 char *profile_ignore[MAX_PROFILE_IGNORE]; 162 char *profile_ignore[MAX_PROFILE_IGNORE];
161 char *chrootdir; // chroot directory 163 char *chrootdir; // chroot directory
@@ -625,7 +627,6 @@ void fs_trace(void);
625 627
626// fs_hostname.c 628// fs_hostname.c
627void fs_hostname(const char *hostname); 629void fs_hostname(const char *hostname);
628void fs_resolvconf(void);
629char *fs_check_hosts_file(const char *fname); 630char *fs_check_hosts_file(const char *fname);
630void fs_store_hosts_file(void); 631void fs_store_hosts_file(void);
631void fs_mount_hosts_file(void); 632void fs_mount_hosts_file(void);
@@ -668,6 +669,7 @@ void fs_machineid(void);
668void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list); 669void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list);
669void fs_private_dir_mount(const char *private_dir, const char *private_run_dir); 670void fs_private_dir_mount(const char *private_dir, const char *private_run_dir);
670void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list); 671void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list);
672void fs_rebuild_etc(void);
671 673
672// no_sandbox.c 674// no_sandbox.c
673int check_namespace_virt(void); 675int check_namespace_virt(void);
diff --git a/src/firejail/fs.c b/src/firejail/fs.c
index 0e26eb505..dd170ad19 100644
--- a/src/firejail/fs.c
+++ b/src/firejail/fs.c
@@ -162,6 +162,19 @@ static void disable_file(OPERATION op, const char *filename) {
162 fs_logger2("blacklist", fname); 162 fs_logger2("blacklist", fname);
163 else 163 else
164 fs_logger2("blacklist-nolog", fname); 164 fs_logger2("blacklist-nolog", fname);
165
166 // files in /etc will be reprocessed during /etc rebuild
167 if (strncmp(fname, "/etc/", 5) == 0) {
168 ProfileEntry *prf = malloc(sizeof(ProfileEntry));
169 if (!prf)
170 errExit("malloc");
171 memset(prf, 0, sizeof(ProfileEntry));
172 prf->data = strdup(fname);
173 if (!prf->data)
174 errExit("strdup");
175 prf->next = cfg.profile_rebuild_etc;
176 cfg.profile_rebuild_etc = prf;
177 }
165 } 178 }
166 } 179 }
167 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) { 180 else if (op == MOUNT_READONLY || op == MOUNT_RDWR || op == MOUNT_NOEXEC) {
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
index b0e1e1bf1..76054b485 100644
--- a/src/firejail/fs_etc.c
+++ b/src/firejail/fs_etc.c
@@ -24,6 +24,7 @@
24#include <sys/types.h> 24#include <sys/types.h>
25#include <time.h> 25#include <time.h>
26#include <unistd.h> 26#include <unistd.h>
27#include <dirent.h>
27 28
28// spoof /etc/machine_id 29// spoof /etc/machine_id
29void fs_machineid(void) { 30void fs_machineid(void) {
@@ -250,3 +251,128 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c
250 fs_private_dir_mount(private_dir, private_run_dir); 251 fs_private_dir_mount(private_dir, private_run_dir);
251 fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end()); 252 fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end());
252} 253}
254
255void fs_rebuild_etc(void) {
256 int have_dhcp = 1;
257 if (cfg.dns1 == NULL && !any_dhcp())
258 have_dhcp = 0;
259
260 if (arg_debug)
261 printf("rebuilding /etc directory\n");
262 if (mkdir(RUN_DNS_ETC, 0755))
263 errExit("mkdir");
264 selinux_relabel_path(RUN_DNS_ETC, "/etc");
265 fs_logger("tmpfs /etc");
266
267 DIR *dir = opendir("/etc");
268 if (!dir)
269 errExit("opendir");
270
271 struct stat s;
272 struct dirent *entry;
273 while ((entry = readdir(dir))) {
274 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
275 continue;
276
277 // skip files in cfg.profile_rebuild_etc list
278 // these files are already blacklisted
279 {
280 ProfileEntry *prf = cfg.profile_rebuild_etc;
281 int found = 0;
282 while (prf) {
283 if (strcmp(entry->d_name, prf->data + 5) == 0) { // 5 is strlen("/etc/")
284 found = 1;
285 break;
286 }
287 prf = prf->next;
288 }
289 if (found)
290 continue;
291 }
292
293 // for resolv.conf we might have to create a brand new file later
294 if (have_dhcp &&
295 (strcmp(entry->d_name, "resolv.conf") == 0 ||
296 strcmp(entry->d_name, "resolv.conf.dhclient-new") == 0))
297 continue;
298// printf("linking %s\n", entry->d_name);
299
300 char *src;
301 if (asprintf(&src, "/etc/%s", entry->d_name) == -1)
302 errExit("asprintf");
303 if (stat(src, &s) != 0) {
304 free(src);
305 continue;
306 }
307
308 char *dest;
309 if (asprintf(&dest, "%s/%s", RUN_DNS_ETC, entry->d_name) == -1)
310 errExit("asprintf");
311
312 int symlink_done = 0;
313 if (is_link(src)) {
314 char *rp =realpath(src, NULL);
315 if (rp == NULL) {
316 free(src);
317 free(dest);
318 continue;
319 }
320 if (symlink(rp, dest))
321 errExit("symlink");
322 else
323 symlink_done = 1;
324 }
325 else if (S_ISDIR(s.st_mode))
326 create_empty_dir_as_root(dest, s.st_mode);
327 else
328 create_empty_file_as_root(dest, s.st_mode);
329
330 // bind-mount src on top of dest
331 if (!symlink_done) {
332 if (mount(src, dest, NULL, MS_BIND|MS_REC, NULL) < 0)
333 errExit("mount bind mirroring /etc");
334 }
335 fs_logger2("clone", src);
336
337 free(src);
338 free(dest);
339 }
340 closedir(dir);
341
342 // mount bind our private etc directory on top of /etc
343 if (arg_debug)
344 printf("Mount-bind %s on top of /etc\n", RUN_DNS_ETC);
345 if (mount(RUN_DNS_ETC, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0)
346 errExit("mount bind mirroring /etc");
347 fs_logger("mount /etc");
348
349 if (have_dhcp == 0)
350 return;
351
352 if (arg_debug)
353 printf("Creating a new /etc/resolv.conf file\n");
354 FILE *fp = fopen("/etc/resolv.conf", "wxe");
355 if (!fp) {
356 fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n");
357 exit(1);
358 }
359
360 if (cfg.dns1) {
361 if (any_dhcp())
362 fwarning("network setup uses DHCP, nameservers will likely be overwritten\n");
363 fprintf(fp, "nameserver %s\n", cfg.dns1);
364 }
365 if (cfg.dns2)
366 fprintf(fp, "nameserver %s\n", cfg.dns2);
367 if (cfg.dns3)
368 fprintf(fp, "nameserver %s\n", cfg.dns3);
369 if (cfg.dns4)
370 fprintf(fp, "nameserver %s\n", cfg.dns4);
371
372 // mode and owner
373 SET_PERMS_STREAM(fp, 0, 0, 0644);
374
375 fclose(fp);
376
377 fs_logger("create /etc/resolv.conf");
378}
diff --git a/src/firejail/fs_hostname.c b/src/firejail/fs_hostname.c
index 80046f7ae..1a9a78ceb 100644
--- a/src/firejail/fs_hostname.c
+++ b/src/firejail/fs_hostname.c
@@ -88,109 +88,6 @@ errexit:
88 exit(1); 88 exit(1);
89} 89}
90 90
91void fs_resolvconf(void) {
92 if (cfg.dns1 == NULL && !any_dhcp())
93 return;
94
95 if (arg_debug)
96 printf("mirroring /etc directory\n");
97 if (mkdir(RUN_DNS_ETC, 0755))
98 errExit("mkdir");
99 selinux_relabel_path(RUN_DNS_ETC, "/etc");
100 fs_logger("tmpfs /etc");
101
102 DIR *dir = opendir("/etc");
103 if (!dir)
104 errExit("opendir");
105
106 struct stat s;
107 struct dirent *entry;
108 while ((entry = readdir(dir))) {
109 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
110 continue;
111 // for resolv.conf we create a brand new file
112 if (strcmp(entry->d_name, "resolv.conf") == 0 ||
113 strcmp(entry->d_name, "resolv.conf.dhclient-new") == 0)
114 continue;
115// printf("linking %s\n", entry->d_name);
116
117 char *src;
118 if (asprintf(&src, "/etc/%s", entry->d_name) == -1)
119 errExit("asprintf");
120 if (stat(src, &s) != 0) {
121 free(src);
122 continue;
123 }
124
125 char *dest;
126 if (asprintf(&dest, "%s/%s", RUN_DNS_ETC, entry->d_name) == -1)
127 errExit("asprintf");
128
129 int symlink_done = 0;
130 if (is_link(src)) {
131 char *rp =realpath(src, NULL);
132 if (rp == NULL) {
133 free(src);
134 free(dest);
135 continue;
136 }
137 if (symlink(rp, dest))
138 errExit("symlink");
139 else
140 symlink_done = 1;
141 }
142 else if (S_ISDIR(s.st_mode))
143 create_empty_dir_as_root(dest, s.st_mode);
144 else
145 create_empty_file_as_root(dest, s.st_mode);
146
147 // bind-mount src on top of dest
148 if (!symlink_done) {
149 if (mount(src, dest, NULL, MS_BIND|MS_REC, NULL) < 0)
150 errExit("mount bind mirroring /etc");
151 }
152 fs_logger2("clone", src);
153
154 free(src);
155 free(dest);
156 }
157 closedir(dir);
158
159 // mount bind our private etc directory on top of /etc
160 if (arg_debug)
161 printf("Mount-bind %s on top of /etc\n", RUN_DNS_ETC);
162 if (mount(RUN_DNS_ETC, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0)
163 errExit("mount bind mirroring /etc");
164 fs_logger("mount /etc");
165
166 if (arg_debug)
167 printf("Creating a new /etc/resolv.conf file\n");
168 FILE *fp = fopen("/etc/resolv.conf", "wxe");
169 if (!fp) {
170 fprintf(stderr, "Error: cannot create /etc/resolv.conf file\n");
171 exit(1);
172 }
173
174 if (cfg.dns1) {
175 if (any_dhcp())
176 fwarning("network setup uses DHCP, nameservers will likely be overwritten\n");
177 fprintf(fp, "nameserver %s\n", cfg.dns1);
178 }
179 if (cfg.dns2)
180 fprintf(fp, "nameserver %s\n", cfg.dns2);
181 if (cfg.dns3)
182 fprintf(fp, "nameserver %s\n", cfg.dns3);
183 if (cfg.dns4)
184 fprintf(fp, "nameserver %s\n", cfg.dns4);
185
186 // mode and owner
187 SET_PERMS_STREAM(fp, 0, 0, 0644);
188
189 fclose(fp);
190
191 fs_logger("create /etc/resolv.conf");
192}
193
194char *fs_check_hosts_file(const char *fname) { 91char *fs_check_hosts_file(const char *fname) {
195 assert(fname); 92 assert(fname);
196 invalid_filename(fname, 0); // no globbing 93 invalid_filename(fname, 0); // no globbing
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index fd359c39e..59ddfb855 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -1043,7 +1043,7 @@ int sandbox(void* sandbox_arg) {
1043 //**************************** 1043 //****************************
1044 // set dns 1044 // set dns
1045 //**************************** 1045 //****************************
1046 fs_resolvconf(); 1046 fs_rebuild_etc();
1047 1047
1048 //**************************** 1048 //****************************
1049 // start dhcp client 1049 // start dhcp client