aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/fs_bin.c217
-rw-r--r--src/firejail/main.c9
-rw-r--r--src/firejail/sandbox.c2
4 files changed, 230 insertions, 1 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index 2dd70c7f4..27e49ea38 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 HOME_DIR "/tmp/firejail/mnt/home" 29#define HOME_DIR "/tmp/firejail/mnt/home"
30#define ETC_DIR "/tmp/firejail/mnt/etc" 30#define ETC_DIR "/tmp/firejail/mnt/etc"
31#define BIN_DIR "/tmp/firejail/mnt/bin"
31#define WHITELIST_HOME_DIR "/tmp/firejail/mnt/whome" 32#define WHITELIST_HOME_DIR "/tmp/firejail/mnt/whome"
32#define DEFAULT_USER_PROFILE "generic" 33#define DEFAULT_USER_PROFILE "generic"
33#define DEFAULT_ROOT_PROFILE "server" 34#define DEFAULT_ROOT_PROFILE "server"
@@ -82,6 +83,7 @@ typedef struct config_t {
82 char *home_private; // private home directory 83 char *home_private; // private home directory
83 char *home_private_keep; // keep list for private home directory 84 char *home_private_keep; // keep list for private home directory
84 char *etc_private_keep; // keep list for private etc directory 85 char *etc_private_keep; // keep list for private etc directory
86 char *bin_private_keep; // keep list for private etc directory
85 char *cwd; // current working directory 87 char *cwd; // current working directory
86 char *overlay_dir; 88 char *overlay_dir;
87 89
@@ -169,6 +171,7 @@ extern int arg_doubledash; // double dash
169extern int arg_shell_none; // run the program directly without a shell 171extern int arg_shell_none; // run the program directly without a shell
170extern int arg_private_dev; // private dev directory 172extern int arg_private_dev; // private dev directory
171extern int arg_private_etc; // private etc directory 173extern int arg_private_etc; // private etc directory
174extern int arg_private_bin; // private bin directory
172extern int arg_scan; // arp-scan all interfaces 175extern int arg_scan; // arp-scan all interfaces
173extern int arg_whitelist; // whitelist commad 176extern int arg_whitelist; // whitelist commad
174 177
diff --git a/src/firejail/fs_bin.c b/src/firejail/fs_bin.c
new file mode 100644
index 000000000..4b3292b6c
--- /dev/null
+++ b/src/firejail/fs_bin.c
@@ -0,0 +1,217 @@
1/*
2 * Copyright (C) 2014, 2015 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
27static char *paths[] = {
28 "/bin",
29 "/sbin",
30 "/usr/bin",
31 "/usr/sbin",
32 NULL
33};
34
35// return 1 if found, 0 if not found
36static char *check_dir_or_file(const char *name) {
37 assert(name);
38 struct stat s;
39 char *fname = NULL;
40
41 int i = 0;
42 while (paths[i]) {
43 if (asprintf(&fname, "%s/%s", paths[i], name) == -1)
44 errExit("asprintf");
45 if (arg_debug)
46 printf("Checking %s/%s\n", paths[i], name);
47 if (stat(fname, &s) == 0)
48 break; // file found
49
50 free(fname);
51 fname = NULL;
52 i++;
53 }
54
55 if (!fname)
56 return NULL;
57
58 free(fname);
59 return paths[i];
60}
61
62void fs_check_bin_list(void) {
63 if (strstr(cfg.bin_private_keep, "..")) {
64 fprintf(stderr, "Error: invalid private bin list\n");
65 exit(1);
66 }
67
68 char *dlist = strdup(cfg.bin_private_keep);
69 if (!dlist)
70 errExit("strdup");
71
72 // create a new list removing files not found
73 char *newlist = malloc(strlen(dlist) + 1 + 1); // +',' + '\0'
74 if (!newlist)
75 errExit("malloc");
76 *newlist = '\0';
77 char *newlistptr = newlist;
78
79 // check the first file
80 char *ptr = strtok(dlist, ",");
81 int notfound = 0;
82 if (check_dir_or_file(ptr)) {
83 // file found, copy the name in the new list
84 strcpy(newlistptr, ptr);
85 strcat(newlistptr, ",");
86 newlistptr += strlen(newlistptr);
87 }
88 else
89 notfound = 1;
90
91 // check the rest of the list
92 while ((ptr = strtok(NULL, ",")) != NULL) {
93 if (check_dir_or_file(ptr)) {
94 // file found, copy the name in the new list
95 strcpy(newlistptr, ptr);
96 strcat(newlistptr, ",");
97 newlistptr += strlen(newlistptr);
98 }
99 else
100 notfound = 1;
101 }
102printf("here %d: newlist #%s#\n", __LINE__, newlist);
103
104 if (*newlist == '\0') {
105 fprintf(stderr, "Warning: no --private-bin list executable found, option disabled\n");
106 cfg.bin_private_keep = NULL;
107 arg_private_bin = 0;
108 free(newlist);
109 }
110 else {
111 ptr = strrchr(newlist, ',');
112 assert(ptr);
113 *ptr = '\0';
114 if (notfound)
115 fprintf(stderr, "Warning: not all executables from --private-bin list were found. The current list is %s\n", newlist);
116
117 cfg.bin_private_keep = newlist;
118 }
119
120 free(dlist);
121}
122
123static void duplicate(char *fname) {
124 char *cmd;
125 char *path = check_dir_or_file(fname);
126 if (!path)
127 return;
128
129 // expand path, just in case this is a symbolic link
130 char *full_path;
131 if (asprintf(&full_path, "%s/%s", path, fname) == -1)
132 errExit("asprintf");
133
134 char *actual_path = realpath(full_path, NULL);
135 if (actual_path) {
136 // copy the file
137 if (asprintf(&cmd, "cp -a %s %s/%s", actual_path, BIN_DIR, fname) == -1)
138 errExit("asprintf");
139 if (arg_debug)
140 printf("%s\n", cmd);
141 if (system(cmd))
142 errExit("system cp -a");
143 free(cmd);
144 free(actual_path);
145 }
146
147 free(full_path);
148}
149
150
151void fs_private_bin_list(void) {
152 char *private_list = cfg.bin_private_keep;
153 assert(private_list);
154
155 // check bin paths
156 int i = 0;
157 while (paths[i]) {
158 struct stat s;
159 if (stat(paths[i], &s) == -1) {
160 fprintf(stderr, "Error: cannot find %s directory\n", paths[i]);
161 exit(1);
162 }
163 i++;
164 }
165
166 // create /tmp/firejail/mnt/bin directory
167 fs_build_mnt_dir();
168 int rv = mkdir(BIN_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
169 if (rv == -1)
170 errExit("mkdir");
171 if (chown(BIN_DIR, 0, 0) < 0)
172 errExit("chown");
173 if (chmod(BIN_DIR, 0755) < 0)
174 errExit("chmod");
175
176 // copy the list of files in the new etc directory
177 // using a new child process without root privileges
178 pid_t child = fork();
179 if (child < 0)
180 errExit("fork");
181 if (child == 0) {
182 if (arg_debug)
183 printf("Copying files in the new home:\n");
184
185 // elevate privileges - files in the new /bin directory belong to root
186 if (setreuid(0, 0) < 0)
187 errExit("setreuid");
188 if (setregid(0, 0) < 0)
189 errExit("setregid");
190
191 // copy the list of files in the new home directory
192 char *dlist = strdup(private_list);
193 if (!dlist)
194 errExit("strdup");
195
196 char *ptr = strtok(dlist, ",");
197 duplicate(ptr);
198
199 while ((ptr = strtok(NULL, ",")) != NULL)
200 duplicate(ptr);
201 free(dlist);
202 exit(0);
203 }
204 // wait for the child to finish
205 waitpid(child, NULL, 0);
206
207 // moun-bind
208 i = 0;
209 while (paths[i]) {
210 if (arg_debug)
211 printf("Mount-bind %s on top of %s\n", BIN_DIR, paths[i]);
212 if (mount(BIN_DIR, paths[i], NULL, MS_BIND|MS_REC, NULL) < 0)
213 errExit("mount bind");
214 i++;
215 }
216}
217
diff --git a/src/firejail/main.c b/src/firejail/main.c
index a7eda3906..616b26894 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -82,6 +82,7 @@ int 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_private_etc = 0; // private etc directory
85int arg_private_bin = 0; // private bin directory
85int arg_scan = 0; // arp-scan all interfaces 86int arg_scan = 0; // arp-scan all interfaces
86int arg_whitelist = 0; // whitelist commad 87int arg_whitelist = 0; // whitelist commad
87 88
@@ -764,6 +765,12 @@ int main(int argc, char **argv) {
764 fs_check_etc_list(); 765 fs_check_etc_list();
765 arg_private_etc = 1; 766 arg_private_etc = 1;
766 } 767 }
768 else if (strncmp(argv[i], "--private-bin=", 14) == 0) {
769 // extract private etc dirname
770 cfg.bin_private_keep = argv[i] + 14;
771 fs_check_bin_list();
772 arg_private_bin = 1;
773 }
767 774
768 775
769 776
@@ -1029,7 +1036,7 @@ int main(int argc, char **argv) {
1029 } 1036 }
1030 cfg.shell = argv[i] + 8; 1037 cfg.shell = argv[i] + 8;
1031 1038
1032 if (is_dir(cfg.shell) || is_link(cfg.shell) || strstr(cfg.shell, "..")) { 1039 if (is_dir(cfg.shell) || strstr(cfg.shell, "..")) {
1033 fprintf(stderr, "Error: invalid shell\n"); 1040 fprintf(stderr, "Error: invalid shell\n");
1034 exit(1); 1041 exit(1);
1035 } 1042 }
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index eca4c2282..d3f92e51b 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -257,6 +257,8 @@ int sandbox(void* sandbox_arg) {
257 fs_private_dev(); 257 fs_private_dev();
258 if (arg_private_etc) 258 if (arg_private_etc)
259 fs_private_etc_list(); 259 fs_private_etc_list();
260 if (arg_private_bin)
261 fs_private_bin_list();
260 262
261 //**************************** 263 //****************************
262 // install trace 264 // install trace