diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/profile.c | 110 | ||||
-rw-r--r-- | src/man/firejail-profile.txt | 18 | ||||
-rw-r--r-- | src/man/firejail.txt | 12 |
3 files changed, 124 insertions, 16 deletions
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 4fc710f39..c7c8fd9fa 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -132,12 +132,99 @@ void profile_add_ignore(const char *str) { | |||
132 | } | 132 | } |
133 | 133 | ||
134 | 134 | ||
135 | int profile_check_conditional(char *ptr, int lineno, const char *fname) { | ||
136 | struct cond_t { | ||
137 | char *name; // conditional name | ||
138 | size_t len; // length of name | ||
139 | bool value; // true if set | ||
140 | } conditionals[] = { | ||
141 | {"HAS_APPIMAGE", strlen("HAS_APPIMAGE"), arg_appimage!=0}, | ||
142 | NULL | ||
143 | }, *cond = conditionals; | ||
144 | char *tmp = ptr, *msg = NULL; | ||
145 | |||
146 | if (*ptr++ != '?') | ||
147 | return 1; | ||
148 | |||
149 | while (cond->name) { | ||
150 | // continue if not this conditional | ||
151 | if (strncmp(ptr, cond->name, cond->len) != 0) { | ||
152 | cond++; | ||
153 | continue; | ||
154 | } | ||
155 | ptr += cond->len; | ||
156 | |||
157 | if (*ptr == ' ') | ||
158 | ptr++; | ||
159 | if (*ptr++ != ':') { | ||
160 | msg = "invalid syntax: colon must come after conditional"; | ||
161 | ptr = tmp; | ||
162 | goto error; | ||
163 | } | ||
164 | if (*ptr == '\0') { | ||
165 | msg = "invalid conditional line: no profile line after conditional"; | ||
166 | ptr = tmp; | ||
167 | goto error; | ||
168 | } | ||
169 | if (*ptr == ' ') | ||
170 | ptr++; | ||
171 | |||
172 | // if set, continue processing statement in caller | ||
173 | if (cond->value) { | ||
174 | // move ptr to start of profile line | ||
175 | ptr = strdup(ptr); | ||
176 | if (!ptr) | ||
177 | errExit("strdup"); | ||
178 | |||
179 | // check that the profile line does not contain either | ||
180 | // quiet or include directives | ||
181 | if ((strncmp(ptr, "quiet", 5) == 0) || | ||
182 | (strncmp(ptr, "include", 7) == 0)) { | ||
183 | msg = "invalid profile line: quiet and include not allowed in conditionals"; | ||
184 | ptr = tmp; | ||
185 | goto error; | ||
186 | } | ||
187 | free(tmp); | ||
188 | |||
189 | // verify syntax, exit in case of error | ||
190 | if (profile_check_line(ptr, lineno, fname)) | ||
191 | profile_add(ptr); | ||
192 | } | ||
193 | // tell caller to ignore | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | tmp = ptr; | ||
198 | // get the conditional used | ||
199 | while (*tmp != ':' && *tmp != '\0') | ||
200 | tmp++; | ||
201 | *tmp = '\0'; | ||
202 | |||
203 | // this was a '?' prefix, but didn't match any of the conditionals | ||
204 | msg = "invalid/unsupported conditional"; | ||
205 | |||
206 | error: | ||
207 | fprintf(stderr, "Error: %s (\"%s\"", msg, ptr); | ||
208 | if (lineno == 0) ; | ||
209 | else if (fname != NULL) | ||
210 | fprintf(stderr, " on line %d in %s", lineno, fname); | ||
211 | else | ||
212 | fprintf(stderr, " on line %d in the custom profile", lineno); | ||
213 | fprintf(stderr, ")\n"); | ||
214 | exit(1); | ||
215 | } | ||
216 | |||
217 | |||
135 | // check profile line; if line == 0, this was generated from a command line option | 218 | // check profile line; if line == 0, this was generated from a command line option |
136 | // return 1 if the command is to be added to the linked list of profile commands | 219 | // return 1 if the command is to be added to the linked list of profile commands |
137 | // return 0 if the command was already executed inside the function | 220 | // return 0 if the command was already executed inside the function |
138 | int profile_check_line(char *ptr, int lineno, const char *fname) { | 221 | int profile_check_line(char *ptr, int lineno, const char *fname) { |
139 | EUID_ASSERT(); | 222 | EUID_ASSERT(); |
140 | 223 | ||
224 | // check and process conditional profile lines | ||
225 | if (profile_check_conditional(ptr, lineno, fname) == 0) | ||
226 | return 0; | ||
227 | |||
141 | // check ignore list | 228 | // check ignore list |
142 | if (is_in_ignore_list(ptr)) | 229 | if (is_in_ignore_list(ptr)) |
143 | return 0; | 230 | return 0; |
@@ -1280,7 +1367,7 @@ void profile_read(const char *fname) { | |||
1280 | if (ptr && strlen(ptr) == 6) | 1367 | if (ptr && strlen(ptr) == 6) |
1281 | return; | 1368 | return; |
1282 | 1369 | ||
1283 | fprintf(stderr, "Error: cannot access profile file\n"); | 1370 | fprintf(stderr, "Error: cannot access profile file: %s\n", fname); |
1284 | exit(1); | 1371 | exit(1); |
1285 | } | 1372 | } |
1286 | 1373 | ||
@@ -1342,17 +1429,22 @@ void profile_read(const char *fname) { | |||
1342 | if (strncmp(ptr, "include ", 8) == 0) { | 1429 | if (strncmp(ptr, "include ", 8) == 0) { |
1343 | include_level++; | 1430 | include_level++; |
1344 | 1431 | ||
1345 | // extract profile filename and new skip params | 1432 | // expand macros in front of the include profile file |
1346 | char *newprofile = ptr + 8; // profile name | 1433 | char *newprofile = expand_macros(ptr + 8); |
1347 | 1434 | ||
1348 | // expand ${HOME}/ in front of the new profile file | 1435 | char *ptr2 = newprofile; |
1349 | char *newprofile2 = expand_macros(newprofile); | 1436 | while (*ptr2 != '/' && *ptr2 != '\0') |
1437 | ptr2++; | ||
1438 | // profile path contains no / chars, do a search | ||
1439 | if (*ptr2 == '\0') { | ||
1440 | profile_find_firejail(newprofile, 0); | ||
1441 | } | ||
1442 | else { | ||
1443 | profile_read(newprofile); | ||
1444 | } | ||
1350 | 1445 | ||
1351 | // recursivity | ||
1352 | profile_read((newprofile2)? newprofile2:newprofile); | ||
1353 | include_level--; | 1446 | include_level--; |
1354 | if (newprofile2) | 1447 | free(newprofile); |
1355 | free(newprofile2); | ||
1356 | free(ptr); | 1448 | free(ptr); |
1357 | continue; | 1449 | continue; |
1358 | } | 1450 | } |
diff --git a/src/man/firejail-profile.txt b/src/man/firejail-profile.txt index 5daca8abd..e26b5f989 100644 --- a/src/man/firejail-profile.txt +++ b/src/man/firejail-profile.txt | |||
@@ -27,7 +27,7 @@ Reading profile /home/netblue/icecat.profile | |||
27 | .RS | 27 | .RS |
28 | $ firejail --profile=icecat icecat-wrapper.sh | 28 | $ firejail --profile=icecat icecat-wrapper.sh |
29 | .br | 29 | .br |
30 | Reading profile /home/netblue/icecat.profile | 30 | Reading profile /etc/firejail/icecat.profile |
31 | .br | 31 | .br |
32 | [...] | 32 | [...] |
33 | .RE | 33 | .RE |
@@ -87,6 +87,18 @@ Example: "blacklist ~/My Virtual Machines" | |||
87 | \fB# this is a comment | 87 | \fB# this is a comment |
88 | 88 | ||
89 | .TP | 89 | .TP |
90 | \fB?CONDITIONAL: profile line | ||
91 | Conditionally add profile line. | ||
92 | |||
93 | Example: "?HAS_APPIMAGE: whitelist ${HOME}/special/appimage/dir" | ||
94 | |||
95 | This example will load the whitelist profile line only if the \-\-appimage option has been specified on the command line. | ||
96 | |||
97 | Currently the only conditional supported is HAS_APPIMAGE. | ||
98 | |||
99 | The profile line may be any profile line that you would normally use in a profile \fBexcept\fR for "quiet" and "include" lines. | ||
100 | |||
101 | .TP | ||
90 | \fBinclude other.profile | 102 | \fBinclude other.profile |
91 | Include other.profile file. | 103 | Include other.profile file. |
92 | 104 | ||
@@ -101,6 +113,10 @@ Example: "include ${HOME}/myprofiles/profile1" will load "~/myprofiles/profile1" | |||
101 | 113 | ||
102 | Example: "include ${CFG}/firefox.profile" will load "/etc/firejail/firefox.profile" file. | 114 | Example: "include ${CFG}/firefox.profile" will load "/etc/firejail/firefox.profile" file. |
103 | 115 | ||
116 | The file name may also be just the name without the leading directory components. In this case, first the user config directory (${HOME}/.config/firejail) is searched for the file name and if not found then the system configuration directory is search for the file name. Note: Unlike the \-\-profile option which takes a profile name without the '.profile' suffix, include must be given the full file name. | ||
117 | |||
118 | Example: "include firefox.profile" will load "${HOME}/.config/firejail/firefox.profile" file and if it does not exist "${CFG}/firefox.profile" will be loaded. | ||
119 | |||
104 | System configuration files in ${CFG} are overwritten during software installation. | 120 | System configuration files in ${CFG} are overwritten during software installation. |
105 | Persistent configuration at system level is handled in ".local" files. For every | 121 | Persistent configuration at system level is handled in ".local" files. For every |
106 | profile file in ${CFG} directory, the user can create a corresponding .local file | 122 | profile file in ${CFG} directory, the user can create a corresponding .local file |
diff --git a/src/man/firejail.txt b/src/man/firejail.txt index 5a374ac55..f7d18536d 100644 --- a/src/man/firejail.txt +++ b/src/man/firejail.txt | |||
@@ -395,7 +395,7 @@ $ firejail \-\-net=eth0 \-\-defaultgw=10.10.20.1 firefox | |||
395 | 395 | ||
396 | .TP | 396 | .TP |
397 | \fB\-\-disable-mnt | 397 | \fB\-\-disable-mnt |
398 | Disable /mnt, /media, /run/mount and /run/media access. | 398 | Blacklist /mnt, /media, /run/mount and /run/media access. |
399 | .br | 399 | .br |
400 | 400 | ||
401 | .br | 401 | .br |
@@ -1681,12 +1681,12 @@ Enable seccomp filter and blacklist the syscalls in the default list (@default). | |||
1681 | _sysctl, acct, add_key, adjtimex, afs_syscall, bdflush, bpf, break, chroot, clock_adjtime, clock_settime, | 1681 | _sysctl, acct, add_key, adjtimex, afs_syscall, bdflush, bpf, break, chroot, clock_adjtime, clock_settime, |
1682 | create_module, delete_module, fanotify_init, finit_module, ftime, get_kernel_syms, getpmsg, gtty, init_module, | 1682 | create_module, delete_module, fanotify_init, finit_module, ftime, get_kernel_syms, getpmsg, gtty, init_module, |
1683 | io_cancel, io_destroy, io_getevents, io_setup, io_submit, ioperm, iopl, ioprio_set, kcmp, kexec_file_load, | 1683 | io_cancel, io_destroy, io_getevents, io_setup, io_submit, ioperm, iopl, ioprio_set, kcmp, kexec_file_load, |
1684 | kexec_load, keyctl, lock, lookup_dcookie, mbind, mfsservctl, migrate_pages, modify_ldt, mount, move_pages, mpx, | 1684 | kexec_load, keyctl, lock, lookup_dcookie, mbind, migrate_pages, modify_ldt, mount, move_pages, mpx, |
1685 | name_to_handle_at, open_by_handle_at, pciconfig_iobase, pciconfig_read, pciconfig_write, perf_event_open, | 1685 | name_to_handle_at, nfsservctl, ni_syscall, open_by_handle_at, pciconfig_iobase, pciconfig_read, pciconfig_write, perf_event_open, |
1686 | personality, pivot_root, process_vm_readv, process_vm_writev, process_vm_writev, prof, profil, ptrace, putpmsg, | 1686 | personality, pivot_root, process_vm_readv, process_vm_writev, prof, profil, ptrace, putpmsg, |
1687 | query_module, reboot, remap_file_pages, request_key, rtas, s390_mmio_read, s390_mmio_write, s390_runtime_instr, | 1687 | query_module, reboot, remap_file_pages, request_key, rtas, s390_mmio_read, s390_mmio_write, s390_runtime_instr, |
1688 | security, set_mempolicy, setdomainname, sethostname, settimeofday, sgetmask, ssetmask, stime, stty, subpage_prot, | 1688 | security, set_mempolicy, setdomainname, sethostname, settimeofday, sgetmask, ssetmask, stime, stty, subpage_prot, |
1689 | swapoff, swapon, switch_endian, sysfs, syslog, tuxcall, ulimit, umount, umount2, uselib, userfaultfd, ustat, vhangup, | 1689 | swapoff, swapon, switch_endian, sys_debug_setcontext, sysfs, syslog, tuxcall, ulimit, umount, umount2, uselib, userfaultfd, ustat, vhangup, |
1690 | vm86, vm86old, vmsplice and vserver. | 1690 | vm86, vm86old, vmsplice and vserver. |
1691 | 1691 | ||
1692 | .br | 1692 | .br |
@@ -2716,7 +2716,7 @@ Reading profile /home/netblue/icecat.profile | |||
2716 | .RS | 2716 | .RS |
2717 | $ firejail --profile=icecat icecat-wrapper.sh | 2717 | $ firejail --profile=icecat icecat-wrapper.sh |
2718 | .br | 2718 | .br |
2719 | Reading profile /home/netblue/icecat.profile | 2719 | Reading profile /etc/firejail/icecat.profile |
2720 | .br | 2720 | .br |
2721 | [...] | 2721 | [...] |
2722 | .RE | 2722 | .RE |