aboutsummaryrefslogtreecommitdiffstats
path: root/src/fbuilder
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2017-09-16 08:49:05 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2017-09-16 08:49:05 -0400
commit280f37eba89ebc211d0c02848d3d47d086458b25 (patch)
tree1398c5dfc53c4d286d7b6b528d5a3c1585a67325 /src/fbuilder
parentMerge pull request #1552 from SpotComms/mf (diff)
downloadfirejail-280f37eba89ebc211d0c02848d3d47d086458b25.tar.gz
firejail-280f37eba89ebc211d0c02848d3d47d086458b25.tar.zst
firejail-280f37eba89ebc211d0c02848d3d47d086458b25.zip
--build
Diffstat (limited to 'src/fbuilder')
-rw-r--r--src/fbuilder/Makefile.in45
-rw-r--r--src/fbuilder/build_fs.c276
-rw-r--r--src/fbuilder/build_home.c199
-rw-r--r--src/fbuilder/build_profile.c165
-rw-r--r--src/fbuilder/build_seccomp.c191
-rw-r--r--src/fbuilder/fbuilder.h65
-rw-r--r--src/fbuilder/filedb.c79
-rw-r--r--src/fbuilder/main.c71
-rw-r--r--src/fbuilder/utils.c72
9 files changed, 1163 insertions, 0 deletions
diff --git a/src/fbuilder/Makefile.in b/src/fbuilder/Makefile.in
new file mode 100644
index 000000000..dd8e2ce6e
--- /dev/null
+++ b/src/fbuilder/Makefile.in
@@ -0,0 +1,45 @@
1all: fbuilder
2
3CC=@CC@
4prefix=@prefix@
5exec_prefix=@exec_prefix@
6libdir=@libdir@
7sysconfdir=@sysconfdir@
8
9VERSION=@PACKAGE_VERSION@
10NAME=@PACKAGE_NAME@
11HAVE_SECCOMP_H=@HAVE_SECCOMP_H@
12HAVE_SECCOMP=@HAVE_SECCOMP@
13HAVE_CHROOT=@HAVE_CHROOT@
14HAVE_BIND=@HAVE_BIND@
15HAVE_FATAL_WARNINGS=@HAVE_FATAL_WARNINGS@
16HAVE_NETWORK=@HAVE_NETWORK@
17HAVE_USERNS=@HAVE_USERNS@
18HAVE_X11=@HAVE_X11@
19HAVE_FILE_TRANSFER=@HAVE_FILE_TRANSFER@
20HAVE_WHITELIST=@HAVE_WHITELIST@
21HAVE_GLOBALCFG=@HAVE_GLOBALCFG@
22HAVE_APPARMOR=@HAVE_APPARMOR@
23HAVE_OVERLAYFS=@HAVE_OVERLAYFS@
24HAVE_PRIVATE_HOME=@HAVE_PRIVATE_HOME@
25EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
26HAVE_GCOV=@HAVE_GCOV@
27EXTRA_LDFLAGS +=@EXTRA_LDFLAGS@
28
29H_FILE_LIST = $(sort $(wildcard *.[h]))
30C_FILE_LIST = $(sort $(wildcard *.c))
31OBJS = $(C_FILE_LIST:.c=.o)
32BINOBJS = $(foreach file, $(OBJS), $file)
33CFLAGS += -ggdb $(HAVE_FATAL_WARNINGS) -O2 -DVERSION='"$(VERSION)"' $(HAVE_GCOV) -DPREFIX='"$(prefix)"' -DSYSCONFDIR='"$(sysconfdir)/firejail"' -DLIBDIR='"$(libdir)"' $(HAVE_X11) $(HAVE_PRIVATE_HOME) $(HAVE_APPARMOR) $(HAVE_OVERLAYFS) $(HAVE_SECCOMP) $(HAVE_GLOBALCFG) $(HAVE_SECCOMP_H) $(HAVE_CHROOT) $(HAVE_NETWORK) $(HAVE_USERNS) $(HAVE_BIND) $(HAVE_FILE_TRANSFER) $(HAVE_WHITELIST) -fstack-protector-all -D_FORTIFY_SOURCE=2 -fPIE -pie -Wformat -Wformat-security
34LDFLAGS += -pie -Wl,-z,relro -Wl,-z,now -lpthread
35
36%.o : %.c $(H_FILE_LIST) ../include/common.h ../include/syscall.h
37 $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
38
39fbuilder: $(OBJS)
40 $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(EXTRA_LDFLAGS)
41
42clean:; rm -f *.o fbuilder *.gcov *.gcda *.gcno
43
44distclean: clean
45 rm -fr Makefile
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c
new file mode 100644
index 000000000..76281a54d
--- /dev/null
+++ b/src/fbuilder/build_fs.c
@@ -0,0 +1,276 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22
23// common file processing function, using the callback for each line in the file
24static void process_file(const char *fname, const char *dir, void (*callback)(char *)) {
25 assert(fname);
26 assert(dir);
27 assert(callback);
28
29 int dir_len = strlen(dir);
30
31 // process trace file
32 FILE *fp = fopen(fname, "r");
33 if (!fp) {
34 fprintf(stderr, "Error: cannot open %s\n", fname);
35 exit(1);
36 }
37
38 char buf[MAX_BUF];
39 while (fgets(buf, MAX_BUF, fp)) {
40 // remove \n
41 char *ptr = strchr(buf, '\n');
42 if (ptr)
43 *ptr = '\0';
44
45 // parse line: 4:galculator:access /etc/fonts/conf.d:0
46 // number followed by :
47 ptr = buf;
48 if (!isdigit(*ptr))
49 continue;
50 while (isdigit(*ptr))
51 ptr++;
52 if (*ptr != ':')
53 continue;
54 ptr++;
55
56 // next :
57 ptr = strchr(ptr, ':');
58 if (!ptr)
59 continue;
60 ptr++;
61 if (strncmp(ptr, "access ", 7) == 0)
62 ptr += 7;
63 else if (strncmp(ptr, "fopen ", 6) == 0)
64 ptr += 6;
65 else if (strncmp(ptr, "fopen64 ", 8) == 0)
66 ptr += 8;
67 else if (strncmp(ptr, "open64 ", 7) == 0)
68 ptr += 7;
69 else if (strncmp(ptr, "open ", 5) == 0)
70 ptr += 5;
71 else
72 continue;
73 if (strncmp(ptr, dir, dir_len) != 0)
74 continue;
75
76 // end of filename
77 char *ptr2 = strchr(ptr, ':');
78 if (!ptr2)
79 continue;
80 *ptr2 = '\0';
81
82 callback(ptr);
83 }
84
85 fclose(fp);
86}
87
88// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
89static void process_files(const char *fname, const char *dir, void (*callback)(char *)) {
90 assert(fname);
91 assert(dir);
92 assert(callback);
93
94 // run fname
95 process_file(fname, dir, callback);
96
97 // run all the rest
98 struct stat s;
99 int i;
100 for (i = 1; i <= 5; i++) {
101 char *newname;
102 if (asprintf(&newname, "%s.%d", fname, i) == -1)
103 errExit("asprintf");
104 if (stat(newname, &s) == 0)
105 process_file(newname, dir, callback);
106 free(newname);
107 }
108}
109
110//*******************************************
111// etc directory
112//*******************************************
113static FileDB *etc_out = NULL;
114
115static void etc_callback(char *ptr) {
116 // skip firejail directory
117 if (strncmp(ptr, "/etc/firejail", 13) == 0)
118 return;
119
120 // add only top files and directories
121 ptr += 5; // skip "/etc/"
122 char *end = strchr(ptr, '/');
123 if (end)
124 *end = '\0';
125 etc_out = filedb_add(etc_out, ptr);
126}
127
128void build_etc(const char *fname) {
129 assert(fname);
130
131 process_files(fname, "/etc", etc_callback);
132
133 printf("private-etc ");
134 if (etc_out == NULL)
135 printf("none\n");
136 else {
137 FileDB *ptr = etc_out;
138 while (ptr) {
139 printf("%s,", ptr->fname);
140 ptr = ptr->next;
141 }
142 printf("\n");
143 }
144}
145
146//*******************************************
147// var directory
148//*******************************************
149static FileDB *var_out = NULL;
150static void var_callback(char *ptr) {
151 if (strncmp(ptr, "/var/lib/menu-xdg", 17) == 0)
152 var_out = filedb_add(var_out, "/var/lib/menu-xdg");
153 else if (strncmp(ptr, "/var/cache/fontconfig", 21) == 0)
154 var_out = filedb_add(var_out, "/var/cache/fontconfig");
155 else
156 var_out = filedb_add(var_out, ptr);
157}
158
159void build_var(const char *fname) {
160 assert(fname);
161
162 process_files(fname, "/var", var_callback);
163
164 if (var_out == NULL)
165 printf("blacklist /var\n");
166 else
167 filedb_print(var_out, "whitelist ");
168}
169
170//*******************************************
171// tmp directory
172//*******************************************
173static FileDB *tmp_out = NULL;
174static void tmp_callback(char *ptr) {
175 filedb_add(tmp_out, ptr);
176}
177
178void build_tmp(const char *fname) {
179 assert(fname);
180
181 process_files(fname, "/tmp", tmp_callback);
182
183 if (tmp_out == NULL)
184 printf("private-tmp\n");
185 else {
186 printf("\n");
187 printf("# private-tmp\n");
188 printf("# File accessed in /tmp directory:\n");
189 printf("# ");
190 FileDB *ptr = tmp_out;
191 while (ptr) {
192 printf("%s,", ptr->fname);
193 ptr = ptr->next;
194 }
195 printf("\n");
196 }
197}
198
199//*******************************************
200// dev directory
201//*******************************************
202static char *dev_skip[] = {
203 "/dev/zero",
204 "/dev/null",
205 "/dev/full",
206 "/dev/random",
207 "/dev/urandom",
208 "/dev/tty",
209 "/dev/snd",
210 "/dev/dri",
211 "/dev/pts",
212 "/dev/nvidia0",
213 "/dev/nvidia1",
214 "/dev/nvidia2",
215 "/dev/nvidia3",
216 "/dev/nvidia4",
217 "/dev/nvidia5",
218 "/dev/nvidia6",
219 "/dev/nvidia7",
220 "/dev/nvidia8",
221 "/dev/nvidia9",
222 "/dev/nvidiactl",
223 "/dev/nvidia-modeset",
224 "/dev/nvidia-uvm",
225 "/dev/video0",
226 "/dev/video1",
227 "/dev/video2",
228 "/dev/video3",
229 "/dev/video4",
230 "/dev/video5",
231 "/dev/video6",
232 "/dev/video7",
233 "/dev/video8",
234 "/dev/video9",
235 "/dev/dvb",
236 "/dev/sr0",
237 NULL
238};
239
240static FileDB *dev_out = NULL;
241static void dev_callback(char *ptr) {
242 // skip private-dev devices
243 int i = 0;
244 int found = 0;
245 while (dev_skip[i]) {
246 if (strcmp(ptr, dev_skip[i]) == 0) {
247 found = 1;
248 break;
249 }
250 i++;
251 }
252 if (!found)
253 filedb_add(dev_out, ptr);
254}
255
256void build_dev(const char *fname) {
257 assert(fname);
258
259 process_files(fname, "/tmp", tmp_callback);
260
261 if (dev_out == NULL)
262 printf("private-dev\n");
263 else {
264 printf("\n");
265 printf("# private-dev\n");
266 printf("# This is the list of devices accessed (on top of regular private-dev devices:\n");
267 printf("# ");
268 FileDB *ptr = dev_out;
269 while (ptr) {
270 printf("%s,", ptr->fname);
271 ptr = ptr->next;
272 }
273 printf("\n");
274 }
275}
276
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c
new file mode 100644
index 000000000..947f172d8
--- /dev/null
+++ b/src/fbuilder/build_home.c
@@ -0,0 +1,199 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22
23static FileDB *db_skip = NULL;
24static FileDB *db_out = NULL;
25
26static void load_whitelist_common(void) {
27 FILE *fp = fopen("/etc/firejail/whitelist-common.inc", "r");
28 if (!fp) {
29 fprintf(stderr, "Error: cannot open whitelist-common.inc\n");
30 exit(1);
31 }
32
33 char buf[MAX_BUF];
34 while (fgets(buf, MAX_BUF, fp)) {
35 if (strncmp(buf, "whitelist ~/", 12) != 0)
36 continue;
37 char *fn = buf + 12;
38 char *ptr = strchr(buf, '\n');
39 if (!ptr)
40 continue;
41 *ptr = '\0';
42
43 // add the file to skip list
44 db_skip = filedb_add(db_skip, fn);
45 }
46
47 fclose(fp);
48}
49
50void process_home(const char *fname, char *home, int home_len) {
51 assert(fname);
52 assert(home);
53 assert(home_len);
54
55 // process trace file
56 FILE *fp = fopen(fname, "r");
57 if (!fp) {
58 fprintf(stderr, "Error: cannot open %s\n", fname);
59 exit(1);
60 }
61
62 char buf[MAX_BUF];
63 while (fgets(buf, MAX_BUF, fp)) {
64 // remove \n
65 char *ptr = strchr(buf, '\n');
66 if (ptr)
67 *ptr = '\0';
68
69 // parse line: 4:galculator:access /etc/fonts/conf.d:0
70 // number followed by :
71 ptr = buf;
72 if (!isdigit(*ptr))
73 continue;
74 while (isdigit(*ptr))
75 ptr++;
76 if (*ptr != ':')
77 continue;
78 ptr++;
79
80 // next :
81 ptr = strchr(ptr, ':');
82 if (!ptr)
83 continue;
84 ptr++;
85 if (strncmp(ptr, "access /home", 12) == 0)
86 ptr += 7;
87 else if (strncmp(ptr, "fopen /home", 11) == 0)
88 ptr += 6;
89 else if (strncmp(ptr, "fopen64 /home", 13) == 0)
90 ptr += 8;
91 else if (strncmp(ptr, "open64 /home", 12) == 0)
92 ptr += 7;
93 else if (strncmp(ptr, "open /home", 10) == 0)
94 ptr += 5;
95 else
96 continue;
97
98 // end of filename
99 char *ptr2 = strchr(ptr, ':');
100 if (!ptr2)
101 continue;
102 *ptr2 = '\0';
103
104 // check home directory
105 if (strncmp(ptr, home, home_len) != 0)
106 continue;
107 if (strcmp(ptr, home) == 0)
108 continue;
109 ptr += home_len + 1;
110
111 // skip files handled automatically by firejail
112 if (strcmp(ptr, ".Xauthority") == 0 ||
113 strcmp(ptr, ".Xdefaults-debian") == 0 ||
114 strncmp(ptr, ".config/pulse/", 13) == 0 ||
115 strncmp(ptr, ".pulse/", 7) == 0 ||
116 strncmp(ptr, ".bash_hist", 10) == 0 ||
117 strcmp(ptr, ".bashrc") == 0)
118 continue;
119
120
121 // try to find the relevant directory for this file
122 char *dir = extract_dir(ptr);
123 char *toadd = (dir)? dir: ptr;
124
125 // skip some dot directories
126 if (strcmp(toadd, ".config") == 0 ||
127 strcmp(toadd, ".local") == 0 ||
128 strcmp(toadd, ".local/share") == 0 ||
129 strcmp(toadd, ".cache") == 0) {
130 if (dir)
131 free(dir);
132 continue;
133 }
134
135 // clean .cache entries
136 if (strncmp(toadd, ".cache/", 7) == 0) {
137 char *ptr2 = toadd + 7;
138 ptr2 = strchr(ptr2, '/');
139 if (ptr2)
140 *ptr2 = '\0';
141 }
142
143 // skip files and directories in whitelist-common.inc
144 if (filedb_find(db_skip, toadd)) {
145 if (dir)
146 free(dir);
147 continue;
148 }
149
150 // add the file to out list
151 db_out = filedb_add(db_out, toadd);
152 if (dir)
153 free(dir);
154
155 }
156 fclose(fp);
157}
158
159
160// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
161void build_home(const char *fname) {
162 assert(fname);
163
164 // load whitelist common
165 load_whitelist_common();
166
167 // find user home directory
168 struct passwd *pw = getpwuid(getuid());
169 if (!pw)
170 errExit("getpwuid");
171 char *home = pw->pw_dir;
172 if (!home)
173 errExit("getpwuid");
174 int home_len = strlen(home);
175
176 // run fname
177 process_home(fname, home, home_len);
178
179 // run all the rest
180 struct stat s;
181 int i;
182 for (i = 1; i <= 5; i++) {
183 char *newname;
184 if (asprintf(&newname, "%s.%d", fname, i) == -1)
185 errExit("asprintf");
186 if (stat(newname, &s) == 0)
187 process_home(newname, home, home_len);
188 free(newname);
189 }
190
191 // print the out list if any
192 if (db_out) {
193 filedb_print(db_out, "whitelist ~/");
194 printf("include /etc/firejail/whitelist-common.inc\n");
195 }
196 else
197 printf("private\n");
198
199} \ No newline at end of file
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c
new file mode 100644
index 000000000..5fca22648
--- /dev/null
+++ b/src/fbuilder/build_profile.c
@@ -0,0 +1,165 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22#include <sys/wait.h>
23#include <fcntl.h>
24
25#define TRACE_OUTPUT "/tmp/firejail-trace"
26#define STRACE_OUTPUT "/tmp/firejail-strace"
27
28static char *cmdlist[] = {
29 "/usr/bin/firejail",
30 "--quiet",
31 "--output=" TRACE_OUTPUT,
32 "--noprofile",
33 "--caps.drop=all",
34 "--nonewprivs",
35 "--trace",
36 "/usr/bin/strace", // also used as a marker in build_profile()
37 "-c",
38 "-f",
39 "-o" STRACE_OUTPUT,
40};
41
42static void clear_tmp_files(void) {
43 unlink(STRACE_OUTPUT);
44 unlink(TRACE_OUTPUT);
45
46 // run all the rest
47 int i;
48 for (i = 1; i <= 5; i++) {
49 char *newname;
50 if (asprintf(&newname, "%s.%d", TRACE_OUTPUT, i) == -1)
51 errExit("asprintf");
52 unlink(newname);
53 free(newname);
54 }
55
56}
57
58void build_profile(int argc, char **argv, int index) {
59 unlink("/tmp/strace-output");
60
61 // next index is the application name
62 if (index >= argc) {
63 fprintf(stderr, "Error: application name missing\n");
64 exit(1);
65 }
66
67 // clean /tmp files
68 clear_tmp_files();
69
70 // detect strace
71 int have_strace = 0;
72 if (access("/usr/bin/strace", X_OK) == 0)
73 have_strace = 1;
74
75 // calculate command length
76 int len = (int) sizeof(cmdlist) / sizeof(char*) + argc - index + 1;
77 if (arg_debug)
78 printf("command len %d + %d + 1\n", (int) (sizeof(cmdlist) / sizeof(char*)), argc - index);
79 char *cmd[len];
80
81 // build command
82 int i = 0;
83 for (i = 0; i < (int) sizeof(cmdlist) / sizeof(char*); i++) {
84 // skip strace if not installed
85 if (have_strace == 0 && strcmp(cmdlist[i], "/usr/bin/strace") == 0)
86 break;
87 cmd[i] = cmdlist[i];
88 }
89
90 int i2 = index;
91 for (; i < (len - 1); i++, i2++)
92 cmd[i] = argv[i2];
93 cmd[i] = NULL;
94
95 if (arg_debug) {
96 for (i = 0; i < len; i++)
97 printf("\t%s\n", cmd[i]);
98 }
99
100 // fork and execute
101 pid_t child = fork();
102 if (child == -1)
103 errExit("fork");
104 if (child == 0) {
105 int rv = execvp(cmd[0], cmd);
106 errExit("execv");
107 }
108
109 // wait for all processes to finish
110 int status;
111 if (waitpid(child, &status, 0) != child)
112 errExit("waitpid");
113
114 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
115 printf("\n\n\n");
116 printf("############################################\n");
117 printf("# %s profile\n", argv[index]);
118 printf("############################################\n");
119 printf("# Persistent global definitions\n");
120 printf("# include /etc/firejail/globals.local\n");
121 printf("\n");
122
123 printf("### basic blacklisting\n");
124 printf("include /etc/firejail/disable-common.inc\n");
125 printf("# include /etc/firejail/disable-devel.inc\n");
126 printf("include /etc/firejail/disable-passwdmgr.inc\n");
127 printf("# include /etc/firejail/disable-programs.inc\n");
128 printf("\n");
129
130 printf("### home directory whitelisting\n");
131 build_home(TRACE_OUTPUT);
132 printf("\n");
133
134 printf("### filesystem\n");
135 build_tmp(TRACE_OUTPUT);
136 build_dev(TRACE_OUTPUT);
137 build_etc(TRACE_OUTPUT);
138 build_var(TRACE_OUTPUT);
139 printf("\n");
140
141 printf("### security filters\n");
142 printf("caps.drop all\n");
143 printf("nonewprivs\n");
144 printf("seccomp\n");
145 if (have_strace)
146 build_seccomp(STRACE_OUTPUT);
147 else {
148 printf("# If you install strace on your system, Firejail will also create a\n");
149 printf("# whitelisted seccomp filter.\n");
150 }
151 printf("\n");
152
153 printf("### network\n");
154 build_protocol(TRACE_OUTPUT);
155 printf("\n");
156
157 printf("### environment\n");
158 printf("shell none\n");
159
160 }
161 else {
162 fprintf(stderr, "Error: cannot run the sandbox\n");
163 exit(1);
164 }
165}
diff --git a/src/fbuilder/build_seccomp.c b/src/fbuilder/build_seccomp.c
new file mode 100644
index 000000000..18a767518
--- /dev/null
+++ b/src/fbuilder/build_seccomp.c
@@ -0,0 +1,191 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22
23void build_seccomp(const char *fname) {
24 assert(fname);
25
26 FILE *fp = fopen(fname, "r");
27 if (!fp) {
28 fprintf(stderr, "Error: cannot open %s\n", fname);
29 exit(1);
30 }
31
32 char buf[MAX_BUF];
33 int line = 1;
34 int position = 0;
35 int cnt = 0;
36 while (fgets(buf, MAX_BUF, fp)) {
37 // remove \n
38 char *ptr = strchr(buf, '\n');
39 if (ptr)
40 *ptr = '\0';
41
42 // first line:
43 //% time seconds usecs/call calls errors syscall
44 if (line == 1) {
45 // extract syscall position
46 ptr = strstr(buf, "syscall");
47 if (*buf != '%' || ptr == NULL) {
48 // skip this line, it could be garbage from strace
49 continue;
50 }
51 position = (int) (ptr - buf);
52 }
53 else if (line == 2) {
54 if (*buf != '-') {
55 fprintf(stderr, "Error: invalid strace output\n%s\n", buf);
56 exit(1);
57 }
58 }
59 else {
60 // get out on the next "----" line
61 if (*buf == '-')
62 break;
63
64 if (line == 3)
65 printf("# seccomp.keep %s", buf + position);
66 else
67 printf(",%s", buf + position);
68 cnt++;
69 }
70 line++;
71 }
72 printf("\n");
73 printf("# %d syscalls total\n", cnt);
74 printf("# Probably you will need to add more syscalls to seccomp.keep. Look for\n");
75 printf("# seccomp errors in /var/log/syslog or /var/log/audit/audit.log while\n");
76 printf("# running your sandbox.\n");
77
78 fclose(fp);
79}
80
81//***************************************
82// protocol
83//***************************************
84int unix_s = 0;
85int inet = 0;
86int inet6 = 0;
87int netlink = 0;
88int packet = 0;
89static void process_protocol(const char *fname) {
90 assert(fname);
91
92 // process trace file
93 FILE *fp = fopen(fname, "r");
94 if (!fp) {
95 fprintf(stderr, "Error: cannot open %s\n", fname);
96 exit(1);
97 }
98
99 char buf[MAX_BUF];
100 while (fgets(buf, MAX_BUF, fp)) {
101 // remove \n
102 char *ptr = strchr(buf, '\n');
103 if (ptr)
104 *ptr = '\0';
105
106 // parse line: 4:galculator:access /etc/fonts/conf.d:0
107 // number followed by :
108 ptr = buf;
109 if (!isdigit(*ptr))
110 continue;
111 while (isdigit(*ptr))
112 ptr++;
113 if (*ptr != ':')
114 continue;
115 ptr++;
116
117 // next :
118 ptr = strchr(ptr, ':');
119 if (!ptr)
120 continue;
121 ptr++;
122 if (strncmp(ptr, "socket ", 7) == 0)
123 ptr += 7;
124 else
125 continue;
126
127 if (strncmp(ptr, "AF_LOCAL ", 9) == 0)
128 unix_s = 1;
129 else if (strncmp(ptr, "AF_INET ", 8) == 0)
130 inet = 1;
131 else if (strncmp(ptr, "AF_INET6 ", 9) == 0)
132 inet6 = 1;
133 else if (strncmp(ptr, "AF_NETLINK ", 9) == 0)
134 netlink = 1;
135 else if (strncmp(ptr, "AF_PACKET ", 9) == 0)
136 packet = 1;
137 }
138
139 fclose(fp);
140}
141
142
143// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
144void build_protocol(const char *fname) {
145 assert(fname);
146
147 // run fname
148 process_protocol(fname);
149
150 // run all the rest
151 struct stat s;
152 int i;
153 for (i = 1; i <= 5; i++) {
154 char *newname;
155 if (asprintf(&newname, "%s.%d", fname, i) == -1)
156 errExit("asprintf");
157 if (stat(newname, &s) == 0)
158 process_protocol(newname);
159 free(newname);
160 }
161
162 int net = 0;
163 if (unix_s || inet || inet6 || netlink || packet) {
164 printf("protocol ");
165 if (unix_s)
166 printf("unix,");
167 if (inet) {
168 printf("inet,");
169 net = 1;
170 }
171 if (inet6) {
172 printf("inet6,");
173 net = 1;
174 }
175 if (netlink)
176 printf("netlink,");
177 if (packet) {
178 printf("packet");
179 net = 1;
180 }
181 printf("\n");
182 }
183
184 if (net == 0)
185 printf("net none\n");
186 else {
187 printf("# net eth0\n");
188 printf("netfilter\n");
189 }
190}
191
diff --git a/src/fbuilder/fbuilder.h b/src/fbuilder/fbuilder.h
new file mode 100644
index 000000000..a9049ea2d
--- /dev/null
+++ b/src/fbuilder/fbuilder.h
@@ -0,0 +1,65 @@
1/*
2 * Copyright (C) 2014-2017 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
21#ifndef FBUILDER_H
22#define FBUILDER_H
23#include "../include/common.h"
24#include <sys/types.h>
25#include <pwd.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28
29
30#define MAX_BUF 4096
31// main.c
32extern int arg_debug;
33
34// build_profile.c
35void build_profile(int argc, char **argv, int index);
36
37// build_seccomp.c
38void build_seccomp(const char *fname);
39void build_protocol(const char *fname);
40
41// build_fs.c
42void build_etc(const char *fname);
43void build_var(const char *fname);
44void build_tmp(const char *fname);
45void build_dev(const char *fname);
46
47// build_home.c
48void build_home(const char *fname);
49
50// utils.c
51int is_dir(const char *fname);
52char *extract_dir(char *fname);
53
54// filedb.c
55typedef struct filedb_t {
56 struct filedb_t *next;
57 char *fname; // file name
58 int len; // length of file name
59} FileDB;
60
61FileDB *filedb_add(FileDB *head, const char *fname);
62FileDB *filedb_find(FileDB *head, const char *fname);
63void filedb_print(FileDB *head, const char *prefix);
64
65#endif \ No newline at end of file
diff --git a/src/fbuilder/filedb.c b/src/fbuilder/filedb.c
new file mode 100644
index 000000000..a76fbc961
--- /dev/null
+++ b/src/fbuilder/filedb.c
@@ -0,0 +1,79 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22
23FileDB *filedb_find(FileDB *head, const char *fname) {
24 FileDB *ptr = head;
25 int found = 0;
26 int len = strlen(fname);
27
28 while (ptr) {
29 // exact name
30 if (strcmp(fname, ptr->fname) == 0) {
31 found = 1;
32 break;
33 }
34
35 // parent directory in the list
36 if (len > ptr->len &&
37 fname[ptr->len] == '/' &&
38 strncmp(ptr->fname, fname, ptr->len) == 0) {
39 found = 1;
40 break;
41 }
42
43 ptr = ptr->next;
44 }
45
46 if (found)
47 return ptr;
48
49 return NULL;
50}
51
52FileDB *filedb_add(FileDB *head, const char *fname) {
53 assert(fname);
54
55 // don't add it if it is already there or if the parent directory is already in the list
56 if (filedb_find(head, fname))
57 return head;
58
59 // add a new entry
60 FileDB *entry = malloc(sizeof(FileDB));
61 if (!entry)
62 errExit("malloc");
63 memset(entry, 0, sizeof(FileDB));
64 entry->fname = strdup(fname);
65 if (!entry->fname)
66 errExit("strdup");
67 entry->len = strlen(entry->fname);
68 entry->next = head;
69 return entry;
70};
71
72void filedb_print(FileDB *head, const char *prefix) {
73 FileDB *ptr = head;
74 while (ptr) {
75 printf("%s%s\n", prefix, ptr->fname);
76 ptr = ptr->next;
77 }
78}
79
diff --git a/src/fbuilder/main.c b/src/fbuilder/main.c
new file mode 100644
index 000000000..83217ef98
--- /dev/null
+++ b/src/fbuilder/main.c
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2014-2017 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 "fbuilder.h"
21int arg_debug = 0;
22
23static void usage(void) {
24 printf("Firejail profile builder\n");
25 printf("Usage: firejail [--debug] --build program-and-arguments\n");
26}
27
28int main(int argc, char **argv) {
29#if 0
30{
31system("cat /proc/self/status");
32int i;
33for (i = 0; i < argc; i++)
34 printf("*%s* ", argv[i]);
35printf("\n");
36}
37#endif
38
39 int i;
40 int prog_index = 0;
41
42 // parse arguments and extract program index
43 for (i = 1; i < argc; i++) {
44 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-?") ==0) {
45 usage();
46 return 0;
47 }
48 else if (strcmp(argv[i], "--debug") == 0)
49 arg_debug = 1;
50 else if (strcmp(argv[i], "--build") == 0)
51 ; // do nothing, this is passed down from firejail
52 else {
53 if (*argv[i] == '-') {
54 fprintf(stderr, "Error fbuilder: invalid program\n");
55 usage();
56 exit(1);
57 }
58 prog_index = i;
59 break;
60 }
61 }
62
63 if (prog_index == 0) {
64 fprintf(stderr, "Error fbuilder: program and arguments required\n");
65 usage();
66 exit(1);
67 }
68
69 build_profile(argc, argv, prog_index);
70 return 0;
71}
diff --git a/src/fbuilder/utils.c b/src/fbuilder/utils.c
new file mode 100644
index 000000000..902290899
--- /dev/null
+++ b/src/fbuilder/utils.c
@@ -0,0 +1,72 @@
1/*
2 * Copyright (C) 2014-2017 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
21#include "fbuilder.h"
22
23// todo: duplicated from src/firejail/util.c - remove dplication
24// return 1 if the file is a directory
25int is_dir(const char *fname) {
26 assert(fname);
27 if (*fname == '\0')
28 return 0;
29
30 // if fname doesn't end in '/', add one
31 int rv;
32 struct stat s;
33 if (fname[strlen(fname) - 1] == '/')
34 rv = stat(fname, &s);
35 else {
36 char *tmp;
37 if (asprintf(&tmp, "%s/", fname) == -1) {
38 fprintf(stderr, "Error: cannot allocate memory, %s:%d\n", __FILE__, __LINE__);
39 errExit("asprintf");
40 }
41 rv = stat(tmp, &s);
42 free(tmp);
43 }
44
45 if (rv == -1)
46 return 0;
47
48 if (S_ISDIR(s.st_mode))
49 return 1;
50
51 return 0;
52}
53
54// return NULL if fname is already a directory, or if no directory found
55char *extract_dir(char *fname) {
56 assert(fname);
57 if (is_dir(fname))
58 return NULL;
59
60 char *name = strdup(fname);
61 if (!name)
62 errExit("strdup");
63
64 char *ptr = strrchr(name, '/');
65 if (!ptr) {
66 free(name);
67 return NULL;
68 }
69 *ptr = '\0';
70
71 return name;
72}