aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2015-08-12 08:36:41 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2015-08-12 08:36:41 -0400
commit46334f0039100403572d7a6144d3a082cb648a42 (patch)
treec7e9d600b3ce213158ea9f26b9a87e9610269afb
parenttenative fix for issue 11 (diff)
downloadfirejail-46334f0039100403572d7a6144d3a082cb648a42.tar.gz
firejail-46334f0039100403572d7a6144d3a082cb648a42.tar.zst
firejail-46334f0039100403572d7a6144d3a082cb648a42.zip
--private-etc option, issue #5
-rw-r--r--src/firejail/firejail.h6
-rw-r--r--src/firejail/fs_etc.c146
-rw-r--r--src/firejail/fs_home.c2
-rw-r--r--src/firejail/main.c7
-rw-r--r--src/firejail/profile.c10
-rw-r--r--src/firejail/sandbox.c2
-rw-r--r--src/firejail/usage.c5
-rw-r--r--src/man/firejail-profile.txt5
-rw-r--r--src/man/firejail.txt13
9 files changed, 194 insertions, 2 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 2ec6e54c9..5adabbcb3 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -28,6 +28,7 @@
28#define MNT_DIR "/tmp/firejail/mnt" 28#define MNT_DIR "/tmp/firejail/mnt"
29#define OVERLAY_DIR "/tmp/firejail/overlay" 29#define OVERLAY_DIR "/tmp/firejail/overlay"
30#define HOME_DIR "/tmp/firejail/mnt/home" 30#define HOME_DIR "/tmp/firejail/mnt/home"
31#define ETC_DIR "/tmp/firejail/mnt/etc"
31#define MAX_INCLUDE_LEVEL 6 32#define MAX_INCLUDE_LEVEL 6
32 33
33// main.c 34// main.c
@@ -67,6 +68,7 @@ typedef struct config_t {
67 char *chrootdir; // chroot directory 68 char *chrootdir; // chroot directory
68 char *home_private; // private home directory 69 char *home_private; // private home directory
69 char *home_private_keep; // keep list for private home directory 70 char *home_private_keep; // keep list for private home directory
71 char *etc_private_keep; // keep list for private etc directory
70 char *cwd; // current working directory 72 char *cwd; // current working directory
71 73
72 // networking 74 // networking
@@ -140,6 +142,7 @@ extern char *arg_netfilter_file; // netfilter file
140extern int arg_doubledash; // double dash 142extern int arg_doubledash; // double dash
141extern int arg_shell_none; // run the program directly without a shell 143extern int arg_shell_none; // run the program directly without a shell
142extern int arg_private_dev; // private dev directory 144extern int arg_private_dev; // private dev directory
145extern int arg_private_etc; // private etc directory
143extern int arg_scan; // arp-scan all interfaces 146extern int arg_scan; // arp-scan all interfaces
144 147
145extern int parent_to_child_fds[2]; 148extern int parent_to_child_fds[2];
@@ -350,5 +353,8 @@ void bandwidth_pid(pid_t pid, const char *command, const char *dev, int down, in
350void network_shm_del_file(pid_t pid); 353void network_shm_del_file(pid_t pid);
351void network_shm_set_file(pid_t pid); 354void network_shm_set_file(pid_t pid);
352 355
356// fs_etc.c
357void fs_check_etc_list(void);
358void fs_private_etc_list(void);
353 359
354#endif \ No newline at end of file 360#endif \ No newline at end of file
diff --git a/src/firejail/fs_etc.c b/src/firejail/fs_etc.c
new file mode 100644
index 000000000..57b0b4f3e
--- /dev/null
+++ b/src/firejail/fs_etc.c
@@ -0,0 +1,146 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
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
27static void check_dir_or_file(const char *name) {
28 assert(name);
29 struct stat s;
30 char *fname;
31 if (asprintf(&fname, "/etc/%s", name) == -1)
32 errExit("asprintf");
33 if (arg_debug)
34 printf("Checking %s\n", fname);
35 if (stat(fname, &s) == -1) {
36 fprintf(stderr, "Error: file %s not found.\n", fname);
37 exit(1);
38 }
39
40 // dir or regular file
41 if (S_ISDIR(s.st_mode) || S_ISREG(s.st_mode)) {
42 free(fname);
43 return;
44 }
45
46 if (!is_link(fname)) {
47 free(fname);
48 return;
49 }
50
51 fprintf(stderr, "Error: invalid file type, %s.\n", fname);
52 exit(1);
53}
54
55void fs_check_etc_list(void) {
56 if (strstr(cfg.etc_private_keep, "..")) {
57 fprintf(stderr, "Error: invalid private etc list\n");
58 exit(1);
59 }
60
61 char *dlist = strdup(cfg.etc_private_keep);
62 if (!dlist)
63 errExit("strdup");
64
65 char *ptr = strtok(dlist, ",");
66 check_dir_or_file(ptr);
67 while ((ptr = strtok(NULL, ",")) != NULL)
68 check_dir_or_file(ptr);
69
70 free(dlist);
71}
72
73static void duplicate(char *fname) {
74 char *cmd;
75
76 // copy the file
77 if (asprintf(&cmd, "cp -a --parents /etc/%s %s", fname, MNT_DIR) == -1)
78 errExit("asprintf");
79 if (arg_debug)
80 printf("%s\n", cmd);
81 if (system(cmd))
82 errExit("system cp -a --parents");
83 free(cmd);
84}
85
86
87void fs_private_etc_list(void) {
88 char *private_list = cfg.etc_private_keep;
89 assert(private_list);
90
91 uid_t u = getuid();
92 gid_t g = getgid();
93 struct stat s;
94 if (stat("/etc", &s) == -1) {
95 fprintf(stderr, "Error: cannot find user /etc directory\n");
96 exit(1);
97 }
98
99 // create /tmp/firejail/mnt/etc directory
100 fs_build_mnt_dir();
101 int rv = mkdir(ETC_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
102 if (rv == -1)
103 errExit("mkdir");
104 if (chown(ETC_DIR, 0, 0) < 0)
105 errExit("chown");
106 if (chmod(ETC_DIR, 0755) < 0)
107 errExit("chmod");
108
109 // copy the list of files in the new etc directory
110 // using a new child process without root privileges
111 pid_t child = fork();
112 if (child < 0)
113 errExit("fork");
114 if (child == 0) {
115 if (arg_debug)
116 printf("Copying files in the new home:\n");
117
118 // elevate privileges - files in the new /etc directory belong to root
119 if (setreuid(0, 0) < 0)
120 errExit("setreuid");
121 if (setregid(0, 0) < 0)
122 errExit("setregid");
123
124 // copy the list of files in the new home directory
125 char *dlist = strdup(private_list);
126 if (!dlist)
127 errExit("strdup");
128
129 char *ptr = strtok(dlist, ",");
130 duplicate(ptr);
131
132 while ((ptr = strtok(NULL, ",")) != NULL)
133 duplicate(ptr);
134 free(dlist);
135 exit(0);
136 }
137 // wait for the child to finish
138 waitpid(child, NULL, 0);
139
140 if (arg_debug)
141 printf("Mount-bind %s on top of /etc\n", ETC_DIR);
142 if (mount(ETC_DIR, "/etc", NULL, MS_BIND|MS_REC, NULL) < 0)
143 errExit("mount bind");
144
145}
146
diff --git a/src/firejail/fs_home.c b/src/firejail/fs_home.c
index 853e3930b..ca4691751 100644
--- a/src/firejail/fs_home.c
+++ b/src/firejail/fs_home.c
@@ -273,7 +273,7 @@ static void check_dir_or_file(const char *name) {
273 if (asprintf(&fname, "%s/%s", cfg.homedir, name) == -1) 273 if (asprintf(&fname, "%s/%s", cfg.homedir, name) == -1)
274 errExit("asprintf"); 274 errExit("asprintf");
275 if (arg_debug) 275 if (arg_debug)
276 printf("***************Checking %s\n", fname); 276 printf("Checking %s\n", fname);
277 if (stat(fname, &s) == -1) { 277 if (stat(fname, &s) == -1) {
278 fprintf(stderr, "Error: file %s not found.\n", fname); 278 fprintf(stderr, "Error: file %s not found.\n", fname);
279 exit(1); 279 exit(1);
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 78971aa86..1f4574c5c 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -81,6 +81,7 @@ char *arg_netfilter_file = NULL; // netfilter file
81int arg_doubledash = 0; // double dash 81int arg_doubledash = 0; // double dash
82int arg_shell_none = 0; // run the program directly without a shell 82int arg_shell_none = 0; // run the program directly without a shell
83int arg_private_dev = 0; // private dev directory 83int arg_private_dev = 0; // private dev directory
84int arg_private_etc = 0; // private etc directory
84int arg_scan = 0; // arp-scan all interfaces 85int arg_scan = 0; // arp-scan all interfaces
85 86
86int parent_to_child_fds[2]; 87int parent_to_child_fds[2];
@@ -699,6 +700,12 @@ int main(int argc, char **argv) {
699 else if (strcmp(argv[i], "--private-dev") == 0) { 700 else if (strcmp(argv[i], "--private-dev") == 0) {
700 arg_private_dev = 1; 701 arg_private_dev = 1;
701 } 702 }
703 else if (strncmp(argv[i], "--private-etc=", 14) == 0) {
704 // extract private etc dirname
705 cfg.etc_private_keep = argv[i] + 14;
706 fs_check_etc_list();
707 arg_private_etc = 1;
708 }
702 709
703 710
704 711
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index 877428637..a6843cc6d 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -227,13 +227,21 @@ int profile_check_line(char *ptr, int lineno) {
227 return 0; 227 return 0;
228 } 228 }
229 229
230 // private list of files and directories 230 // private home list of files and directories
231 if (strncmp(ptr, "private.keep ", 13) == 0) { 231 if (strncmp(ptr, "private.keep ", 13) == 0) {
232 cfg.home_private_keep = ptr + 13; 232 cfg.home_private_keep = ptr + 13;
233 fs_check_home_list(); 233 fs_check_home_list();
234 arg_private = 1; 234 arg_private = 1;
235 return 0; 235 return 0;
236 } 236 }
237
238 // private /etc list of files and directories
239 if (strncmp(ptr, "private-etc ", 12) == 0) {
240 cfg.etc_private_keep = ptr + 12;
241 fs_check_etc_list();
242 arg_private_etc = 1;
243 return 0;
244 }
237 245
238 // filesystem bind 246 // filesystem bind
239 if (strncmp(ptr, "bind ", 5) == 0) { 247 if (strncmp(ptr, "bind ", 5) == 0) {
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index 3f5fb51fa..2beb31099 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -245,6 +245,8 @@ int sandbox(void* sandbox_arg) {
245 245
246 if (arg_private_dev) 246 if (arg_private_dev)
247 fs_private_dev(); 247 fs_private_dev();
248 if (arg_private_etc)
249 fs_private_etc_list();
248 250
249 //**************************** 251 //****************************
250 // install trace 252 // install trace
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 71ae203ff..2beeddb70 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -152,8 +152,13 @@ void usage(void) {
152 printf("\t\tfilesystem, and copy the files and directories in the list in\n"); 152 printf("\t\tfilesystem, and copy the files and directories in the list in\n");
153 printf("\t\tthe new home. All modifications are discarded when the sandbox\n"); 153 printf("\t\tthe new home. All modifications are discarded when the sandbox\n");
154 printf("\t\tis closed.\n\n"); 154 printf("\t\tis closed.\n\n");
155
155 printf("\t--private-dev - create a new /dev directory. Only null, full, zero, tty,\n"); 156 printf("\t--private-dev - create a new /dev directory. Only null, full, zero, tty,\n");
156 printf("\t\tpst, ptms, random, urandom and shm devices are available.\n\n"); 157 printf("\t\tpst, ptms, random, urandom and shm devices are available.\n\n");
158
159 printf("\t--private-etc=file,directory - build a new /etc in a temporary\n");
160 printf("\t\tfilesystem, and copy the files and directories in the list.\n");
161 printf("\t\tAll modifications are discarded when the sandbox is closed.\n\n");
157 162
158 printf("\t--profile=filename - use a custom profile.\n\n"); 163 printf("\t--profile=filename - use a custom profile.\n\n");
159 printf("\t--read-only=dirname_or_filename - set directory or file read-only.\n\n"); 164 printf("\t--read-only=dirname_or_filename - set directory or file read-only.\n\n");
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt
index f85e10171..60d9c47c5 100644
--- a/src/man/firejail-profile.txt
+++ b/src/man/firejail-profile.txt
@@ -81,6 +81,11 @@ closed.
81.TP 81.TP
82\f\private-dev 82\f\private-dev
83Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available. 83Create a new /dev directory. Only null, full, zero, tty, pts, ptmx, random, urandom and shm devices are available.
84.TP
85\f\private-etc file,directory
86Build a new /etc in a temporary
87filesystem, and copy the files and directories in the list.
88All modifications are discarded when the sandbox is closed.
84 89
85.SH Filters 90.SH Filters
86\fBcaps\fR and \fBseccomp\fR enable Linux capabilities and seccomp filters. Examples: 91\fBcaps\fR and \fBseccomp\fR enable Linux capabilities and seccomp filters. Examples:
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 4e8d96d31..dbffe68ed 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -670,6 +670,19 @@ full null ptmx pts random shm tty urandom zero
670.br 670.br
671$ 671$
672.TP 672.TP
673\fB\-\-private-etc=file,directory
674Build a new /etc in a temporary
675filesystem, and copy the files and directories in the list.
676All modifications are discarded when the sandbox is closed.
677.br
678
679.br
680Example:
681.br
682$ firejail --private-etc=group,hostname,localtime, \\
683.br
684nsswitch.conf,passwd,resolv.conf
685.TP
673\fB\-\-profile=filename 686\fB\-\-profile=filename
674Load a custom profile from filename. For filename use an absolute path or a path relative to the current path. 687Load a custom profile from filename. For filename use an absolute path or a path relative to the current path.
675For more information, see PROFILES section below. 688For more information, see PROFILES section below.