aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@protonmail.com>2021-05-06 15:39:36 -0400
committerLibravatar netblue30 <netblue30@protonmail.com>2021-05-06 15:39:36 -0400
commit43e47483ff94753655ade1e633e973725d8fb505 (patch)
treef4f69043bcb37fd62c6d60da57cad5b6027f46c5
parentsome wireshark hardening (#4245) (diff)
downloadfirejail-43e47483ff94753655ade1e633e973725d8fb505.tar.gz
firejail-43e47483ff94753655ade1e633e973725d8fb505.tar.zst
firejail-43e47483ff94753655ade1e633e973725d8fb505.zip
more --build
-rw-r--r--src/fbuilder/build_bin.c9
-rw-r--r--src/fbuilder/build_fs.c145
-rw-r--r--src/fbuilder/build_home.c26
-rw-r--r--src/fbuilder/build_profile.c53
-rw-r--r--src/fbuilder/fbuilder.h1
-rw-r--r--src/fbuilder/filedb.c49
6 files changed, 130 insertions, 153 deletions
diff --git a/src/fbuilder/build_bin.c b/src/fbuilder/build_bin.c
index 431aebee6..9577042c4 100644
--- a/src/fbuilder/build_bin.c
+++ b/src/fbuilder/build_bin.c
@@ -83,11 +83,9 @@ static void process_bin(const char *fname) {
83 continue; 83 continue;
84 *ptr2 = '\0'; 84 *ptr2 = '\0';
85 85
86 // skip strace 86 // skip strace and firejail (in case we hit a symlink in /usr/local/bin)
87 if (strcmp(ptr, "strace") == 0) 87 if (strcmp(ptr, "strace") && strcmp(ptr, "firejail"))
88 continue; 88 bin_out = filedb_add(bin_out, ptr);
89
90 bin_out = filedb_add(bin_out, ptr);
91 } 89 }
92 90
93 fclose(fp); 91 fclose(fp);
@@ -121,6 +119,5 @@ void build_bin(const char *fname, FILE *fp) {
121 ptr = ptr->next; 119 ptr = ptr->next;
122 } 120 }
123 fprintf(fp, "\n"); 121 fprintf(fp, "\n");
124 fprintf(fp, "#private-lib\n");
125 } 122 }
126} 123}
diff --git a/src/fbuilder/build_fs.c b/src/fbuilder/build_fs.c
index b35380b96..8700e0ba1 100644
--- a/src/fbuilder/build_fs.c
+++ b/src/fbuilder/build_fs.c
@@ -146,106 +146,57 @@ void build_etc(const char *fname, FILE *fp) {
146//******************************************* 146//*******************************************
147// var directory 147// var directory
148//******************************************* 148//*******************************************
149#if 0
150// todo: load the list from whitelist-var-common.inc
151static char *var_skip[] = {
152 "/var/lib/ca-certificates",
153 "/var/lib/dbus",
154 "/var/lib/menu-xdg",
155 "/var/lib/uim",
156 "/var/cache/fontconfig",
157 "/var/tmp",
158 "/var/run",
159 "/var/lock",
160 NULL
161};
162#endif
149static FileDB *var_out = NULL; 163static FileDB *var_out = NULL;
164static FileDB *var_skip = NULL;
150static void var_callback(char *ptr) { 165static void var_callback(char *ptr) {
151 if (strcmp(ptr, "/var/lib") == 0) 166 // extract the directory:
152 ; 167 assert(strncmp(ptr, "/var", 4) == 0);
153 else if (strcmp(ptr, "/var/cache") == 0) 168 char *p1 = ptr + 4;
154 ; 169 if (*p1 != '/')
155 else if (strncmp(ptr, "/var/lib/menu-xdg", 17) == 0) 170 return;
156 var_out = filedb_add(var_out, "/var/lib/menu-xdg"); 171 p1++;
157 else if (strncmp(ptr, "/var/cache/fontconfig", 21) == 0) 172
158 var_out = filedb_add(var_out, "/var/cache/fontconfig"); 173 if (*p1 == '/') // double '/'
159 else 174 p1++;
160 var_out = filedb_add(var_out, ptr); 175 if (*p1 == '\0')
176 return;
177
178 if (!filedb_find(var_skip, p1))
179 var_out = filedb_add(var_out, p1);
161} 180}
162 181
163void build_var(const char *fname, FILE *fp) { 182void build_var(const char *fname, FILE *fp) {
164 assert(fname); 183 assert(fname);
165 184
185 var_skip = filedb_load_whitelist(var_skip, "whitelist-var-common.inc", "whitelist /var/");
166 process_files(fname, "/var", var_callback); 186 process_files(fname, "/var", var_callback);
167 187
168 if (var_out == NULL) { 188 // always whitelist /var
169 fprintf(fp, "blacklist /var\n"); 189 if (var_out)
170 } else { 190 filedb_print(var_out, "whitelist /var/", fp);
171 filedb_print(var_out, "whitelist ", fp); 191 fprintf(fp, "include whitelist-var-common.inc\n");
172 fprintf(fp, "include whitelist-var-common.inc\n");
173 }
174} 192}
175 193
176 194
177//******************************************* 195//*******************************************
178// usr/share directory 196// usr/share directory
179//******************************************* 197//*******************************************
180// todo: load the list from whitelist-usr-share-common.inc
181static char *share_skip[] = {
182 "/usr/share/alsa",
183 "/usr/share/applications",
184 "/usr/share/ca-certificates",
185 "/usr/share/crypto-policies",
186 "/usr/share/cursors",
187 "/usr/share/dconf",
188 "/usr/share/distro-info",
189 "/usr/share/drirc.d",
190 "/usr/share/enchant",
191 "/usr/share/enchant-2",
192 "/usr/share/file",
193 "/usr/share/fontconfig",
194 "/usr/share/fonts",
195 "/usr/share/fonts-config",
196 "/usr/share/gir-1.0",
197 "/usr/share/gjs-1.0",
198 "/usr/share/glib-2.0",
199 "/usr/share/glvnd",
200 "/usr/share/gtk-2.0",
201 "/usr/share/gtk-3.0",
202 "/usr/share/gtk-engines",
203 "/usr/share/gtksourceview-3.0",
204 "/usr/share/gtksourceview-4",
205 "/usr/share/hunspell",
206 "/usr/share/hwdata",
207 "/usr/share/icons",
208 "/usr/share/icu",
209 "/usr/share/knotifications5",
210 "/usr/share/kservices5",
211 "/usr/share/Kvantum",
212 "/usr/share/kxmlgui5",
213 "/usr/share/libdrm",
214 "/usr/share/libthai",
215 "/usr/share/locale",
216 "/usr/share/mime",
217 "/usr/share/misc",
218 "/usr/share/Modules",
219 "/usr/share/myspell",
220 "/usr/share/p11-kit",
221 "/usr/share/perl",
222 "/usr/share/perl5",
223 "/usr/share/pixmaps",
224 "/usr/share/pki",
225 "/usr/share/plasma",
226 "/usr/share/publicsuffix",
227 "/usr/share/qt",
228 "/usr/share/qt4",
229 "/usr/share/qt5",
230 "/usr/share/qt5ct",
231 "/usr/share/sounds",
232 "/usr/share/tcl8.6",
233 "/usr/share/tcltk",
234 "/usr/share/terminfo",
235 "/usr/share/texlive",
236 "/usr/share/texmf",
237 "/usr/share/themes",
238 "/usr/share/thumbnail.so",
239 "/usr/share/uim",
240 "/usr/share/vulkan",
241 "/usr/share/X11",
242 "/usr/share/xml",
243 "/usr/share/zenity",
244 "/usr/share/zoneinfo",
245 NULL
246};
247
248static FileDB *share_out = NULL; 198static FileDB *share_out = NULL;
199static FileDB *share_skip = NULL;
249static void share_callback(char *ptr) { 200static void share_callback(char *ptr) {
250 // extract the directory: 201 // extract the directory:
251 assert(strncmp(ptr, "/usr/share", 10) == 0); 202 assert(strncmp(ptr, "/usr/share", 10) == 0);
@@ -263,30 +214,21 @@ static void share_callback(char *ptr) {
263 if (p2) 214 if (p2)
264 *p2 = '\0'; 215 *p2 = '\0';
265 216
266 int i = 0; 217
267 int found = 0; 218 if (!filedb_find(share_skip, p1))
268 while (share_skip[i]) { 219 share_out = filedb_add(share_out, p1);
269 if (strncmp(ptr, share_skip[i], strlen(share_skip[i])) == 0) {
270 found = 1;
271 break;
272 }
273 i++;
274 }
275 if (!found)
276 share_out = filedb_add(share_out, ptr);
277} 220}
278 221
279void build_share(const char *fname, FILE *fp) { 222void build_share(const char *fname, FILE *fp) {
280 assert(fname); 223 assert(fname);
281 224
225 share_skip = filedb_load_whitelist(share_skip, "whitelist-usr-share-common.inc", "whitelist /usr/share/");
282 process_files(fname, "/usr/share", share_callback); 226 process_files(fname, "/usr/share", share_callback);
283 227
284 if (share_out == NULL) { 228 // always whitelist /usr/share
285 fprintf(fp, "blacklist /usr/share\n"); 229 if (share_out)
286 } else { 230 filedb_print(share_out, "whitelist /usr/share/", fp);
287 filedb_print(share_out, "whitelist ", fp); 231 fprintf(fp, "include whitelist-usr-share-common.inc\n");
288 fprintf(fp, "include whitelist-usr-share-common.inc\n");
289 }
290} 232}
291 233
292//******************************************* 234//*******************************************
@@ -336,6 +278,7 @@ static char *dev_skip[] = {
336 "/dev/null", 278 "/dev/null",
337 "/dev/full", 279 "/dev/full",
338 "/dev/random", 280 "/dev/random",
281 "/dev/srandom",
339 "/dev/urandom", 282 "/dev/urandom",
340 "/dev/sr0", 283 "/dev/sr0",
341 "/dev/cdrom", 284 "/dev/cdrom",
diff --git a/src/fbuilder/build_home.c b/src/fbuilder/build_home.c
index d7706282a..b3ec6cffd 100644
--- a/src/fbuilder/build_home.c
+++ b/src/fbuilder/build_home.c
@@ -23,30 +23,6 @@
23static FileDB *db_skip = NULL; 23static FileDB *db_skip = NULL;
24static FileDB *db_out = NULL; 24static FileDB *db_out = NULL;
25 25
26static void load_whitelist_common(void) {
27 FILE *fp = fopen(SYSCONFDIR "/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 ${HOME}/", 18) != 0)
36 continue;
37 char *fn = buf + 18;
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) { 26void process_home(const char *fname, char *home, int home_len) {
51 assert(fname); 27 assert(fname);
52 assert(home); 28 assert(home);
@@ -162,7 +138,7 @@ void build_home(const char *fname, FILE *fp) {
162 assert(fname); 138 assert(fname);
163 139
164 // load whitelist common 140 // load whitelist common
165 load_whitelist_common(); 141 db_skip = filedb_load_whitelist(db_skip, "whitelist-common.inc", "whitelist ${HOME}/");
166 142
167 // find user home directory 143 // find user home directory
168 struct passwd *pw = getpwuid(getuid()); 144 struct passwd *pw = getpwuid(getuid());
diff --git a/src/fbuilder/build_profile.c b/src/fbuilder/build_profile.c
index 100630eb9..fb53f70a6 100644
--- a/src/fbuilder/build_profile.c
+++ b/src/fbuilder/build_profile.c
@@ -141,57 +141,70 @@ void build_profile(int argc, char **argv, int index, FILE *fp) {
141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
142 if (fp == stdout) 142 if (fp == stdout)
143 printf("--- Built profile beings after this line ---\n"); 143 printf("--- Built profile beings after this line ---\n");
144 fprintf(fp, "# Firejail profile for %s\n", argv[index]); 144 fprintf(fp, "# Save this file as \"application.profile\" (change \"application\" with the\n");
145 fprintf(fp, "# program name) in ~/.config/firejail directory. Firejail will find it\n");
146 fprintf(fp, "# automatically every time you sandbox your application.\n#\n");
147 fprintf(fp, "# Run \"firejail application\" to test it. In the file there are\n");
148 fprintf(fp, "# some other commands you can try. Enable them by removing the \"#\".\n");
149
150 fprintf(fp, "\n# Firejail profile for %s\n", argv[index]);
145 fprintf(fp, "# Persistent local customizations\n"); 151 fprintf(fp, "# Persistent local customizations\n");
146 fprintf(fp, "#include %s.local\n", argv[index]); 152 fprintf(fp, "#include %s.local\n", argv[index]);
147 fprintf(fp, "# Persistent global definitions\n"); 153 fprintf(fp, "# Persistent global definitions\n");
148 fprintf(fp, "#include globals.local\n"); 154 fprintf(fp, "#include globals.local\n");
149 fprintf(fp, "\n"); 155 fprintf(fp, "\n");
150 156
151 fprintf(fp, "### basic blacklisting\n"); 157 fprintf(fp, "### Basic Blacklisting ###\n");
158 fprintf(fp, "### Enable as many of them as you can! A very important one is\n");
159 fprintf(fp, "### \"disable-exec.inc\". This will make among other things your home\n");
160 fprintf(fp, "### and /tmp directories non-executable.\n");
152 fprintf(fp, "include disable-common.inc\n"); 161 fprintf(fp, "include disable-common.inc\n");
153 fprintf(fp, "#include disable-devel.inc\n"); 162 fprintf(fp, "#include disable-devel.inc\n");
154 fprintf(fp, "#include disable-exec.inc\n"); 163 fprintf(fp, "#include disable-exec.inc\n");
155 fprintf(fp, "#include disable-interpreters.inc\n"); 164 fprintf(fp, "#include disable-interpreters.inc\n");
156 fprintf(fp, "include disable-passwdmgr.inc\n"); 165 fprintf(fp, "include disable-passwdmgr.inc\n");
157 fprintf(fp, "#include disable-programs.inc\n"); 166 fprintf(fp, "include disable-programs.inc\n");
158 fprintf(fp, "#include disable-xdg.inc\n"); 167 fprintf(fp, "#include disable-xdg.inc\n");
159 fprintf(fp, "\n"); 168 fprintf(fp, "\n");
160 169
161 fprintf(fp, "### home directory whitelisting\n"); 170 fprintf(fp, "### Home Directory Whitelisting ###\n");
171 fprintf(fp, "### If something goes wrong, this section is the first one to comment out.\n");
172 fprintf(fp, "### Instead, you'll have to relay on the basic blacklisting above.\n");
162 build_home(trace_output, fp); 173 build_home(trace_output, fp);
163 174
164 fprintf(fp, "\n### /usr/share:\n"); 175 fprintf(fp, "\n### The Rest of the Filesystem ###\n");
165 build_share(trace_output, fp); 176 build_share(trace_output, fp);
166 fprintf(fp, "\n### /var:\n");
167 build_var(trace_output, fp); 177 build_var(trace_output, fp);
168 fprintf(fp, "\n### /bin:\n");
169 build_bin(trace_output, fp); 178 build_bin(trace_output, fp);
170 fprintf(fp, "\n### /dev:\n");
171 build_dev(trace_output, fp); 179 build_dev(trace_output, fp);
172 fprintf(fp, "\n### /etc:\n"); 180 fprintf(fp, "#nodvd\n");
181 fprintf(fp, "#noinput\n");
182 fprintf(fp, "#notv\n");
183 fprintf(fp, "#nou2f\n");
184 fprintf(fp, "#novideo\n");
173 build_etc(trace_output, fp); 185 build_etc(trace_output, fp);
174 fprintf(fp, "\n### /tmp:\n");
175 build_tmp(trace_output, fp); 186 build_tmp(trace_output, fp);
176 187
177 fprintf(fp, "\n### security filters\n"); 188 fprintf(fp, "\n### Security Filters ###\n");
189 fprintf(fp, "#apparmor\n");
178 fprintf(fp, "caps.drop all\n"); 190 fprintf(fp, "caps.drop all\n");
191 fprintf(fp, "netfilter\n");
192 fprintf(fp, "#nogroups\n");
193 fprintf(fp, "#noroot\n");
179 fprintf(fp, "nonewprivs\n"); 194 fprintf(fp, "nonewprivs\n");
195 build_protocol(trace_output, fp);
196
180 fprintf(fp, "seccomp\n"); 197 fprintf(fp, "seccomp\n");
181 if (!have_strace) { 198 if (!have_strace) {
182 fprintf(fp, "# If you install strace on your system, Firejail will also create a\n"); 199 fprintf(fp, "### If you install strace on your system, Firejail will also create a\n");
183 fprintf(fp, "# whitelisted seccomp filter.\n"); 200 fprintf(fp, "### whitelisted seccomp filter.\n");
184 } 201 }
185 else if (!have_yama_permission) 202 else if (!have_yama_permission)
186 fprintf(fp, "# Yama security module prevents creation of a whitelisted seccomp filter\n"); 203 fprintf(fp, "### Yama security module prevents creation of a whitelisted seccomp filter\n");
187 else 204 else
188 build_seccomp(strace_output, fp); 205 build_seccomp(strace_output, fp);
189 206 fprintf(fp, "#shell none\n");
190 fprintf(fp, "\n### network\n"); 207 fprintf(fp, "#tracelog\n");
191 build_protocol(trace_output, fp);
192
193 fprintf(fp, "\n### environment\n");
194 fprintf(fp, "shell none\n");
195 208
196 if (!arg_debug) { 209 if (!arg_debug) {
197 unlink(trace_output); 210 unlink(trace_output);
diff --git a/src/fbuilder/fbuilder.h b/src/fbuilder/fbuilder.h
index 8d3621c02..08dd35e10 100644
--- a/src/fbuilder/fbuilder.h
+++ b/src/fbuilder/fbuilder.h
@@ -66,5 +66,6 @@ typedef struct filedb_t {
66FileDB *filedb_add(FileDB *head, const char *fname); 66FileDB *filedb_add(FileDB *head, const char *fname);
67FileDB *filedb_find(FileDB *head, const char *fname); 67FileDB *filedb_find(FileDB *head, const char *fname);
68void filedb_print(FileDB *head, const char *prefix, FILE *fp); 68void filedb_print(FileDB *head, const char *prefix, FILE *fp);
69FileDB *filedb_load_whitelist(FileDB *head, const char *fname, const char *prefix);
69 70
70#endif 71#endif
diff --git a/src/fbuilder/filedb.c b/src/fbuilder/filedb.c
index 6e302a606..94a226cb7 100644
--- a/src/fbuilder/filedb.c
+++ b/src/fbuilder/filedb.c
@@ -20,7 +20,9 @@
20 20
21#include "fbuilder.h" 21#include "fbuilder.h"
22 22
23// find exact name or an exact name in a parent directory
23FileDB *filedb_find(FileDB *head, const char *fname) { 24FileDB *filedb_find(FileDB *head, const char *fname) {
25 assert(fname);
24 FileDB *ptr = head; 26 FileDB *ptr = head;
25 int found = 0; 27 int found = 0;
26 int len = strlen(fname); 28 int len = strlen(fname);
@@ -52,6 +54,8 @@ FileDB *filedb_find(FileDB *head, const char *fname) {
52FileDB *filedb_add(FileDB *head, const char *fname) { 54FileDB *filedb_add(FileDB *head, const char *fname) {
53 assert(fname); 55 assert(fname);
54 56
57 // todo: support fnames such as ${RUNUSER}/.mutter-Xwaylandauth.*
58
55 // don't add it if it is already there or if the parent directory is already in the list 59 // 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)) 60 if (filedb_find(head, fname))
57 return head; 61 return head;
@@ -70,9 +74,52 @@ FileDB *filedb_add(FileDB *head, const char *fname) {
70}; 74};
71 75
72void filedb_print(FileDB *head, const char *prefix, FILE *fp) { 76void filedb_print(FileDB *head, const char *prefix, FILE *fp) {
77 assert(head);
78 assert(prefix);
79
73 FileDB *ptr = head; 80 FileDB *ptr = head;
74 while (ptr) { 81 while (ptr) {
75 fprintf(fp, "%s%s\n", prefix, ptr->fname); 82 if (fp)
83 fprintf(fp, "%s%s\n", prefix, ptr->fname);
84 else
85 printf("%s%s\n", prefix, ptr->fname);
76 ptr = ptr->next; 86 ptr = ptr->next;
77 } 87 }
78} 88}
89
90FileDB *filedb_load_whitelist(FileDB *head, const char *fname, const char *prefix) {
91 assert(fname);
92 assert(prefix);
93 int len = strlen(prefix);
94 char *f;
95 if (asprintf(&f, "%s/%s", SYSCONFDIR, fname) == -1)
96 errExit("asprintf");
97 FILE *fp = fopen(f, "r");
98 if (!fp) {
99 fprintf(stderr, "Error: cannot open whitelist-common.inc\n");
100 free(f);
101 exit(1);
102 }
103
104 char buf[MAX_BUF];
105 while (fgets(buf, MAX_BUF, fp)) {
106 if (strncmp(buf, prefix, len) != 0)
107 continue;
108
109 char *fn = buf + len;
110 char *ptr = strchr(buf, '\n');
111 if (!ptr)
112 continue;
113 *ptr = '\0';
114
115 // add the file to skip list
116 head = filedb_add(head, fn);
117 }
118
119 fclose(fp);
120 free(f);
121//printf("***************************************************\n");
122//filedb_print(head, prefix, NULL);
123//printf("***************************************************\n");
124 return head;
125}