aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2020-08-22 07:45:58 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2020-08-22 07:45:58 -0400
commit07472ed702f416f8c684de8baff3b32761ebc32a (patch)
tree4bfeb5e53e2ae379dd30a80421ff29cdf1293a09 /src
parentcleaning up POSTMORTEM code (diff)
parentMerge pull request #3572 from smitsohu/dumpable (diff)
downloadfirejail-07472ed702f416f8c684de8baff3b32761ebc32a.tar.gz
firejail-07472ed702f416f8c684de8baff3b32761ebc32a.tar.zst
firejail-07472ed702f416f8c684de8baff3b32761ebc32a.zip
Merge branch 'master' of https://github.com/netblue30/firejail
Diffstat (limited to 'src')
-rw-r--r--src/fcopy/main.c6
-rw-r--r--src/firejail/firejail.h3
-rw-r--r--src/firejail/ls.c169
-rw-r--r--src/firejail/main.c35
-rw-r--r--src/firejail/sandbox.c40
-rw-r--r--src/firejail/sbox.c1
-rw-r--r--src/firejail/usage.c3
-rw-r--r--src/firejail/x11.c173
-rw-r--r--src/fldd/main.c6
-rw-r--r--src/fnet/main.c16
-rw-r--r--src/fnetfilter/main.c6
-rw-r--r--src/fsec-optimize/fsec_optimize.h1
-rw-r--r--src/fsec-optimize/main.c6
-rw-r--r--src/fsec-print/fsec_print.h1
-rw-r--r--src/fsec-print/main.c5
-rw-r--r--src/fseccomp/fseccomp.h1
-rw-r--r--src/fseccomp/main.c16
-rw-r--r--src/include/common.h3
-rw-r--r--src/include/rundefs.h5
-rw-r--r--src/man/firejail.txt20
20 files changed, 306 insertions, 210 deletions
diff --git a/src/fcopy/main.c b/src/fcopy/main.c
index 83d9c17e6..67237b4ea 100644
--- a/src/fcopy/main.c
+++ b/src/fcopy/main.c
@@ -23,6 +23,7 @@
23#include <ftw.h> 23#include <ftw.h>
24#include <errno.h> 24#include <errno.h>
25#include <pwd.h> 25#include <pwd.h>
26#include <sys/prctl.h>
26 27
27#if HAVE_SELINUX 28#if HAVE_SELINUX
28#include <sys/stat.h> 29#include <sys/stat.h>
@@ -411,6 +412,11 @@ int main(int argc, char **argv) {
411 exit(1); 412 exit(1);
412 } 413 }
413 414
415#ifdef WARN_DUMPABLE
416 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
417 fprintf(stderr, "Error fcopy: I am dumpable\n");
418#endif
419
414 // trim trailing chars 420 // trim trailing chars
415 if (src[strlen(src) - 1] == '/') 421 if (src[strlen(src) - 1] == '/')
416 src[strlen(src) - 1] = '\0'; 422 src[strlen(src) - 1] = '\0';
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index c98f80d13..49d19e33d 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -728,10 +728,13 @@ void x11_xorg(void);
728// ls.c 728// ls.c
729enum { 729enum {
730 SANDBOX_FS_LS = 0, 730 SANDBOX_FS_LS = 0,
731 SANDBOX_FS_CAT,
731 SANDBOX_FS_GET, 732 SANDBOX_FS_GET,
732 SANDBOX_FS_PUT, 733 SANDBOX_FS_PUT,
733 SANDBOX_FS_MAX // this should always be the last entry 734 SANDBOX_FS_MAX // this should always be the last entry
734}; 735};
736void ls(const char *path);
737void cat(const char *path);
735void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn)); 738void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) __attribute__((noreturn));
736 739
737// checkcfg.c 740// checkcfg.c
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index aa33d838b..4d0a001b6 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -34,18 +34,12 @@
34static uid_t c_uid = 0; 34static uid_t c_uid = 0;
35static char *c_uid_name = NULL; 35static char *c_uid_name = NULL;
36 36
37static void print_file_or_dir(const char *path, const char *fname, int separator) { 37static void print_file_or_dir(const char *path, const char *fname) {
38 assert(fname); 38 assert(fname);
39 39
40 char *name; 40 char *name;
41 if (separator) { 41 if (asprintf(&name, "%s/%s", path, fname) == -1)
42 if (asprintf(&name, "%s/%s", path, fname) == -1) 42 errExit("asprintf");
43 errExit("asprintf");
44 }
45 else {
46 if (asprintf(&name, "%s%s", path, fname) == -1)
47 errExit("asprintf");
48 }
49 43
50 struct stat s; 44 struct stat s;
51 if (stat(name, &s) == -1) { 45 if (stat(name, &s) == -1) {
@@ -178,13 +172,81 @@ static void print_directory(const char *path) {
178 errExit("scandir"); 172 errExit("scandir");
179 else { 173 else {
180 for (i = 0; i < n; i++) { 174 for (i = 0; i < n; i++) {
181 print_file_or_dir(path, namelist[i]->d_name, 0); 175 print_file_or_dir(path, namelist[i]->d_name);
182 free(namelist[i]); 176 free(namelist[i]);
183 } 177 }
184 } 178 }
185 free(namelist); 179 free(namelist);
186} 180}
187 181
182void ls(const char *path) {
183 EUID_ASSERT();
184 assert(path);
185
186 char *rp = realpath(path, NULL);
187 if (!rp || access(rp, R_OK) == -1) {
188 fprintf(stderr, "Error: cannot access %s\n", path);
189 exit(1);
190 }
191 if (arg_debug)
192 printf("ls %s\n", rp);
193
194 // list directory contents
195 struct stat s;
196 if (stat(rp, &s) == -1) {
197 fprintf(stderr, "Error: cannot access %s\n", rp);
198 exit(1);
199 }
200 if (S_ISDIR(s.st_mode))
201 print_directory(rp);
202 else {
203 char *split = strrchr(rp, '/');
204 if (split) {
205 *split = '\0';
206 char *rp2 = split + 1;
207 if (arg_debug)
208 printf("path %s, file %s\n", rp, rp2);
209 print_file_or_dir(rp, rp2);
210 }
211 }
212 free(rp);
213}
214
215void cat(const char *path) {
216 EUID_ASSERT();
217 assert(path);
218
219 if (arg_debug)
220 printf("cat %s\n", path);
221 FILE *fp = fopen(path, "r");
222 if (!fp) {
223 fprintf(stderr, "Error: cannot read %s\n", path);
224 exit(1);
225 }
226 int fd = fileno(fp);
227 if (fd == -1)
228 errExit("fileno");
229 struct stat s;
230 if (fstat(fd, &s) == -1)
231 errExit("fstat");
232 if (!S_ISREG(s.st_mode)) {
233 fprintf(stderr, "Error: %s is not a regular file\n", path);
234 exit(1);
235 }
236 bool tty = isatty(STDOUT_FILENO);
237
238 int c;
239 while ((c = fgetc(fp)) != EOF) {
240 // file is untrusted
241 // replace control characters when printing to a terminal
242 if (tty && c != '\t' && c != '\n' && iscntrl((unsigned char) c))
243 c = '?';
244 fputc(c, stdout);
245 }
246 fflush(stdout);
247 fclose(fp);
248}
249
188char *expand_path(const char *path) { 250char *expand_path(const char *path) {
189 char *fname = NULL; 251 char *fname = NULL;
190 if (*path == '/') { 252 if (*path == '/') {
@@ -219,14 +281,14 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
219 check_join_permission(pid); 281 check_join_permission(pid);
220 282
221 // expand paths 283 // expand paths
222 char *fname1 = expand_path(path1);; 284 char *fname1 = expand_path(path1);
223 char *fname2 = NULL; 285 char *fname2 = NULL;
224 if (path2 != NULL) { 286 if (path2 != NULL) {
225 fname2 = expand_path(path2); 287 fname2 = expand_path(path2);
226 } 288 }
227 if (arg_debug) { 289 if (arg_debug) {
228 printf("file1 %s\n", fname1); 290 printf("file1 %s\n", fname1);
229 printf("file2 %s\n", fname2); 291 printf("file2 %s\n", fname2 ? fname2 : "(null)");
230 } 292 }
231 293
232 // sandbox root directory 294 // sandbox root directory
@@ -234,57 +296,36 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
234 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) 296 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
235 errExit("asprintf"); 297 errExit("asprintf");
236 298
237 if (op == SANDBOX_FS_LS) { 299 if (op == SANDBOX_FS_LS || op == SANDBOX_FS_CAT) {
238 EUID_ROOT(); 300 pid_t child = fork();
239 // chroot 301 if (child < 0)
240 if (chroot(rootdir) < 0) 302 errExit("fork");
241 errExit("chroot"); 303 if (child == 0) {
242 if (chdir("/") < 0) 304 EUID_ROOT();
243 errExit("chdir"); 305 // chroot
244 306 if (chroot(rootdir) < 0)
245 // drop privileges 307 errExit("chroot");
246 drop_privs(0); 308 if (chdir("/") < 0)
247 309 errExit("chdir");
248 // check access
249 if (access(fname1, R_OK) == -1) {
250 fprintf(stderr, "Error: Cannot access %s\n", fname1);
251 exit(1);
252 }
253 /* coverity[toctou] */
254 char *rp = realpath(fname1, NULL);
255 if (!rp) {
256 fprintf(stderr, "Error: Cannot access %s\n", fname1);
257 exit(1);
258 }
259 if (arg_debug)
260 printf("realpath %s\n", rp);
261
262 310
263 // list directory contents 311 // drop privileges
264 struct stat s; 312 drop_privs(0);
265 if (stat(rp, &s) == -1) {
266 fprintf(stderr, "Error: Cannot access %s\n", rp);
267 exit(1);
268 }
269 if (S_ISDIR(s.st_mode)) {
270 char *dir;
271 if (asprintf(&dir, "%s/", rp) == -1)
272 errExit("asprintf");
273 313
274 print_directory(dir); 314 if (op == SANDBOX_FS_LS)
275 free(dir); 315 ls(fname1);
276 } 316 else
277 else { 317 cat(fname1);
278 char *split = strrchr(rp, '/'); 318#ifdef HAVE_GCOV
279 if (split) { 319 __gcov_flush();
280 *split = '\0'; 320#endif
281 char *rp2 = split + 1; 321 _exit(0);
282 if (arg_debug)
283 printf("path %s, file %s\n", rp, rp2);
284 print_file_or_dir(rp, rp2, 1);
285 }
286 } 322 }
287 free(rp); 323 // wait for the child to finish
324 int status = 0;
325 waitpid(child, &status, 0);
326 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
327 else
328 exit(1);
288 } 329 }
289 330
290 // get file from sandbox and store it in the current directory 331 // get file from sandbox and store it in the current directory
@@ -303,10 +344,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
303 // create a user-owned temporary file in /run/firejail directory 344 // create a user-owned temporary file in /run/firejail directory
304 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; 345 char tmp_fname[] = "/run/firejail/tmpget-XXXXXX";
305 int fd = mkstemp(tmp_fname); 346 int fd = mkstemp(tmp_fname);
306 if (fd != -1) { 347 if (fd == -1) {
307 SET_PERMS_FD(fd, getuid(), getgid(), 0600); 348 fprintf(stderr, "Error: cannot create temporary file %s\n", tmp_fname);
308 close(fd); 349 exit(1);
309 } 350 }
351 SET_PERMS_FD(fd, getuid(), getgid(), 0600);
352 close(fd);
310 353
311 // copy the source file into the temporary file - we need to chroot 354 // copy the source file into the temporary file - we need to chroot
312 pid_t child = fork(); 355 pid_t child = fork();
diff --git a/src/firejail/main.c b/src/firejail/main.c
index 4c98210f5..072651c4d 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -789,6 +789,8 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
789 } 789 }
790 790
791 // list directory contents 791 // list directory contents
792 if (!arg_debug)
793 arg_quiet = 1;
792 pid_t pid = require_pid(argv[i] + 5); 794 pid_t pid = require_pid(argv[i] + 5);
793 sandboxfs(SANDBOX_FS_LS, pid, path, NULL); 795 sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
794 exit(0); 796 exit(0);
@@ -796,6 +798,35 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
796 else 798 else
797 exit_err_feature("file transfer"); 799 exit_err_feature("file transfer");
798 } 800 }
801 else if (strncmp(argv[i], "--cat=", 6) == 0) {
802 if (checkcfg(CFG_FILE_TRANSFER)) {
803 logargs(argc, argv);
804 if (arg_private_cwd) {
805 fprintf(stderr, "Error: --cat and --private-cwd options are mutually exclusive\n");
806 exit(1);
807 }
808
809 if ((i + 2) != argc) {
810 fprintf(stderr, "Error: invalid --cat option, path expected\n");
811 exit(1);
812 }
813 char *path = argv[i + 1];
814 invalid_filename(path, 0); // no globbing
815 if (strstr(path, "..")) {
816 fprintf(stderr, "Error: invalid file name %s\n", path);
817 exit(1);
818 }
819
820 // write file contents to stdout
821 if (!arg_debug)
822 arg_quiet = 1;
823 pid_t pid = require_pid(argv[i] + 6);
824 sandboxfs(SANDBOX_FS_CAT, pid, path, NULL);
825 exit(0);
826 }
827 else
828 exit_err_feature("file transfer");
829 }
799#endif 830#endif
800 else if (strncmp(argv[i], "--join=", 7) == 0) { 831 else if (strncmp(argv[i], "--join=", 7) == 0) {
801 if (checkcfg(CFG_JOIN) || getuid() == 0) { 832 if (checkcfg(CFG_JOIN) || getuid() == 0) {
@@ -1252,6 +1283,10 @@ int main(int argc, char **argv, char **envp) {
1252 } 1283 }
1253 EUID_ASSERT(); 1284 EUID_ASSERT();
1254 1285
1286#ifdef WARN_DUMPABLE
1287 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
1288 fprintf(stderr, "Error: Firejail is dumpable\n");
1289#endif
1255 1290
1256 // check for force-nonewprivs in /etc/firejail/firejail.config file 1291 // check for force-nonewprivs in /etc/firejail/firejail.config file
1257 if (checkcfg(CFG_FORCE_NONEWPRIVS)) 1292 if (checkcfg(CFG_FORCE_NONEWPRIVS))
diff --git a/src/firejail/sandbox.c b/src/firejail/sandbox.c
index e42d35be5..81d535762 100644
--- a/src/firejail/sandbox.c
+++ b/src/firejail/sandbox.c
@@ -140,6 +140,20 @@ void set_apparmor(void) {
140} 140}
141#endif 141#endif
142 142
143#ifdef HAVE_SECCOMP
144void seccomp_debug(void) {
145 if (arg_debug == 0)
146 return;
147
148 EUID_USER();
149 printf("Seccomp directory:\n");
150 ls(RUN_SECCOMP_DIR);
151 printf("Active seccomp files:\n");
152 cat(RUN_SECCOMP_LIST);
153 EUID_ROOT();
154}
155#endif
156
143static void save_nogroups(void) { 157static void save_nogroups(void) {
144 if (arg_nogroups == 0) 158 if (arg_nogroups == 0)
145 return; 159 return;
@@ -197,32 +211,6 @@ static FILE *create_ready_for_join_file(void) {
197 } 211 }
198} 212}
199 213
200#ifdef HAVE_SECCOMP
201static void seccomp_debug(void) {
202 if (arg_debug == 0)
203 return;
204
205 pid_t child = fork();
206 if (child < 0)
207 errExit("fork");
208 if (child == 0) {
209 // dropping privs before calling system(3)
210 drop_privs(1);
211 printf("Seccomp directory:\n");
212 int rv = system("ls -l " RUN_SECCOMP_DIR);
213 (void) rv;
214 printf("Active seccomp files:\n");
215 rv = system("cat " RUN_SECCOMP_LIST);
216 (void) rv;
217#ifdef HAVE_GCOV
218 __gcov_flush();
219#endif
220 _exit(0);
221 }
222 waitpid(child, NULL, 0);
223}
224#endif
225
226static void sandbox_if_up(Bridge *br) { 214static void sandbox_if_up(Bridge *br) {
227 assert(br); 215 assert(br);
228 if (!br->configured) 216 if (!br->configured)
diff --git a/src/firejail/sbox.c b/src/firejail/sbox.c
index 57c21ce78..a92d62940 100644
--- a/src/firejail/sbox.c
+++ b/src/firejail/sbox.c
@@ -48,6 +48,7 @@ static int __attribute__((noreturn)) sbox_do_exec_v(unsigned filtermask, char *
48 if (cfg.seccomp_error_action) 48 if (cfg.seccomp_error_action)
49 if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1) 49 if (asprintf(&new_environment[env_index++], "FIREJAIL_SECCOMP_ERROR_ACTION=%s", cfg.seccomp_error_action) == -1)
50 errExit("asprintf"); 50 errExit("asprintf");
51 new_environment[env_index++] = "FIREJAIL_PLUGIN="; // always set
51 52
52 if (filtermask & SBOX_STDIN_FROM_FILE) { 53 if (filtermask & SBOX_STDIN_FROM_FILE) {
53 int fd; 54 int fd;
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 73c9a6a8b..2390706f2 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -47,6 +47,9 @@ static char *usage_str =
47 " --caps.drop=capability,capability - blacklist capabilities filter.\n" 47 " --caps.drop=capability,capability - blacklist capabilities filter.\n"
48 " --caps.keep=capability,capability - whitelist capabilities filter.\n" 48 " --caps.keep=capability,capability - whitelist capabilities filter.\n"
49 " --caps.print=name|pid - print the caps filter.\n" 49 " --caps.print=name|pid - print the caps filter.\n"
50#ifdef HAVE_FILE_TRANSFER
51 " --cat=name|pid filename - print content of file from sandbox container.\n"
52#endif
50 " --cgroup=tasks-file - place the sandbox in the specified control group.\n" 53 " --cgroup=tasks-file - place the sandbox in the specified control group.\n"
51#ifdef HAVE_CHROOT 54#ifdef HAVE_CHROOT
52 " --chroot=dirname - chroot into directory.\n" 55 " --chroot=dirname - chroot into directory.\n"
diff --git a/src/firejail/x11.c b/src/firejail/x11.c
index ba54ca376..e10abad4e 100644
--- a/src/firejail/x11.c
+++ b/src/firejail/x11.c
@@ -34,7 +34,7 @@
34 34
35#include <fcntl.h> 35#include <fcntl.h>
36#ifndef O_PATH 36#ifndef O_PATH
37# define O_PATH 010000000 37#define O_PATH 010000000
38#endif 38#endif
39 39
40 40
@@ -1129,28 +1129,17 @@ void x11_start(int argc, char **argv) {
1129} 1129}
1130#endif 1130#endif
1131 1131
1132// Porting notes: 1132
1133//
1134// 1. merge #1100 from zackw:
1135// Attempting to run xauth -f directly on a file in /run/firejail/mnt/ directory fails on Debian 8
1136// with this message:
1137// xauth: timeout in locking authority file /run/firejail/mnt/sec.Xauthority-Qt5Mu4
1138// Failed to create untrusted X cookie: xauth: exit 1
1139// For this reason we run xauth on a file in a tmpfs filesystem mounted on /tmp. This was
1140// a partial merge.
1141//
1142// 2. Since we cannot deal with the TOCTOU condition when mounting .Xauthority in user home
1143// directory, we need to make sure /usr/bin/xauth executable is the real thing, and not
1144// something picked up on $PATH.
1145//
1146// 3. If for any reason xauth command fails, we exit the sandbox. On Debian 8 this happens
1147// when using a network namespace. Somehow, xauth tries to connect to the abstract socket,
1148// and it fails because of the network namespace - it should try to connect to the regular
1149// Unix socket! If we ignore the fail condition, the program will be started on X server without
1150// the security extension loaded.
1151void x11_xorg(void) { 1133void x11_xorg(void) {
1152#ifdef HAVE_X11 1134#ifdef HAVE_X11
1153 1135
1136 // get DISPLAY env
1137 char *display = getenv("DISPLAY");
1138 if (!display) {
1139 fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr);
1140 exit(1);
1141 }
1142
1154 // check xauth utility is present in the system 1143 // check xauth utility is present in the system
1155 struct stat s; 1144 struct stat s;
1156 if (stat("/usr/bin/xauth", &s) == -1) { 1145 if (stat("/usr/bin/xauth", &s) == -1) {
@@ -1160,26 +1149,27 @@ void x11_xorg(void) {
1160 fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n"); 1149 fprintf(stderr, " Fedora: sudo dnf install xorg-x11-xauth\n");
1161 exit(1); 1150 exit(1);
1162 } 1151 }
1163 if (s.st_uid != 0 && s.st_gid != 0) { 1152 if ((s.st_uid != 0 && s.st_gid != 0) || (s.st_mode & S_IWOTH)) {
1164 fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n"); 1153 fprintf(stderr, "Error: invalid /usr/bin/xauth executable\n");
1165 exit(1); 1154 exit(1);
1166 } 1155 }
1167 1156 if (s.st_size > 1024 * 1024) {
1168 // get DISPLAY env 1157 fprintf(stderr, "Error: /usr/bin/xauth executable is too large\n");
1169 char *display = getenv("DISPLAY");
1170 if (!display) {
1171 fputs("Error: --x11=xorg requires an 'outer' X11 server to use.\n", stderr);
1172 exit(1); 1158 exit(1);
1173 } 1159 }
1174 1160 // copy /usr/bin/xauth in the sandbox and set mode to 0711
1175 // temporarily mount a tempfs on top of /tmp directory 1161 // users are not able to trace the running xauth this way
1176 if (mount("tmpfs", "/tmp", "tmpfs", MS_NOSUID | MS_STRICTATIME, "mode=1777,gid=0") < 0)
1177 errExit("mounting /tmp");
1178
1179 // create the temporary .Xauthority file
1180 if (arg_debug) 1162 if (arg_debug)
1181 printf("Generating a new .Xauthority file\n"); 1163 printf("Copying /usr/bin/xauth to %s\n", RUN_XAUTH_FILE);
1182 char tmpfname[] = "/tmp/.tmpXauth-XXXXXX"; 1164 if (copy_file("/usr/bin/xauth", RUN_XAUTH_FILE, 0, 0, 0711)) {
1165 fprintf(stderr, "Error: cannot copy /usr/bin/xauth executable\n");
1166 exit(1);
1167 }
1168
1169 fmessage("Generating a new .Xauthority file\n");
1170 mkdir_attr(RUN_XAUTHORITY_SEC_DIR, 0700, getuid(), getgid());
1171 // create new Xauthority file in RUN_XAUTHORITY_SEC_DIR
1172 char tmpfname[] = RUN_XAUTHORITY_SEC_DIR "/.Xauth-XXXXXX";
1183 int fd = mkstemp(tmpfname); 1173 int fd = mkstemp(tmpfname);
1184 if (fd == -1) { 1174 if (fd == -1) {
1185 fprintf(stderr, "Error: cannot create .Xauthority file\n"); 1175 fprintf(stderr, "Error: cannot create .Xauthority file\n");
@@ -1189,64 +1179,17 @@ void x11_xorg(void) {
1189 errExit("chown"); 1179 errExit("chown");
1190 close(fd); 1180 close(fd);
1191 1181
1192 pid_t child = fork(); 1182 // run xauth
1193 if (child < 0)
1194 errExit("fork");
1195 if (child == 0) {
1196 drop_privs(1);
1197 clearenv();
1198#ifdef HAVE_GCOV
1199 __gcov_flush();
1200#endif
1201 if (arg_debug) {
1202 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-v", "-f", tmpfname,
1203 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
1204 }
1205 else {
1206 execlp("/usr/bin/xauth", "/usr/bin/xauth", "-f", tmpfname,
1207 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted", NULL);
1208 }
1209
1210 _exit(127);
1211 }
1212
1213 // wait for the xauth process to finish
1214 int status;
1215 if (waitpid(child, &status, 0) != child)
1216 errExit("waitpid");
1217 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
1218 /* success */
1219 }
1220 else if (WIFEXITED(status)) {
1221 fprintf(stderr, "Failed to create untrusted X cookie: xauth: exit %d\n",
1222 WEXITSTATUS(status));
1223 exit(1);
1224 }
1225 else if (WIFSIGNALED(status)) {
1226 fprintf(stderr, "Failed to create untrusted X cookie: xauth: %s\n",
1227 strsignal(WTERMSIG(status)));
1228 exit(1);
1229 }
1230 else {
1231 fprintf(stderr, "Failed to create untrusted X cookie: "
1232 "xauth: un-decodable exit status %04x\n", status);
1233 exit(1);
1234 }
1235
1236 // move the temporary file in RUN_XAUTHORITY_SEC_FILE in order to have it deleted
1237 // automatically when the sandbox is closed (rename doesn't work)
1238 if (arg_debug) 1183 if (arg_debug)
1239 printf("Copying the new .Xauthority file\n"); 1184 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 8, RUN_XAUTH_FILE, "-v", "-f", tmpfname,
1240 copy_file_from_user_to_root(tmpfname, RUN_XAUTHORITY_SEC_FILE, getuid(), getgid(), 0600); 1185 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1241 1186 else
1242 /* coverity[toctou] */ 1187 sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 7, RUN_XAUTH_FILE, "-f", tmpfname,
1243 unlink(tmpfname); 1188 "generate", display, "MIT-MAGIC-COOKIE-1", "untrusted");
1244 umount("/tmp"); 1189 // remove xauth copy
1245 1190 unlink(RUN_XAUTH_FILE);
1246 // mount RUN_XAUTHORITY_SEC_FILE noexec, nodev, nosuid
1247 fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_NOEXEC, 0);
1248 1191
1249 // Ensure there is already a file in the usual location, so that bind-mount below will work. 1192 // ensure there is already a file ~/.Xauthority, so that bind-mount below will work.
1250 char *dest; 1193 char *dest;
1251 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1) 1194 if (asprintf(&dest, "%s/.Xauthority", cfg.homedir) == -1)
1252 errExit("asprintf"); 1195 errExit("asprintf");
@@ -1257,13 +1200,12 @@ void x11_xorg(void) {
1257 exit(1); 1200 exit(1);
1258 } 1201 }
1259 } 1202 }
1260 1203 // get a file descriptor for ~/.Xauthority
1261 // get a file descriptor for .Xauthority 1204 int dst = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1262 fd = safe_fd(dest, O_PATH|O_NOFOLLOW|O_CLOEXEC); 1205 if (dst == -1)
1263 if (fd == -1)
1264 errExit("safe_fd"); 1206 errExit("safe_fd");
1265 // check if the actual mount destination is a user owned regular file 1207 // check if the actual mount destination is a user owned regular file
1266 if (fstat(fd, &s) == -1) 1208 if (fstat(dst, &s) == -1)
1267 errExit("fstat"); 1209 errExit("fstat");
1268 if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) { 1210 if (!S_ISREG(s.st_mode) || s.st_uid != getuid()) {
1269 if (S_ISLNK(s.st_mode)) 1211 if (S_ISLNK(s.st_mode))
@@ -1274,31 +1216,49 @@ void x11_xorg(void) {
1274 } 1216 }
1275 // preserve a read-only mount 1217 // preserve a read-only mount
1276 struct statvfs vfs; 1218 struct statvfs vfs;
1277 if (fstatvfs(fd, &vfs) == -1) 1219 if (fstatvfs(dst, &vfs) == -1)
1278 errExit("fstatvfs"); 1220 errExit("fstatvfs");
1279 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY) 1221 if ((vfs.f_flag & MS_RDONLY) == MS_RDONLY)
1280 fs_remount(RUN_XAUTHORITY_SEC_FILE, MOUNT_READONLY, 0); 1222 fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_READONLY, 0);
1223
1224 // always mounting the new Xauthority file noexec,nodev,nosuid
1225 fs_remount(RUN_XAUTHORITY_SEC_DIR, MOUNT_NOEXEC, 0);
1226
1227 // get a file descriptor for the new Xauthority file
1228 int src = safe_fd(tmpfname, O_PATH|O_NOFOLLOW|O_CLOEXEC);
1229 if (src == -1)
1230 errExit("safe_fd");
1231 if (fstat(src, &s) == -1)
1232 errExit("fstat");
1233 if (!S_ISREG(s.st_mode)) {
1234 errno = EPERM;
1235 errExit("mounting Xauthority file");
1236 }
1281 1237
1282 // mount via the link in /proc/self/fd 1238 // mount via the link in /proc/self/fd
1283 if (arg_debug) 1239 if (arg_debug)
1284 printf("Mounting %s on %s\n", RUN_XAUTHORITY_SEC_FILE, dest); 1240 printf("Mounting %s on %s\n", tmpfname, dest);
1285 char *proc; 1241 char *proc_src, *proc_dst;
1286 if (asprintf(&proc, "/proc/self/fd/%d", fd) == -1) 1242 if (asprintf(&proc_src, "/proc/self/fd/%d", src) == -1)
1243 errExit("asprintf");
1244 if (asprintf(&proc_dst, "/proc/self/fd/%d", dst) == -1)
1287 errExit("asprintf"); 1245 errExit("asprintf");
1288 if (mount(RUN_XAUTHORITY_SEC_FILE, proc, "none", MS_BIND, "mode=0600") == -1) { 1246 if (mount(proc_src, proc_dst, NULL, MS_BIND, NULL) == -1) {
1289 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n"); 1247 fprintf(stderr, "Error: cannot mount the new .Xauthority file\n");
1290 exit(1); 1248 exit(1);
1291 } 1249 }
1292 free(proc);
1293 close(fd);
1294 // check /proc/self/mountinfo to confirm the mount is ok 1250 // check /proc/self/mountinfo to confirm the mount is ok
1295 MountData *mptr = get_last_mount(); 1251 MountData *mptr = get_last_mount();
1296 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0) 1252 if (strcmp(mptr->dir, dest) != 0 || strcmp(mptr->fstype, "tmpfs") != 0)
1297 errLogExit("invalid .Xauthority mount"); 1253 errLogExit("invalid .Xauthority mount");
1254 free(proc_src);
1255 free(proc_dst);
1256 close(src);
1257 close(dst);
1298 1258
1299 ASSERT_PERMS(dest, getuid(), getgid(), 0600); 1259 ASSERT_PERMS(dest, getuid(), getgid(), 0600);
1300 1260
1301 // blacklist .Xauthority file if it is not masked already 1261 // blacklist user .Xauthority file if it is not masked already
1302 char *envar = getenv("XAUTHORITY"); 1262 char *envar = getenv("XAUTHORITY");
1303 if (envar) { 1263 if (envar) {
1304 char *rp = realpath(envar, NULL); 1264 char *rp = realpath(envar, NULL);
@@ -1312,6 +1272,11 @@ void x11_xorg(void) {
1312 if (setenv("XAUTHORITY", dest, 1) < 0) 1272 if (setenv("XAUTHORITY", dest, 1) < 0)
1313 errExit("setenv"); 1273 errExit("setenv");
1314 free(dest); 1274 free(dest);
1275
1276 // mask RUN_XAUTHORITY_SEC_DIR
1277 if (mount("tmpfs", RUN_XAUTHORITY_SEC_DIR, "tmpfs", MS_NOSUID | MS_NODEV | MS_STRICTATIME, "mode=755,gid=0") < 0)
1278 errExit("mounting tmpfs");
1279 fs_logger2("tmpfs", RUN_XAUTHORITY_SEC_DIR);
1315#endif 1280#endif
1316} 1281}
1317 1282
diff --git a/src/fldd/main.c b/src/fldd/main.c
index dd22e601e..d68504f6b 100644
--- a/src/fldd/main.c
+++ b/src/fldd/main.c
@@ -24,6 +24,7 @@
24#include <fcntl.h> 24#include <fcntl.h>
25#include <sys/mman.h> 25#include <sys/mman.h>
26#include <sys/mount.h> 26#include <sys/mount.h>
27#include <sys/prctl.h>
27#include <sys/stat.h> 28#include <sys/stat.h>
28#include <sys/types.h> 29#include <sys/types.h>
29#include <unistd.h> 30#include <unistd.h>
@@ -302,6 +303,11 @@ printf("\n");
302 return 0; 303 return 0;
303 } 304 }
304 305
306#ifdef WARN_DUMPABLE
307 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
308 fprintf(stderr, "Error fldd: I am dumpable\n");
309#endif
310
305 // check program access 311 // check program access
306 if (access(argv[1], R_OK)) { 312 if (access(argv[1], R_OK)) {
307 fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]); 313 fprintf(stderr, "Error fldd: cannot access %s\n", argv[1]);
diff --git a/src/fnet/main.c b/src/fnet/main.c
index 95e12164e..f6316a7fe 100644
--- a/src/fnet/main.c
+++ b/src/fnet/main.c
@@ -21,6 +21,7 @@
21#include <sys/types.h> 21#include <sys/types.h>
22#include <sys/stat.h> 22#include <sys/stat.h>
23#include <sys/utsname.h> 23#include <sys/utsname.h>
24#include <sys/prctl.h>
24 25
25int arg_quiet = 0; 26int arg_quiet = 0;
26 27
@@ -64,16 +65,19 @@ printf("\n");
64 usage(); 65 usage();
65 return 1; 66 return 1;
66 } 67 }
67
68 char *quiet = getenv("FIREJAIL_QUIET");
69 if (quiet && strcmp(quiet, "yes") == 0)
70 arg_quiet = 1;
71
72 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { 68 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
73 usage(); 69 usage();
74 return 0; 70 return 0;
75 } 71 }
76 else if (argc == 3 && strcmp(argv[1], "ifup") == 0) { 72#ifdef WARN_DUMPABLE
73 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
74 fprintf(stderr, "Error fnet: I am dumpable\n");
75#endif
76 char *quiet = getenv("FIREJAIL_QUIET");
77 if (quiet && strcmp(quiet, "yes") == 0)
78 arg_quiet = 1;
79
80 if (argc == 3 && strcmp(argv[1], "ifup") == 0) {
77 net_if_up(argv[2]); 81 net_if_up(argv[2]);
78 } 82 }
79 else if (argc == 2 && strcmp(argv[1], "printif") == 0) { 83 else if (argc == 2 && strcmp(argv[1], "printif") == 0) {
diff --git a/src/fnetfilter/main.c b/src/fnetfilter/main.c
index 8124beb1a..1ca35ab56 100644
--- a/src/fnetfilter/main.c
+++ b/src/fnetfilter/main.c
@@ -18,6 +18,7 @@
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/ 19*/
20#include "../include/common.h" 20#include "../include/common.h"
21#include <sys/prctl.h>
21 22
22#define MAXBUF 4098 23#define MAXBUF 4098
23#define MAXARGS 16 24#define MAXARGS 16
@@ -180,7 +181,10 @@ printf("\n");
180 usage(); 181 usage();
181 return 1; 182 return 1;
182 } 183 }
183 184#ifdef WARN_DUMPABLE
185 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
186 fprintf(stderr, "Error fnetfilter: I am dumpable\n");
187#endif
184 char *destfile = (argc == 3)? argv[2]: argv[1]; 188 char *destfile = (argc == 3)? argv[2]: argv[1];
185 char *command = (argc == 3)? argv[1]: NULL; 189 char *command = (argc == 3)? argv[1]: NULL;
186//printf("command %s\n", command); 190//printf("command %s\n", command);
diff --git a/src/fsec-optimize/fsec_optimize.h b/src/fsec-optimize/fsec_optimize.h
index 211111641..034fde2ac 100644
--- a/src/fsec-optimize/fsec_optimize.h
+++ b/src/fsec-optimize/fsec_optimize.h
@@ -22,6 +22,7 @@
22#include "../include/common.h" 22#include "../include/common.h"
23#include "../include/seccomp.h" 23#include "../include/seccomp.h"
24#include <sys/mman.h> 24#include <sys/mman.h>
25#include <sys/prctl.h>
25 26
26// optimize.c 27// optimize.c
27struct sock_filter *duplicate(struct sock_filter *filter, int entries); 28struct sock_filter *duplicate(struct sock_filter *filter, int entries);
diff --git a/src/fsec-optimize/main.c b/src/fsec-optimize/main.c
index 416d85b88..fb13eeca8 100644
--- a/src/fsec-optimize/main.c
+++ b/src/fsec-optimize/main.c
@@ -44,6 +44,12 @@ printf("\n");
44 return 0; 44 return 0;
45 } 45 }
46 46
47#ifdef WARN_DUMPABLE
48 // check FIREJAIL_PLUGIN in order to not print a warning during make
49 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN"))
50 fprintf(stderr, "Error fsec-optimize: I am dumpable\n");
51#endif
52
47 char *fname = argv[1]; 53 char *fname = argv[1];
48 54
49 // open input file 55 // open input file
diff --git a/src/fsec-print/fsec_print.h b/src/fsec-print/fsec_print.h
index 337199288..9d17e3f18 100644
--- a/src/fsec-print/fsec_print.h
+++ b/src/fsec-print/fsec_print.h
@@ -23,6 +23,7 @@
23#include "../include/seccomp.h" 23#include "../include/seccomp.h"
24#include "../include/syscall.h" 24#include "../include/syscall.h"
25#include <sys/mman.h> 25#include <sys/mman.h>
26#include <sys/prctl.h>
26 27
27// print.c 28// print.c
28void print(struct sock_filter *filter, int entries); 29void print(struct sock_filter *filter, int entries);
diff --git a/src/fsec-print/main.c b/src/fsec-print/main.c
index ade45c881..d1f056e47 100644
--- a/src/fsec-print/main.c
+++ b/src/fsec-print/main.c
@@ -61,6 +61,11 @@ printf("\n");
61 return 0; 61 return 0;
62 } 62 }
63 63
64#ifdef WARN_DUMPABLE
65 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid())
66 fprintf(stderr, "Error fsec-print: I am dumpable\n");
67#endif
68
64 char *fname = argv[1]; 69 char *fname = argv[1];
65 70
66 // open input file 71 // open input file
diff --git a/src/fseccomp/fseccomp.h b/src/fseccomp/fseccomp.h
index e8dd083b6..e40999938 100644
--- a/src/fseccomp/fseccomp.h
+++ b/src/fseccomp/fseccomp.h
@@ -23,6 +23,7 @@
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h> 24#include <string.h>
25#include <assert.h> 25#include <assert.h>
26#include <sys/prctl.h>
26#include "../include/common.h" 27#include "../include/common.h"
27#include "../include/syscall.h" 28#include "../include/syscall.h"
28 29
diff --git a/src/fseccomp/main.c b/src/fseccomp/main.c
index 3b3c92b46..f505ca0f3 100644
--- a/src/fseccomp/main.c
+++ b/src/fseccomp/main.c
@@ -64,6 +64,16 @@ printf("\n");
64 usage(); 64 usage();
65 return 1; 65 return 1;
66 } 66 }
67 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) {
68 usage();
69 return 0;
70 }
71
72#ifdef WARN_DUMPABLE
73 // check FIREJAIL_PLUGIN in order to not print a warning during make
74 if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 1 && getuid() && getenv("FIREJAIL_PLUGIN"))
75 fprintf(stderr, "Error fseccomp: I am dumpable\n");
76#endif
67 77
68 char *quiet = getenv("FIREJAIL_QUIET"); 78 char *quiet = getenv("FIREJAIL_QUIET");
69 if (quiet && strcmp(quiet, "yes") == 0) 79 if (quiet && strcmp(quiet, "yes") == 0)
@@ -83,11 +93,7 @@ printf("\n");
83 } 93 }
84 } 94 }
85 95
86 if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") ==0) { 96 if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0)
87 usage();
88 return 0;
89 }
90 else if (argc == 2 && strcmp(argv[1], "debug-syscalls") == 0)
91 syscall_print(); 97 syscall_print();
92 else if (argc == 2 && strcmp(argv[1], "debug-syscalls32") == 0) 98 else if (argc == 2 && strcmp(argv[1], "debug-syscalls32") == 0)
93 syscall_print_32(); 99 syscall_print_32();
diff --git a/src/include/common.h b/src/include/common.h
index c65ba0d55..025f3c247 100644
--- a/src/include/common.h
+++ b/src/include/common.h
@@ -34,6 +34,9 @@
34 34
35#define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0) 35#define errExit(msg) do { char msgout[500]; snprintf(msgout, 500, "Error %s: %s:%d %s", msg, __FILE__, __LINE__, __FUNCTION__); perror(msgout); exit(1);} while (0)
36 36
37// check if processes run with dumpable flag set
38#define WARN_DUMPABLE
39
37// macro to print ip addresses in a printf statement 40// macro to print ip addresses in a printf statement
38#define PRINT_IP(A) \ 41#define PRINT_IP(A) \
39((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF)) 42((int) (((A) >> 24) & 0xFF)), ((int) (((A) >> 16) & 0xFF)), ((int) (((A) >> 8) & 0xFF)), ((int) ( (A) & 0xFF))
diff --git a/src/include/rundefs.h b/src/include/rundefs.h
index f8bcdec52..d56623907 100644
--- a/src/include/rundefs.h
+++ b/src/include/rundefs.h
@@ -99,8 +99,9 @@
99#define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share" 99#define RUN_WHITELIST_SHARE_DIR RUN_MNT_DIR "/orig-share"
100#define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module" 100#define RUN_WHITELIST_MODULE_DIR RUN_MNT_DIR "/orig-module"
101 101
102#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" 102#define RUN_XAUTHORITY_FILE RUN_MNT_DIR "/.Xauthority" // private options
103#define RUN_XAUTHORITY_SEC_FILE RUN_MNT_DIR "/sec.Xauthority" 103#define RUN_XAUTH_FILE RUN_MNT_DIR "/xauth" // x11=xorg
104#define RUN_XAUTHORITY_SEC_DIR RUN_MNT_DIR "/.sec.Xauthority" // x11=xorg
104#define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc" 105#define RUN_ASOUNDRC_FILE RUN_MNT_DIR "/.asoundrc"
105#define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname" 106#define RUN_HOSTNAME_FILE RUN_MNT_DIR "/hostname"
106#define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts" 107#define RUN_HOSTS_FILE RUN_MNT_DIR "/hosts"
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index e216531ae..3b7ba4e3d 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -273,6 +273,10 @@ $ firejail \-\-list
273$ firejail \-\-caps.print=3272 273$ firejail \-\-caps.print=3272
274 274
275.TP 275.TP
276\fB\-\-cat=name|pid filename
277Print content of file from sandbox container, see FILE TRANSFER section for more details.
278
279.TP
276\fB\-\-cgroup=tasks-file 280\fB\-\-cgroup=tasks-file
277Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file. 281Place the sandbox in the specified control group. tasks-file is the full path of cgroup tasks file.
278.br 282.br
@@ -344,7 +348,7 @@ $ firejail --dbus-system=filter --dbus-system.log --dbus-log=dbus.txt
344 348
345.TP 349.TP
346\fB\-\-dbus-system=filter|none 350\fB\-\-dbus-system=filter|none
347Set system DBus sandboxing policy. 351Set system DBus sandboxing policy.
348.br 352.br
349 353
350.br 354.br
@@ -3031,6 +3035,12 @@ These features allow the user to inspect the filesystem container of an existing
3031and transfer files between the container and the host filesystem. 3035and transfer files between the container and the host filesystem.
3032 3036
3033.TP 3037.TP
3038\fB\-\-cat=name|pid filename
3039Write content of a container file to standard out. The container is specified by name or PID.
3040If standard out is a terminal, all ASCII control characters except new line and horizontal tab
3041are replaced.
3042
3043.TP
3034\fB\-\-get=name|pid filename 3044\fB\-\-get=name|pid filename
3035Retrieve the container file and store it on the host in the current working directory. 3045Retrieve the container file and store it on the host in the current working directory.
3036The container is specified by name or PID. 3046The container is specified by name or PID.
@@ -3074,6 +3084,10 @@ $ firejail \-\-get=mybrowser ~/Downloads/xpra-clipboard.png
3074$ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png 3084$ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png
3075.br 3085.br
3076 3086
3087.br
3088$ firejail \-\-cat=mybrowser ~/.bashrc
3089.br
3090
3077.SH MONITORING 3091.SH MONITORING
3078Option \-\-list prints a list of all sandboxes. The format 3092Option \-\-list prints a list of all sandboxes. The format
3079for each process entry is as follows: 3093for each process entry is as follows:
@@ -3261,7 +3275,7 @@ Homepage: https://firejail.wordpress.com
3261\&\flfirejail-profile\fR\|(5), 3275\&\flfirejail-profile\fR\|(5),
3262\&\flfirejail-login\fR\|(5), 3276\&\flfirejail-login\fR\|(5),
3263\&\flfirejail-users\fR\|(5), 3277\&\flfirejail-users\fR\|(5),
3264.UR https://github.com/netblue30/firejail/wiki 3278.UR https://github.com/netblue30/firejail/wiki
3265.UE , 3279.UE ,
3266.UR https://github.com/netblue30/firejail 3280.UR https://github.com/netblue30/firejail
3267.UE 3281.UE