aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md14
-rw-r--r--RELNOTES20
-rw-r--r--src/fbuilder/build_bin.c10
-rw-r--r--src/fbuilder/build_fs.c52
-rw-r--r--src/fbuilder/build_home.c8
-rw-r--r--src/fbuilder/build_profile.c74
-rw-r--r--src/fbuilder/build_seccomp.c47
-rw-r--r--src/fbuilder/fbuilder.h22
-rw-r--r--src/fbuilder/filedb.c4
-rw-r--r--src/fbuilder/main.c26
-rw-r--r--src/firejail/main.c32
-rw-r--r--src/firejail/usage.c1
-rw-r--r--src/man/firejail.txt16
13 files changed, 199 insertions, 127 deletions
diff --git a/README.md b/README.md
index 549d3fdc4..d69e6d89b 100644
--- a/README.md
+++ b/README.md
@@ -98,14 +98,23 @@ Use this issue to request new profiles: [#1139](https://github.com/netblue30/fir
98````` 98`````
99# Current development version: 0.9.51 99# Current development version: 0.9.51
100 100
101## Whitelisting /var 101## Whitelisting, globbing etc.
102 102
103Add "include /etc/firejail/whitelist-var-common.inc" to an application profile and test it. If it's working, 103Add "include /etc/firejail/whitelist-var-common.inc" to an application profile and test it. If it's working,
104send a pull request. I did it so far for some more common applications like Firefox, Chromium etc. 104send a pull request. I did it so far for some more common applications like Firefox, Chromium etc.
105 105
106Added globbing support for --private-bin. Added whitlisting support for /etc and /usr/share.
107
108--private-lib was enhanced to autodetect GTK2, GTK3 and Qt4 libraries. We do a test run with this option enabled
109for the following applications: evince, galculator, gnome-calculator,
110 leafpad, mousepad, transmission-gtk, xcalc, xmr-stak-cpu,
111 atril, mate-color-select, tar, file, strings, gpicview,
112 eom, eog, gedit, pluma
113
106## Profile build tool 114## Profile build tool
107````` 115`````
108$ firejail --build appname 116$ firejail --build appname
117$ firejail --build=appname.profile appname
109````` 118`````
110The command builds a whitelisted profile. If /usr/bin/strace is installed on the system, it also 119The command builds a whitelisted profile. If /usr/bin/strace is installed on the system, it also
111builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox, 120builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox,
@@ -182,3 +191,6 @@ imagej, karbon, kdenlive, krita, linphone, lmms, macrofusion, mpd, natron, Natro
182ricochet, shotcut, teamspeak3, tor, tor-browser-en, Viber, x-terminal-emulator, zart, 191ricochet, shotcut, teamspeak3, tor, tor-browser-en, Viber, x-terminal-emulator, zart,
183conky, arch-audit, ffmpeg, bluefish, cliqz, cinelerra, openshot-qt, pinta, uefitool, 192conky, arch-audit, ffmpeg, bluefish, cliqz, cinelerra, openshot-qt, pinta, uefitool,
184aosp, pdfmod, gnome-ring, signal-dekstop, xcalc, zaproxy 193aosp, pdfmod, gnome-ring, signal-dekstop, xcalc, zaproxy
194
195Upstreamed many profiles from the following sources: https://github.com/chiraag-nataraj/firejail-profiles,
196https://github.com/nyancat18/fe, and https://aur.archlinux.org/packages/firejail-profiles. \ No newline at end of file
diff --git a/RELNOTES b/RELNOTES
index 49ec862a1..9efcd5c55 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -6,7 +6,8 @@ firejail (0.9.51) baseline; urgency=low
6 * enhancement: support Firejail user config directory in firecfg 6 * enhancement: support Firejail user config directory in firecfg
7 * enhancement: disable DBus activation in firecfg 7 * enhancement: disable DBus activation in firecfg
8 * enhancement; enumerate root directories in apparmor profile 8 * enhancement; enumerate root directories in apparmor profile
9 * enhancement: enable private-lib in Firefox profile 9 * enhancement: /etc and /usr/share whitelisting support
10 * enhancement: globbing support for --private-bin
10 * feature: systemd-resolved integration 11 * feature: systemd-resolved integration
11 * feature: whitelisting /var directory in most profiles 12 * feature: whitelisting /var directory in most profiles
12 * feature: GTK2, GTK3 and Qt4 private-lib support 13 * feature: GTK2, GTK3 and Qt4 private-lib support
@@ -14,9 +15,24 @@ firejail (0.9.51) baseline; urgency=low
14 applications: evince, galculator, gnome-calculator, 15 applications: evince, galculator, gnome-calculator,
15 leafpad, mousepad, transmission-gtk, xcalc, xmr-stak-cpu, 16 leafpad, mousepad, transmission-gtk, xcalc, xmr-stak-cpu,
16 atril, mate-color-select, tar, file, strings, gpicview, 17 atril, mate-color-select, tar, file, strings, gpicview,
17 eom, eog 18 eom, eog, gedit, pluma
18 * feature: --writable-run-user 19 * feature: --writable-run-user
19 * feature: profile build tool (--build) 20 * feature: profile build tool (--build)
21 * new profiles: upstreamed many profiles from the following sources:
22 https://github.com/chiraag-nataraj/firejail-profiles,
23 https://github.com/nyancat18/fe,
24 https://aur.archlinux.org/packages/firejail-profiles.
25 * new profiles: terasology, surf, rocketchat, clamscan, clamdscan,
26 clamdtop, freshclam, xmr-stak-cpu, amule, ardour4, ardour5,
27 brackets, calligra, calligraauthor, calligraconverter, calligraflow,
28 calligraplan, calligraplanwork, calligrasheets, calligrastage,
29 calligrawords, cin, dooble, dooble-qt4, fetchmail, freecad, freecadcmd,
30 google-earth,imagej, karbon, kdenlive, krita, linphone, lmms, macrofusion,
31 mpd, natron, Natron, ricochet, shotcut, teamspeak3, tor, tor-browser-en,
32 Viber, x-terminal-emulator, zart, conky, arch-audit, ffmpeg, bluefish, cliqz,
33 cinelerra, openshot-qt, pinta, uefitool, aosp, pdfmod, gnome-ring, signal-dekstop,
34 xcalc, zaproxy
35
20 -- netblue30 <netblue30@yahoo.com> Thu, 14 Sep 2017 20:00:00 -0500 36 -- netblue30 <netblue30@yahoo.com> Thu, 14 Sep 2017 20:00:00 -0500
21 37
22firejail (0.9.50~rc1) baseline; urgency=low 38firejail (0.9.50~rc1) baseline; urgency=low
diff --git a/src/fbuilder/build_bin.c b/src/fbuilder/build_bin.c
index 6c173bfcc..fb92fb630 100644
--- a/src/fbuilder/build_bin.c
+++ b/src/fbuilder/build_bin.c
@@ -95,7 +95,7 @@ static void process_bin(const char *fname) {
95 95
96 96
97// process fname, fname.1, fname.2, fname.3, fname.4, fname.5 97// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
98void build_bin(const char *fname) { 98void build_bin(const char *fname, FILE *fp) {
99 assert(fname); 99 assert(fname);
100 100
101 // run fname 101 // run fname
@@ -114,13 +114,13 @@ void build_bin(const char *fname) {
114 } 114 }
115 115
116 if (bin_out) { 116 if (bin_out) {
117 printf("private-bin "); 117 fprintf(fp, "private-bin ");
118 FileDB *ptr = bin_out; 118 FileDB *ptr = bin_out;
119 while (ptr) { 119 while (ptr) {
120 printf("%s,", ptr->fname); 120 fprintf(fp, "%s,", ptr->fname);
121 ptr = ptr->next; 121 ptr = ptr->next;
122 } 122 }
123 printf("\n"); 123 fprintf(fp, "\n");
124 printf("# private-lib\n"); 124 fprintf(fp, "# private-lib\n");
125 } 125 }
126} 126}
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c
index 01104edb1..f1a27a35a 100644
--- a/src/fbuilder/build_fs.c
+++ b/src/fbuilder/build_fs.c
@@ -125,21 +125,21 @@ static void etc_callback(char *ptr) {
125 etc_out = filedb_add(etc_out, ptr); 125 etc_out = filedb_add(etc_out, ptr);
126} 126}
127 127
128void build_etc(const char *fname) { 128void build_etc(const char *fname, FILE *fp) {
129 assert(fname); 129 assert(fname);
130 130
131 process_files(fname, "/etc", etc_callback); 131 process_files(fname, "/etc", etc_callback);
132 132
133 printf("private-etc "); 133 fprintf(fp, "private-etc ");
134 if (etc_out == NULL) 134 if (etc_out == NULL)
135 printf("none\n"); 135 fprintf(fp, "none\n");
136 else { 136 else {
137 FileDB *ptr = etc_out; 137 FileDB *ptr = etc_out;
138 while (ptr) { 138 while (ptr) {
139 printf("%s,", ptr->fname); 139 fprintf(fp, "%s,", ptr->fname);
140 ptr = ptr->next; 140 ptr = ptr->next;
141 } 141 }
142 printf("\n"); 142 fprintf(fp, "\n");
143 } 143 }
144} 144}
145 145
@@ -160,15 +160,15 @@ static void var_callback(char *ptr) {
160 var_out = filedb_add(var_out, ptr); 160 var_out = filedb_add(var_out, ptr);
161} 161}
162 162
163void build_var(const char *fname) { 163void build_var(const char *fname, FILE *fp) {
164 assert(fname); 164 assert(fname);
165 165
166 process_files(fname, "/var", var_callback); 166 process_files(fname, "/var", var_callback);
167 167
168 if (var_out == NULL) 168 if (var_out == NULL)
169 printf("blacklist /var\n"); 169 fprintf(fp, "blacklist /var\n");
170 else 170 else
171 filedb_print(var_out, "whitelist "); 171 filedb_print(var_out, "whitelist ", fp);
172} 172}
173 173
174 174
@@ -197,15 +197,15 @@ static void share_callback(char *ptr) {
197 share_out = filedb_add(share_out, ptr); 197 share_out = filedb_add(share_out, ptr);
198} 198}
199 199
200void build_share(const char *fname) { 200void build_share(const char *fname, FILE *fp) {
201 assert(fname); 201 assert(fname);
202 202
203 process_files(fname, "/usr/share", share_callback); 203 process_files(fname, "/usr/share", share_callback);
204 204
205 if (share_out == NULL) 205 if (share_out == NULL)
206 printf("blacklist /usr/share\n"); 206 fprintf(fp, "blacklist /usr/share\n");
207 else 207 else
208 filedb_print(share_out, "whitelist "); 208 filedb_print(share_out, "whitelist ", fp);
209} 209}
210 210
211//******************************************* 211//*******************************************
@@ -216,21 +216,21 @@ static void tmp_callback(char *ptr) {
216 filedb_add(tmp_out, ptr); 216 filedb_add(tmp_out, ptr);
217} 217}
218 218
219void build_tmp(const char *fname) { 219void build_tmp(const char *fname, FILE *fp) {
220 assert(fname); 220 assert(fname);
221 221
222 process_files(fname, "/tmp", tmp_callback); 222 process_files(fname, "/tmp", tmp_callback);
223 223
224 if (tmp_out == NULL) 224 if (tmp_out == NULL)
225 printf("private-tmp\n"); 225 fprintf(fp, "private-tmp\n");
226 else { 226 else {
227 printf("\n"); 227 fprintf(fp, "\n");
228 printf("# private-tmp\n"); 228 fprintf(fp, "# private-tmp\n");
229 printf("# File accessed in /tmp directory:\n"); 229 fprintf(fp, "# File accessed in /tmp directory:\n");
230 printf("# "); 230 fprintf(fp, "# ");
231 FileDB *ptr = tmp_out; 231 FileDB *ptr = tmp_out;
232 while (ptr) { 232 while (ptr) {
233 printf("%s,", ptr->fname); 233 fprintf(fp, "%s,", ptr->fname);
234 ptr = ptr->next; 234 ptr = ptr->next;
235 } 235 }
236 printf("\n"); 236 printf("\n");
@@ -294,24 +294,24 @@ static void dev_callback(char *ptr) {
294 filedb_add(dev_out, ptr); 294 filedb_add(dev_out, ptr);
295} 295}
296 296
297void build_dev(const char *fname) { 297void build_dev(const char *fname, FILE *fp) {
298 assert(fname); 298 assert(fname);
299 299
300 process_files(fname, "/dev", dev_callback); 300 process_files(fname, "/dev", dev_callback);
301 301
302 if (dev_out == NULL) 302 if (dev_out == NULL)
303 printf("private-dev\n"); 303 fprintf(fp, "private-dev\n");
304 else { 304 else {
305 printf("\n"); 305 fprintf(fp, "\n");
306 printf("# private-dev\n"); 306 fprintf(fp, "# private-dev\n");
307 printf("# This is the list of devices accessed (on top of regular private-dev devices:\n"); 307 fprintf(fp, "# This is the list of devices accessed (on top of regular private-dev devices:\n");
308 printf("# "); 308 fprintf(fp, "# ");
309 FileDB *ptr = dev_out; 309 FileDB *ptr = dev_out;
310 while (ptr) { 310 while (ptr) {
311 printf("%s,", ptr->fname); 311 fprintf(fp, "%s,", ptr->fname);
312 ptr = ptr->next; 312 ptr = ptr->next;
313 } 313 }
314 printf("\n"); 314 fprintf(fp, "\n");
315 } 315 }
316} 316}
317 317
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c
index 947f172d8..9bbd2c258 100644
--- a/src/fbuilder/build_home.c
+++ b/src/fbuilder/build_home.c
@@ -158,7 +158,7 @@ void process_home(const char *fname, char *home, int home_len) {
158 158
159 159
160// process fname, fname.1, fname.2, fname.3, fname.4, fname.5 160// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
161void build_home(const char *fname) { 161void build_home(const char *fname, FILE *fp) {
162 assert(fname); 162 assert(fname);
163 163
164 // load whitelist common 164 // load whitelist common
@@ -190,10 +190,10 @@ void build_home(const char *fname) {
190 190
191 // print the out list if any 191 // print the out list if any
192 if (db_out) { 192 if (db_out) {
193 filedb_print(db_out, "whitelist ~/"); 193 filedb_print(db_out, "whitelist ~/", fp);
194 printf("include /etc/firejail/whitelist-common.inc\n"); 194 fprintf(fp, "include /etc/firejail/whitelist-common.inc\n");
195 } 195 }
196 else 196 else
197 printf("private\n"); 197 fprintf(fp, "private\n");
198 198
199} \ No newline at end of file 199} \ No newline at end of file
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c
index 6d6263035..de9f79232 100644
--- a/src/fbuilder/build_profile.c
+++ b/src/fbuilder/build_profile.c
@@ -56,7 +56,7 @@ static void clear_tmp_files(void) {
56 56
57} 57}
58 58
59void build_profile(int argc, char **argv, int index) { 59void build_profile(int argc, char **argv, int index, FILE *fp) {
60 // next index is the application name 60 // next index is the application name
61 if (index >= argc) { 61 if (index >= argc) {
62 fprintf(stderr, "Error: application name missing\n"); 62 fprintf(stderr, "Error: application name missing\n");
@@ -116,51 +116,51 @@ void build_profile(int argc, char **argv, int index) {
116 116
117 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 117 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
118 printf("\n\n\n"); 118 printf("\n\n\n");
119 printf("############################################\n"); 119 fprintf(fp, "############################################\n");
120 printf("# %s profile\n", argv[index]); 120 fprintf(fp, "# %s profile\n", argv[index]);
121 printf("############################################\n"); 121 fprintf(fp, "############################################\n");
122 printf("# Persistent global definitions\n"); 122 fprintf(fp, "# Persistent global definitions\n");
123 printf("# include /etc/firejail/globals.local\n"); 123 fprintf(fp, "# include /etc/firejail/globals.local\n");
124 printf("\n"); 124 fprintf(fp, "\n");
125 125
126 printf("### basic blacklisting\n"); 126 fprintf(fp, "### basic blacklisting\n");
127 printf("include /etc/firejail/disable-common.inc\n"); 127 fprintf(fp, "include /etc/firejail/disable-common.inc\n");
128 printf("# include /etc/firejail/disable-devel.inc\n"); 128 fprintf(fp, "# include /etc/firejail/disable-devel.inc\n");
129 printf("include /etc/firejail/disable-passwdmgr.inc\n"); 129 fprintf(fp, "include /etc/firejail/disable-passwdmgr.inc\n");
130 printf("# include /etc/firejail/disable-programs.inc\n"); 130 fprintf(fp, "# include /etc/firejail/disable-programs.inc\n");
131 printf("\n"); 131 fprintf(fp, "\n");
132 132
133 printf("### home directory whitelisting\n"); 133 fprintf(fp, "### home directory whitelisting\n");
134 build_home(TRACE_OUTPUT); 134 build_home(TRACE_OUTPUT, fp);
135 printf("\n"); 135 fprintf(fp, "\n");
136 136
137 printf("### filesystem\n"); 137 fprintf(fp, "### filesystem\n");
138 build_tmp(TRACE_OUTPUT); 138 build_tmp(TRACE_OUTPUT, fp);
139 build_dev(TRACE_OUTPUT); 139 build_dev(TRACE_OUTPUT, fp);
140 build_etc(TRACE_OUTPUT); 140 build_etc(TRACE_OUTPUT, fp);
141 build_var(TRACE_OUTPUT); 141 build_var(TRACE_OUTPUT, fp);
142 build_bin(TRACE_OUTPUT); 142 build_bin(TRACE_OUTPUT, fp);
143 build_share(TRACE_OUTPUT); 143 build_share(TRACE_OUTPUT, fp);
144 printf("\n"); 144 fprintf(fp, "\n");
145 145
146 printf("### security filters\n"); 146 fprintf(fp, "### security filters\n");
147 printf("caps.drop all\n"); 147 fprintf(fp, "caps.drop all\n");
148 printf("nonewprivs\n"); 148 fprintf(fp, "nonewprivs\n");
149 printf("seccomp\n"); 149 fprintf(fp, "seccomp\n");
150 if (have_strace) 150 if (have_strace)
151 build_seccomp(STRACE_OUTPUT); 151 build_seccomp(STRACE_OUTPUT, fp);
152 else { 152 else {
153 printf("# If you install strace on your system, Firejail will also create a\n"); 153 fprintf(fp, "# If you install strace on your system, Firejail will also create a\n");
154 printf("# whitelisted seccomp filter.\n"); 154 fprintf(fp, "# whitelisted seccomp filter.\n");
155 } 155 }
156 printf("\n"); 156 fprintf(fp, "\n");
157 157
158 printf("### network\n"); 158 fprintf(fp, "### network\n");
159 build_protocol(TRACE_OUTPUT); 159 build_protocol(TRACE_OUTPUT, fp);
160 printf("\n"); 160 fprintf(fp, "\n");
161 161
162 printf("### environment\n"); 162 fprintf(fp, "### environment\n");
163 printf("shell none\n"); 163 fprintf(fp, "shell none\n");
164 164
165 } 165 }
166 else { 166 else {
diff --git a/src/fbuilder/build_seccomp.c b/src/fbuilder/build_seccomp.c
index 18a767518..63f37e34a 100644
--- a/src/fbuilder/build_seccomp.c
+++ b/src/fbuilder/build_seccomp.c
@@ -20,11 +20,12 @@
20 20
21#include "fbuilder.h" 21#include "fbuilder.h"
22 22
23void build_seccomp(const char *fname) { 23void build_seccomp(const char *fname, FILE *fp) {
24 assert(fname); 24 assert(fname);
25 assert(fp);
25 26
26 FILE *fp = fopen(fname, "r"); 27 FILE *fp2 = fopen(fname, "r");
27 if (!fp) { 28 if (!fp2) {
28 fprintf(stderr, "Error: cannot open %s\n", fname); 29 fprintf(stderr, "Error: cannot open %s\n", fname);
29 exit(1); 30 exit(1);
30 } 31 }
@@ -33,7 +34,7 @@ void build_seccomp(const char *fname) {
33 int line = 1; 34 int line = 1;
34 int position = 0; 35 int position = 0;
35 int cnt = 0; 36 int cnt = 0;
36 while (fgets(buf, MAX_BUF, fp)) { 37 while (fgets(buf, MAX_BUF, fp2)) {
37 // remove \n 38 // remove \n
38 char *ptr = strchr(buf, '\n'); 39 char *ptr = strchr(buf, '\n');
39 if (ptr) 40 if (ptr)
@@ -62,20 +63,20 @@ void build_seccomp(const char *fname) {
62 break; 63 break;
63 64
64 if (line == 3) 65 if (line == 3)
65 printf("# seccomp.keep %s", buf + position); 66 fprintf(fp, "# seccomp.keep %s", buf + position);
66 else 67 else
67 printf(",%s", buf + position); 68 fprintf(fp, ",%s", buf + position);
68 cnt++; 69 cnt++;
69 } 70 }
70 line++; 71 line++;
71 } 72 }
72 printf("\n"); 73 fprintf(fp, "\n");
73 printf("# %d syscalls total\n", cnt); 74 fprintf(fp, "# %d syscalls total\n", cnt);
74 printf("# Probably you will need to add more syscalls to seccomp.keep. Look for\n"); 75 fprintf(fp, "# 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 fprintf(fp, "# seccomp errors in /var/log/syslog or /var/log/audit/audit.log while\n");
76 printf("# running your sandbox.\n"); 77 fprintf(fp, "# running your sandbox.\n");
77 78
78 fclose(fp); 79 fclose(fp2);
79} 80}
80 81
81//*************************************** 82//***************************************
@@ -141,7 +142,7 @@ static void process_protocol(const char *fname) {
141 142
142 143
143// process fname, fname.1, fname.2, fname.3, fname.4, fname.5 144// process fname, fname.1, fname.2, fname.3, fname.4, fname.5
144void build_protocol(const char *fname) { 145void build_protocol(const char *fname, FILE *fp) {
145 assert(fname); 146 assert(fname);
146 147
147 // run fname 148 // run fname
@@ -161,31 +162,31 @@ void build_protocol(const char *fname) {
161 162
162 int net = 0; 163 int net = 0;
163 if (unix_s || inet || inet6 || netlink || packet) { 164 if (unix_s || inet || inet6 || netlink || packet) {
164 printf("protocol "); 165 fprintf(fp, "protocol ");
165 if (unix_s) 166 if (unix_s)
166 printf("unix,"); 167 fprintf(fp, "unix,");
167 if (inet) { 168 if (inet) {
168 printf("inet,"); 169 fprintf(fp, "inet,");
169 net = 1; 170 net = 1;
170 } 171 }
171 if (inet6) { 172 if (inet6) {
172 printf("inet6,"); 173 fprintf(fp, "inet6,");
173 net = 1; 174 net = 1;
174 } 175 }
175 if (netlink) 176 if (netlink)
176 printf("netlink,"); 177 fprintf(fp, "netlink,");
177 if (packet) { 178 if (packet) {
178 printf("packet"); 179 fprintf(fp, "packet");
179 net = 1; 180 net = 1;
180 } 181 }
181 printf("\n"); 182 fprintf(fp, "\n");
182 } 183 }
183 184
184 if (net == 0) 185 if (net == 0)
185 printf("net none\n"); 186 fprintf(fp, "net none\n");
186 else { 187 else {
187 printf("# net eth0\n"); 188 fprintf(fp, "# net eth0\n");
188 printf("netfilter\n"); 189 fprintf(fp, "netfilter\n");
189 } 190 }
190} 191}
191 192
diff --git a/src/fbuilder/fbuilder.h b/src/fbuilder/fbuilder.h
index 401ae908e..81dc951ec 100644
--- a/src/fbuilder/fbuilder.h
+++ b/src/fbuilder/fbuilder.h
@@ -32,24 +32,24 @@
32extern int arg_debug; 32extern int arg_debug;
33 33
34// build_profile.c 34// build_profile.c
35void build_profile(int argc, char **argv, int index); 35void build_profile(int argc, char **argv, int index, FILE *fp);
36 36
37// build_seccomp.c 37// build_seccomp.c
38void build_seccomp(const char *fname); 38void build_seccomp(const char *fname, FILE *fp);
39void build_protocol(const char *fname); 39void build_protocol(const char *fname, FILE *fp);
40 40
41// build_fs.c 41// build_fs.c
42void build_etc(const char *fname); 42void build_etc(const char *fname, FILE *fp);
43void build_var(const char *fname); 43void build_var(const char *fname, FILE *fp);
44void build_tmp(const char *fname); 44void build_tmp(const char *fname, FILE *fp);
45void build_dev(const char *fname); 45void build_dev(const char *fname, FILE *fp);
46void build_share(const char *fname); 46void build_share(const char *fname, FILE *fp);
47 47
48// build_bin.c 48// build_bin.c
49void build_bin(const char *fname); 49void build_bin(const char *fname, FILE *fp);
50 50
51// build_home.c 51// build_home.c
52void build_home(const char *fname); 52void build_home(const char *fname, FILE *fp);
53 53
54// utils.c 54// utils.c
55int is_dir(const char *fname); 55int is_dir(const char *fname);
@@ -64,6 +64,6 @@ typedef struct filedb_t {
64 64
65FileDB *filedb_add(FileDB *head, const char *fname); 65FileDB *filedb_add(FileDB *head, const char *fname);
66FileDB *filedb_find(FileDB *head, const char *fname); 66FileDB *filedb_find(FileDB *head, const char *fname);
67void filedb_print(FileDB *head, const char *prefix); 67void filedb_print(FileDB *head, const char *prefix, FILE *fp);
68 68
69#endif \ No newline at end of file 69#endif \ No newline at end of file
diff --git a/src/fbuilder/filedb.c b/src/fbuilder/filedb.c
index a76fbc961..b7162c2d6 100644
--- a/src/fbuilder/filedb.c
+++ b/src/fbuilder/filedb.c
@@ -69,10 +69,10 @@ FileDB *filedb_add(FileDB *head, const char *fname) {
69 return entry; 69 return entry;
70}; 70};
71 71
72void filedb_print(FileDB *head, const char *prefix) { 72void filedb_print(FileDB *head, const char *prefix, FILE *fp) {
73 FileDB *ptr = head; 73 FileDB *ptr = head;
74 while (ptr) { 74 while (ptr) {
75 printf("%s%s\n", prefix, ptr->fname); 75 fprintf(fp, "%s%s\n", prefix, ptr->fname);
76 ptr = ptr->next; 76 ptr = ptr->next;
77 } 77 }
78} 78}
diff --git a/src/fbuilder/main.c b/src/fbuilder/main.c
index 83217ef98..1b997ccdb 100644
--- a/src/fbuilder/main.c
+++ b/src/fbuilder/main.c
@@ -22,7 +22,7 @@ int arg_debug = 0;
22 22
23static void usage(void) { 23static void usage(void) {
24 printf("Firejail profile builder\n"); 24 printf("Firejail profile builder\n");
25 printf("Usage: firejail [--debug] --build program-and-arguments\n"); 25 printf("Usage: firejail [--debug] --build[=profile-file] program-and-arguments\n");
26} 26}
27 27
28int main(int argc, char **argv) { 28int main(int argc, char **argv) {
@@ -38,6 +38,8 @@ printf("\n");
38 38
39 int i; 39 int i;
40 int prog_index = 0; 40 int prog_index = 0;
41 FILE *fp = stdout;
42 int prof_file = 0;
41 43
42 // parse arguments and extract program index 44 // parse arguments and extract program index
43 for (i = 1; i < argc; i++) { 45 for (i = 1; i < argc; i++) {
@@ -49,6 +51,22 @@ printf("\n");
49 arg_debug = 1; 51 arg_debug = 1;
50 else if (strcmp(argv[i], "--build") == 0) 52 else if (strcmp(argv[i], "--build") == 0)
51 ; // do nothing, this is passed down from firejail 53 ; // do nothing, this is passed down from firejail
54 else if (strncmp(argv[i], "--build=", 8) == 0) {
55 // this option is only supported for non-root users
56 if (getuid() == 0) {
57 fprintf(stderr, "Error fbuild: --build=profile-name is not supported for root user.\n");
58 exit(1);
59 }
60
61 // check file access
62 fp = fopen(argv[i] + 8, "w");
63 if (!fp) {
64 fprintf(stderr, "Error fbuild: cannot open profile file.\n");
65 exit(1);
66 }
67 prof_file = 1;
68 // do nothing, this is passed down from firejail
69 }
52 else { 70 else {
53 if (*argv[i] == '-') { 71 if (*argv[i] == '-') {
54 fprintf(stderr, "Error fbuilder: invalid program\n"); 72 fprintf(stderr, "Error fbuilder: invalid program\n");
@@ -63,9 +81,13 @@ printf("\n");
63 if (prog_index == 0) { 81 if (prog_index == 0) {
64 fprintf(stderr, "Error fbuilder: program and arguments required\n"); 82 fprintf(stderr, "Error fbuilder: program and arguments required\n");
65 usage(); 83 usage();
84 if (prof_file)
85 fclose(fp);
66 exit(1); 86 exit(1);
67 } 87 }
68 88
69 build_profile(argc, argv, prog_index); 89 build_profile(argc, argv, prog_index, fp);
90 if (prof_file)
91 fclose(fp);
70 return 0; 92 return 0;
71} 93}
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 126f98d9b..fef333601 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -831,13 +831,21 @@ char *guess_shell(void) {
831 return shell; 831 return shell;
832} 832}
833 833
834static int check_arg(int argc, char **argv, const char *argument) { 834static int check_arg(int argc, char **argv, const char *argument, int strict) {
835 int i; 835 int i;
836 int found = 0; 836 int found = 0;
837 for (i = 1; i < argc; i++) { 837 for (i = 1; i < argc; i++) {
838 if (strcmp(argv[i], argument) == 0) { 838 if (strict) {
839 found = 1; 839 if (strcmp(argv[i], argument) == 0) {
840 break; 840 found = 1;
841 break;
842 }
843 }
844 else {
845 if (strncmp(argv[i], argument, strlen(argument)) == 0) {
846 found = 1;
847 break;
848 }
841 } 849 }
842 850
843 // detect end of firejail params 851 // detect end of firejail params
@@ -891,9 +899,9 @@ int main(int argc, char **argv) {
891 preproc_build_firejail_dir(); 899 preproc_build_firejail_dir();
892 preproc_clean_run(); 900 preproc_clean_run();
893 901
894 if (check_arg(argc, argv, "--quiet")) 902 if (check_arg(argc, argv, "--quiet", 1))
895 arg_quiet = 1; 903 arg_quiet = 1;
896 if (check_arg(argc, argv, "--allow-debuggers")) { 904 if (check_arg(argc, argv, "--allow-debuggers", 1)) {
897 // check kernel version 905 // check kernel version
898 struct utsname u; 906 struct utsname u;
899 int rv = uname(&u); 907 int rv = uname(&u);
@@ -921,14 +929,14 @@ int main(int argc, char **argv) {
921 929
922#ifdef HAVE_GIT_INSTALL 930#ifdef HAVE_GIT_INSTALL
923 // process git-install and git-uninstall 931 // process git-install and git-uninstall
924 if (check_arg(argc, argv, "--git-install")) 932 if (check_arg(argc, argv, "--git-install", 1))
925 git_install(); // this function will not return 933 git_install(); // this function will not return
926 if (check_arg(argc, argv, "--git-uninstall")) 934 if (check_arg(argc, argv, "--git-uninstall", 1))
927 git_uninstall(); // this function will not return 935 git_uninstall(); // this function will not return
928#endif 936#endif
929 937
930 // profile builder 938 // profile builder
931 if (check_arg(argc, argv, "--build")) 939 if (check_arg(argc, argv, "--build", 0)) // supports both --build and --build=filename
932 run_builder(argc, argv); // this function will not return 940 run_builder(argc, argv); // this function will not return
933 941
934 // check argv[0] symlink wrapper if this is not a login shell 942 // check argv[0] symlink wrapper if this is not a login shell
@@ -946,10 +954,10 @@ int main(int argc, char **argv) {
946 EUID_USER(); 954 EUID_USER();
947 if (rv == 0) { 955 if (rv == 0) {
948 // if --force option is passed to the program, disregard the existing sandbox 956 // if --force option is passed to the program, disregard the existing sandbox
949 if (check_arg(argc, argv, "--force")) 957 if (check_arg(argc, argv, "--force", 1))
950 option_force = 1; 958 option_force = 1;
951 else { 959 else {
952 if (check_arg(argc, argv, "--version")) { 960 if (check_arg(argc, argv, "--version", 1)) {
953 printf("firejail version %s\n", VERSION); 961 printf("firejail version %s\n", VERSION);
954 exit(0); 962 exit(0);
955 } 963 }
@@ -966,7 +974,7 @@ int main(int argc, char **argv) {
966 EUID_ROOT(); 974 EUID_ROOT();
967 if (geteuid()) { 975 if (geteuid()) {
968 // only --version is supported without SUID support 976 // only --version is supported without SUID support
969 if (check_arg(argc, argv, "--version")) { 977 if (check_arg(argc, argv, "--version", 1)) {
970 printf("firejail version %s\n", VERSION); 978 printf("firejail version %s\n", VERSION);
971 exit(0); 979 exit(0);
972 } 980 }
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index f3b3aace5..567d3134e 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -45,6 +45,7 @@ void usage(void) {
45#endif 45#endif
46 printf(" --blacklist=filename - blacklist directory or file.\n"); 46 printf(" --blacklist=filename - blacklist directory or file.\n");
47 printf(" --build - build a whitelisted profile for the application.\n"); 47 printf(" --build - build a whitelisted profile for the application.\n");
48 printf(" --build=filename - build a whitelisted profile for the application.\n");
48 printf(" -c - execute command and exit.\n"); 49 printf(" -c - execute command and exit.\n");
49 printf(" --caps - enable default Linux capabilities filter.\n"); 50 printf(" --caps - enable default Linux capabilities filter.\n");
50 printf(" --caps.drop=all - drop all capabilities.\n"); 51 printf(" --caps.drop=all - drop all capabilities.\n");
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index 00481d4d3..2303a8bbd 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -146,7 +146,7 @@ $ firejail "\-\-blacklist=/home/username/My Virtual Machines"
146$ firejail \-\-blacklist=/home/username/My\\ Virtual\\ Machines 146$ firejail \-\-blacklist=/home/username/My\\ Virtual\\ Machines
147.TP 147.TP
148\fB\-\-build 148\fB\-\-build
149The command builds a whitelisted profile. If /usr/bin/strace is installed on the system, it also 149The command builds a whitelisted profile. The profile is printed on the screen. If /usr/bin/strace is installed on the system, it also
150builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox, 150builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox,
151with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported 151with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported
152in order to allow strace to run. Chromium and Chromium-based browsers will not work. 152in order to allow strace to run. Chromium and Chromium-based browsers will not work.
@@ -155,7 +155,19 @@ in order to allow strace to run. Chromium and Chromium-based browsers will not w
155.br 155.br
156Example: 156Example:
157.br 157.br
158$ firejail --build vlc ~/Videos/test.mp4 158$ firejail --build=profile-file vlc ~/Videos/test.mp4
159.TP
160\fB\-\-build=profile-file
161The command builds a whitelisted profile, and saves it in profile-file. If /usr/bin/strace is installed on the system, it also
162builds a whitelisted seccomp profile. The program is run in a very relaxed sandbox,
163with only --caps.drop=all and --nonewprivs. Programs that raise user privileges are not supported
164in order to allow strace to run. Chromium and Chromium-based browsers will not work.
165.br
166
167.br
168Example:
169.br
170$ firejail --build=vlc.profile vlc ~/Videos/test.mp4
159.TP 171.TP
160\fB\-c 172\fB\-c
161Execute command and exit. 173Execute command and exit.