aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2015-11-12 08:33:34 -0500
committerLibravatar netblue30 <netblue30@yahoo.com>2015-11-12 08:33:34 -0500
commitda90151010a39ccd106fbf9f20b449a1f0119bbe (patch)
tree1150dc98b23d1015e907e7c8146f015a6d6add22 /src
parentfix symlink whitelist (diff)
downloadfirejail-da90151010a39ccd106fbf9f20b449a1f0119bbe.tar.gz
firejail-da90151010a39ccd106fbf9f20b449a1f0119bbe.tar.zst
firejail-da90151010a39ccd106fbf9f20b449a1f0119bbe.zip
whitelist support for /tmp
Diffstat (limited to 'src')
-rw-r--r--src/firejail/firejail.h9
-rw-r--r--src/firejail/fs_whitelist.c188
-rw-r--r--src/firejail/profile.c1
3 files changed, 142 insertions, 56 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 58c497cd8..e3334bd2e 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -39,7 +39,8 @@
39#define DRI_DIR "/run/firejail/mnt/dri" 39#define DRI_DIR "/run/firejail/mnt/dri"
40#define PULSE_DIR "/run/firejail/mnt/pulse" 40#define PULSE_DIR "/run/firejail/mnt/pulse"
41#define DEVLOG_FILE "/run/firejail/mnt/devlog" 41#define DEVLOG_FILE "/run/firejail/mnt/devlog"
42#define WHITELIST_HOME_DIR "/run/firejail/mnt/whome" 42#define WHITELIST_HOME_DIR "/run/firejail/mnt/orig-home"
43#define WHITELIST_TMP_DIR "/run/firejail/mnt/orig-tmp"
43#define XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority" 44#define XAUTHORITY_FILE "/run/firejail/mnt/.Xauthority"
44#define HOSTNAME_FILE "/run/firejail/mnt/hostname" 45#define HOSTNAME_FILE "/run/firejail/mnt/hostname"
45#define RESOLVCONF_FILE "/run/firejail/mnt/resolv.conf" 46#define RESOLVCONF_FILE "/run/firejail/mnt/resolv.conf"
@@ -86,8 +87,12 @@ typedef struct interface_t {
86 87
87typedef struct profile_entry_t { 88typedef struct profile_entry_t {
88 struct profile_entry_t *next; 89 struct profile_entry_t *next;
89 char *data; // expanded name of the file 90 char *data; // command
91
92 // whitelist command parameters
90 char *link; // link name - set if the file is a link 93 char *link; // link name - set if the file is a link
94 unsigned home_dir:1; // whitelist in /home/user directory
95 unsigned tmp_dir:1; // whitelist in /tmp directory
91}ProfileEntry; 96}ProfileEntry;
92 97
93typedef struct config_t { 98typedef struct config_t {
diff --git a/src/firejail/fs_whitelist.c b/src/firejail/fs_whitelist.c
index c856359f6..fd9115a5e 100644
--- a/src/firejail/fs_whitelist.c
+++ b/src/firejail/fs_whitelist.c
@@ -56,26 +56,40 @@ static int mkpath(const char* path, mode_t mode) {
56 return 0; 56 return 0;
57} 57}
58 58
59static void whitelist_path(const char *path) { 59static void whitelist_path(ProfileEntry *entry) {
60 assert(entry);
61 char *path = entry->data + 10;
60 assert(path); 62 assert(path);
63 const char *fname;
64 char *wfile;
61 65
62 // fname needs to start with /home/username 66 if (entry->home_dir) {
63 if (strncmp(path, cfg.homedir, strlen(cfg.homedir))) { 67printf("here %d\n", __LINE__);
64 fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path); 68 fname = path + strlen(cfg.homedir);
65 exit(1); 69 if (*fname == '\0') {
66 } 70 fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path);
67 71 exit(1);
68 const char *fname = path + strlen(cfg.homedir); 72 }
69 if (*fname == '\0') { 73
70 fprintf(stderr, "Error: file %s is not in user home directory, exiting...\n", path); 74 if (asprintf(&wfile, "%s/%s", WHITELIST_HOME_DIR, fname) == -1)
71 exit(1); 75 errExit("asprintf");
72 } 76 }
77 else if (entry->tmp_dir) {
78printf("here %d\n", __LINE__);
79 fname = path + 4; // strlen("/tmp")
80 if (*fname == '\0') {
81 fprintf(stderr, "Error: file %s is not in /tmp directory, exiting...\n", path);
82 exit(1);
83 }
73 84
74 char *wfile; 85 if (asprintf(&wfile, "%s/%s", WHITELIST_TMP_DIR, fname) == -1)
75 if (asprintf(&wfile, "%s/%s", WHITELIST_HOME_DIR, fname) == -1) 86 errExit("asprintf");
76 errExit("asprintf"); 87 }
77 88
78 // check if the file exists 89 // check if the file exists
90printf("here %d %s\n", __LINE__, wfile);
91system("ls -l /run/firejail/mnt/orig-tmp");
92
79 struct stat s; 93 struct stat s;
80 if (stat(wfile, &s) == 0) { 94 if (stat(wfile, &s) == 0) {
81 if (arg_debug) 95 if (arg_debug)
@@ -132,9 +146,12 @@ void fs_whitelist(void) {
132 ProfileEntry *entry = cfg.profile; 146 ProfileEntry *entry = cfg.profile;
133 if (!entry) 147 if (!entry)
134 return; 148 return;
135 149
136 // realpath function will fail with ENOENT if the file is not found 150 char *new_name = NULL;
137 // we need to expand the path before installing a new, empty home directory 151 int home_dir = 0; // /home/user directory flag
152 int tmp_dir = 0; // /tmp directory flag
153
154 // verify whitelist files, extract symbolic links, etc.
138 while (entry) { 155 while (entry) {
139 // handle only whitelist commands 156 // handle only whitelist commands
140 if (strncmp(entry->data, "whitelist ", 10)) { 157 if (strncmp(entry->data, "whitelist ", 10)) {
@@ -142,10 +159,42 @@ void fs_whitelist(void) {
142 continue; 159 continue;
143 } 160 }
144 161
145 char *new_name = expand_home(entry->data + 10, cfg.homedir); 162 // replace ~/ or ${HOME} into /home/username
146 163 new_name = expand_home(entry->data + 10, cfg.homedir);
147 assert(new_name); 164 assert(new_name);
165
166 // extract the absolute path of the file
167 // realpath function will fail with ENOENT if the file is not found
148 char *fname = realpath(new_name, NULL); 168 char *fname = realpath(new_name, NULL);
169 if (!fname) {
170 // file not found, blank the entry in the list and continue
171 if (arg_debug)
172 printf("Removed whitelist path: %s\n", entry->data);
173 *entry->data = '\0';
174 continue;
175 }
176
177 // valid path referenced to filesystem root
178 if (*new_name != '/')
179 goto errexit;
180
181 // check for home directory or tmp directory
182 if (strncmp(new_name, cfg.homedir, strlen(cfg.homedir)) == 0) {
183 entry->home_dir = 1;
184 home_dir = 1;
185 // both path and absolute path are under /home
186 if (strncmp(fname, cfg.homedir, strlen(cfg.homedir)) != 0)
187 goto errexit;
188 }
189 else if (strncmp(new_name, "/tmp/", 5) == 0) {
190 entry->tmp_dir = 1;
191 tmp_dir = 1;
192 // both path and absolute path are under /tmp
193 if (strncmp(fname, "/tmp/", 5) != 0)
194 goto errexit;
195 }
196 else
197 goto errexit;
149 198
150 // mark symbolic links 199 // mark symbolic links
151 if (is_link(new_name)) 200 if (is_link(new_name))
@@ -153,44 +202,60 @@ void fs_whitelist(void) {
153 else 202 else
154 free(new_name); 203 free(new_name);
155 204
156 if (fname) { 205 // change file name in entry->data
157 // change file name in entry->data 206 if (strcmp(fname, entry->data + 10) != 0) {
158 if (strcmp(fname, entry->data + 10) != 0) { 207 char *newdata;
159 char *newdata; 208 if (asprintf(&newdata, "whitelist %s", fname) == -1)
160 if (asprintf(&newdata, "whitelist %s", fname) == -1) 209 errExit("asprintf");
161 errExit("asprintf"); 210 entry->data = newdata;
162 entry->data = newdata;
163 if (arg_debug)
164 printf("Replaced whitelist path: %s\n", entry->data);
165 }
166
167 free(fname);
168 }
169 else {
170 // file not found, blank the entry in the list
171 if (arg_debug) 211 if (arg_debug)
172 printf("Removed whitelist path: %s\n", entry->data); 212 printf("Replaced whitelist path: %s\n", entry->data);
173 *entry->data = '\0';
174 } 213 }
214 free(fname);
175 entry = entry->next; 215 entry = entry->next;
176 } 216 }
177 217
178 // create /tmp/firejail/mnt/whome directory 218 // create mount points
179 fs_build_mnt_dir(); 219 fs_build_mnt_dir();
180 int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
181 if (rv == -1)
182 errExit("mkdir");
183 if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0)
184 errExit("chown");
185 if (chmod(WHITELIST_HOME_DIR, 0755) < 0)
186 errExit("chmod");
187 220
188 // keep a copy of real home dir in /tmp/firejail/mnt/whome 221 // /home/user
189 if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0) 222 if (home_dir) {
190 errExit("mount bind"); 223 // keep a copy of real home dir in WHITELIST_HOME_DIR
191 224 int rv = mkdir(WHITELIST_HOME_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
192 // start building the new home directory by mounting a tmpfs fielsystem 225 if (rv == -1)
193 fs_private(); 226 errExit("mkdir");
227 if (chown(WHITELIST_HOME_DIR, getuid(), getgid()) < 0)
228 errExit("chown");
229 if (chmod(WHITELIST_HOME_DIR, 0755) < 0)
230 errExit("chmod");
231
232 if (mount(cfg.homedir, WHITELIST_HOME_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
233 errExit("mount bind");
234
235 // mount a tmpfs and initialize /home/user
236 fs_private();
237 }
238
239 // /tmp mountpoint
240 if (tmp_dir) {
241 // keep a copy of real /tmp directory in WHITELIST_TMP_DIR
242 int rv = mkdir(WHITELIST_TMP_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
243 if (rv == -1)
244 errExit("mkdir");
245 if (chown(WHITELIST_TMP_DIR, 0, 0) < 0)
246 errExit("chown");
247 if (chmod(WHITELIST_TMP_DIR, 0777) < 0)
248 errExit("chmod");
249
250 if (mount("/tmp", WHITELIST_TMP_DIR, NULL, MS_BIND|MS_REC, NULL) < 0)
251 errExit("mount bind");
252
253 // mount tmpfs on /tmp
254 if (arg_debug)
255 printf("Mounting tmpfs on /tmp directory\n");
256 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=777,gid=0") < 0)
257 errExit("mounting tmpfs on /tmpt");
258 }
194 259
195 // go through profile rules again, and interpret whitelist commands 260 // go through profile rules again, and interpret whitelist commands
196 entry = cfg.profile; 261 entry = cfg.profile;
@@ -201,8 +266,9 @@ void fs_whitelist(void) {
201 continue; 266 continue;
202 } 267 }
203 268
269//printf("here %d#%s#\n", __LINE__, entry->data);
204 // whitelist the real file 270 // whitelist the real file
205 whitelist_path(entry->data + 10); 271 whitelist_path(entry);
206 272
207 // create the link if any 273 // create the link if any
208 if (entry->link) { 274 if (entry->link) {
@@ -220,7 +286,21 @@ void fs_whitelist(void) {
220 entry = entry->next; 286 entry = entry->next;
221 } 287 }
222 288
223 // mask the real home directory, currently mounted on /tmp/firejail/mnt/whome 289 // mask the real home directory, currently mounted on WHITELIST_HOME_DIR
224 if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0) 290 if (home_dir) {
225 errExit("mount tmpfs"); 291 if (mount("tmpfs", WHITELIST_HOME_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
292 errExit("mount tmpfs");
293 }
294
295 // mask the real /tmp directory, currently mounted on WHITELIST_TMP_DIR
296 if (tmp_dir) {
297 if (mount("tmpfs", WHITELIST_TMP_DIR, "tmpfs", MS_NOSUID | MS_STRICTATIME | MS_REC, "mode=755,gid=0") < 0)
298 errExit("mount tmpfs");
299 }
300
301 return;
302
303errexit:
304 fprintf(stderr, "Error: invalid whitelist path %s\n", new_name);
305 exit(1);
226} 306}
diff --git a/src/firejail/profile.c b/src/firejail/profile.c
index aeeacfde8..73407d9c0 100644
--- a/src/firejail/profile.c
+++ b/src/firejail/profile.c
@@ -398,6 +398,7 @@ void profile_add(char *str) {
398 ProfileEntry *prf = malloc(sizeof(ProfileEntry)); 398 ProfileEntry *prf = malloc(sizeof(ProfileEntry));
399 if (!prf) 399 if (!prf)
400 errExit("malloc"); 400 errExit("malloc");
401 memset(prf, 0, sizeof(ProfileEntry));
401 prf->next = NULL; 402 prf->next = NULL;
402 prf->data = str; 403 prf->data = str;
403 404