aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar netblue30 <netblue30@yahoo.com>2016-09-22 13:40:32 -0400
committerLibravatar netblue30 <netblue30@yahoo.com>2016-09-22 13:40:32 -0400
commit6163ff2a6fd8fa0858ff4f7c57d45dc57c8f39b1 (patch)
tree38ef7124e4706eca260adfca467890f6f6edff44
parent--get fixes (diff)
downloadfirejail-6163ff2a6fd8fa0858ff4f7c57d45dc57c8f39b1.tar.gz
firejail-6163ff2a6fd8fa0858ff4f7c57d45dc57c8f39b1.tar.zst
firejail-6163ff2a6fd8fa0858ff4f7c57d45dc57c8f39b1.zip
add files to sandbox container (--put)
-rw-r--r--RELNOTES1
-rw-r--r--src/firejail/firejail.h12
-rw-r--r--src/firejail/ls.c187
-rw-r--r--src/firejail/main.c43
-rw-r--r--src/firejail/usage.c27
-rw-r--r--src/man/firejail.txt17
6 files changed, 216 insertions, 71 deletions
diff --git a/RELNOTES b/RELNOTES
index 31b948c71..84ad8bce7 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -4,6 +4,7 @@ firejail (0.9.43) baseline; urgency=low
4 * modifs: make deb builds package based on the current configuration 4 * modifs: make deb builds package based on the current configuration
5 * modifs: --private-tmp whitelists /tmp/.X11-unix directory 5 * modifs: --private-tmp whitelists /tmp/.X11-unix directory
6 * modifs: Nvidia drivers added to --privte-dev 6 * modifs: Nvidia drivers added to --privte-dev
7 * feature: add files to sandbox container (--put)
7 * feature: blocking x11 (--x11=block) 8 * feature: blocking x11 (--x11=block)
8 * feature: x11 xpra, x11 xephyr, x11 block profile commands 9 * feature: x11 xpra, x11 xephyr, x11 block profile commands
9 * bugfixes 10 * bugfixes
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h
index bee93ca85..e3bf5e187 100644
--- a/src/firejail/firejail.h
+++ b/src/firejail/firejail.h
@@ -629,10 +629,14 @@ void x11_start_xephyr(int argc, char **argv);
629void x11_block(void); 629void x11_block(void);
630 630
631// ls.c 631// ls.c
632#define SANDBOX_FS_LS 0 632enum {
633#define SANDBOX_FS_GET 1 633 SANDBOX_FS_LS = 0,
634void sandboxfs_name(int op, const char *name, const char *path); 634 SANDBOX_FS_GET,
635void sandboxfs(int op, pid_t pid, const char *patqh); 635 SANDBOX_FS_PUT,
636 SANDBOX_FS_MAX // this should always be the last entry
637};
638void sandboxfs_name(int op, const char *name, const char *path1, const char *path2);
639void sandboxfs(int op, pid_t pid, const char *path1, const char *path2);
636 640
637// checkcfg.c 641// checkcfg.c
638enum { 642enum {
diff --git a/src/firejail/ls.c b/src/firejail/ls.c
index 4c1992278..14991ba94 100644
--- a/src/firejail/ls.c
+++ b/src/firejail/ls.c
@@ -185,7 +185,7 @@ static void print_directory(const char *path) {
185 free(namelist); 185 free(namelist);
186} 186}
187 187
188void sandboxfs_name(int op, const char *name, const char *path) { 188void sandboxfs_name(int op, const char *name, const char *path1, const char *path2) {
189 EUID_ASSERT(); 189 EUID_ASSERT();
190 190
191 if (!name || strlen(name) == 0) { 191 if (!name || strlen(name) == 0) {
@@ -198,10 +198,29 @@ void sandboxfs_name(int op, const char *name, const char *path) {
198 exit(1); 198 exit(1);
199 } 199 }
200 200
201 sandboxfs(op, pid, path); 201 sandboxfs(op, pid, path1, path2);
202} 202}
203 203
204void sandboxfs(int op, pid_t pid, const char *path) { 204char *expand_path(const char *path) {
205 char *fname = NULL;
206 if (*path == '/') {
207 fname = strdup(path);
208 if (!fname)
209 errExit("strdup");
210 }
211 else if (*path == '~') {
212 if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1)
213 errExit("asprintf");
214 }
215 else {
216 // assume the file is in current working directory
217 if (asprintf(&fname, "%s/%s", cfg.cwd, path) == -1)
218 errExit("asprintf");
219 }
220 return fname;
221}
222
223void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
205 EUID_ASSERT(); 224 EUID_ASSERT();
206 225
207 // if the pid is that of a firejail process, use the pid of the first child process 226 // if the pid is that of a firejail process, use the pid of the first child process
@@ -228,22 +247,17 @@ void sandboxfs(int op, pid_t pid, const char *path) {
228 } 247 }
229 } 248 }
230 249
231 // full path or file in current directory? 250 // expand paths
232 char *fname; 251 char *fname1 = expand_path(path1);;
233 if (*path == '/') { 252 char *fname2 = NULL;
234 fname = strdup(path); 253 if (path2 != NULL) {
235 if (!fname) 254 fname2 = expand_path(path2);
236 errExit("strdup");
237 } 255 }
238 else if (*path == '~') { 256 if (arg_debug) {
239 if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1) 257 printf("file1 %s\n", fname1);
240 errExit("asprintf"); 258 printf("file2 %s\n", fname2);
241 } 259 }
242 else { 260
243 fprintf(stderr, "Error: Cannot access %s\n", path);
244 exit(1);
245 }
246
247 // sandbox root directory 261 // sandbox root directory
248 char *rootdir; 262 char *rootdir;
249 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1) 263 if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
@@ -260,21 +274,21 @@ void sandboxfs(int op, pid_t pid, const char *path) {
260 // drop privileges 274 // drop privileges
261 drop_privs(0); 275 drop_privs(0);
262 276
263 if (access(fname, R_OK) == -1) { 277 if (access(fname1, R_OK) == -1) {
264 fprintf(stderr, "Error: Cannot access %s\n", fname); 278 fprintf(stderr, "Error: Cannot access %s\n", fname1);
265 exit(1); 279 exit(1);
266 } 280 }
267 281
268 // list directory contents 282 // list directory contents
269 struct stat s; 283 struct stat s;
270 if (stat(fname, &s) == -1) { 284 if (stat(fname1, &s) == -1) {
271 fprintf(stderr, "Error: Cannot access %s\n", fname); 285 fprintf(stderr, "Error: Cannot access %s\n", fname1);
272 exit(1); 286 exit(1);
273 } 287 }
274 if (S_ISDIR(s.st_mode)) { 288 if (S_ISDIR(s.st_mode)) {
275 char *rp = realpath(fname, NULL); 289 char *rp = realpath(fname1, NULL);
276 if (!rp) { 290 if (!rp) {
277 fprintf(stderr, "Error: Cannot access %s\n", fname); 291 fprintf(stderr, "Error: Cannot access %s\n", fname1);
278 exit(1); 292 exit(1);
279 } 293 }
280 if (arg_debug) 294 if (arg_debug)
@@ -289,9 +303,9 @@ void sandboxfs(int op, pid_t pid, const char *path) {
289 free(dir); 303 free(dir);
290 } 304 }
291 else { 305 else {
292 char *rp = realpath(fname, NULL); 306 char *rp = realpath(fname1, NULL);
293 if (!rp) { 307 if (!rp) {
294 fprintf(stderr, "Error: Cannot access %s\n", fname); 308 fprintf(stderr, "Error: Cannot access %s\n", fname1);
295 exit(1); 309 exit(1);
296 } 310 }
297 if (arg_debug) 311 if (arg_debug)
@@ -312,15 +326,18 @@ void sandboxfs(int op, pid_t pid, const char *path) {
312 else if (op == SANDBOX_FS_GET) { 326 else if (op == SANDBOX_FS_GET) {
313 // check source file (sandbox) 327 // check source file (sandbox)
314 char *src_fname; 328 char *src_fname;
315 if (asprintf(&src_fname, "%s%s", rootdir, fname) == -1) 329 if (asprintf(&src_fname, "%s%s", rootdir, fname1) == -1)
316 errExit("asprintf"); 330 errExit("asprintf");
317 EUID_ROOT(); 331 EUID_ROOT();
318 struct stat s; 332 struct stat s;
319 if (stat(src_fname, &s) == -1) { 333 if (stat(src_fname, &s) == -1) {
320 fprintf(stderr, "Error: Cannot access %s\n", fname); 334 fprintf(stderr, "Error: Cannot access %s\n", fname1);
335 exit(1);
336 }
337 if (is_dir(src_fname)) {
338 fprintf(stderr, "Error: source file name is a directory\n");
321 exit(1); 339 exit(1);
322 } 340 }
323
324 341
325 // try to open the source file - we need to chroot 342 // try to open the source file - we need to chroot
326 pid_t child = fork(); 343 pid_t child = fork();
@@ -337,8 +354,8 @@ void sandboxfs(int op, pid_t pid, const char *path) {
337 drop_privs(0); 354 drop_privs(0);
338 355
339 // try to read the file 356 // try to read the file
340 if (access(fname, R_OK) == -1) { 357 if (access(fname1, R_OK) == -1) {
341 fprintf(stderr, "Error: Cannot read %s\n", fname); 358 fprintf(stderr, "Error: Cannot read %s\n", fname1);
342 exit(1); 359 exit(1);
343 } 360 }
344 exit(0); 361 exit(0);
@@ -353,9 +370,9 @@ void sandboxfs(int op, pid_t pid, const char *path) {
353 EUID_USER(); 370 EUID_USER();
354 371
355 // check destination file (host) 372 // check destination file (host)
356 char *dest_fname = strrchr(fname, '/'); 373 char *dest_fname = strrchr(fname1, '/');
357 if (!dest_fname || *(++dest_fname) == '\0') { 374 if (!dest_fname || *(++dest_fname) == '\0') {
358 fprintf(stderr, "Error: invalid file name %s\n", fname); 375 fprintf(stderr, "Error: invalid file name %s\n", fname1);
359 exit(1); 376 exit(1);
360 } 377 }
361 378
@@ -376,7 +393,7 @@ void sandboxfs(int op, pid_t pid, const char *path) {
376 fclose(fp); 393 fclose(fp);
377 exit(0); 394 exit(0);
378 } 395 }
379 396
380 // wait for the child to finish 397 // wait for the child to finish
381 int status = 0; 398 int status = 0;
382 waitpid(child, &status, 0); 399 waitpid(child, &status, 0);
@@ -392,6 +409,8 @@ void sandboxfs(int op, pid_t pid, const char *path) {
392 } 409 }
393 410
394 // copy file 411 // copy file
412 if (arg_debug)
413 printf("copy %s to %s\n", src_fname, dest_fname);
395 EUID_ROOT(); 414 EUID_ROOT();
396 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644)) 415 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
397 fprintf(stderr, "Error: transfer failed\n"); 416 fprintf(stderr, "Error: transfer failed\n");
@@ -399,8 +418,106 @@ void sandboxfs(int op, pid_t pid, const char *path) {
399 printf("Transfer complete\n"); 418 printf("Transfer complete\n");
400 EUID_USER(); 419 EUID_USER();
401 } 420 }
402 421 // get file from host and store it in the sandbox
403 free(fname); 422 else if (op == SANDBOX_FS_PUT) {
423 // verify the source file
424 const char *src_fname = path1;
425 struct stat s;
426 if (stat(src_fname, &s) == -1) {
427 fprintf(stderr, "Error: Cannot access %s\n", fname1);
428 exit(1);
429 }
430 if (is_dir(src_fname)) {
431 fprintf(stderr, "Error: source file name is a directory\n");
432 exit(1);
433 }
434
435 // try to open the source file
436 pid_t child = fork();
437 if (child < 0)
438 errExit("fork");
439 if (child == 0) {
440 // drop privileges
441 drop_privs(0);
442
443 // try to read the file
444 if (access(src_fname, R_OK) == -1) {
445 fprintf(stderr, "Error: Cannot read %s\n", src_fname);
446 exit(1);
447 }
448 exit(0);
449 }
450
451 // wait for the child to finish
452 int status = 0;
453 waitpid(child, &status, 0);
454 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
455 else
456 exit(1);
457
458 // check destination file (sandbox)
459 char *dest_fname;
460 if (asprintf(&dest_fname, "%s%s", rootdir, fname2) == -1)
461 errExit("asprintf");
462 EUID_ROOT();
463 if (is_dir(dest_fname)) {
464 fprintf(stderr, "Error: destination file name is a directory inside the sandbox\n");
465 exit(1);
466 }
467
468 // check write access on destination
469 child = fork();
470 if (child < 0)
471 errExit("fork");
472 if (child == 0) {
473 // chroot
474 if (chroot(rootdir) < 0)
475 errExit("chroot");
476 if (chdir("/") < 0)
477 errExit("chdir");
478
479 // drop privileges
480 drop_privs(0);
481
482 if (access(path2, F_OK) == -1) {
483 FILE *fp = fopen(path2, "w");
484 if (!fp) {
485 fprintf(stderr, "Error: cannot create %s\n", path2);
486 exit(1);
487 }
488 fclose(fp);
489 }
490 else {
491 if (access(path2, W_OK) == -1) {
492 fprintf(stderr, "Error: cannot write %s\n", path2);
493 exit(1);
494 }
495 }
496
497 exit(0);
498 }
499
500 // wait for the child to finish
501 status = 0;
502 waitpid(child, &status, 0);
503 if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
504 else
505 exit(1);
506
507 // copy file
508 if (arg_debug)
509 printf("copy %s to %s\n", src_fname, dest_fname);
510 EUID_ROOT();
511 if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
512 fprintf(stderr, "Error: transfer failed\n");
513 else
514 printf("Transfer complete\n");
515 EUID_USER();
516 }
517
518 if (fname2)
519 free(fname2);
520 free(fname1);
404 free(rootdir); 521 free(rootdir);
405 522
406 exit(0); 523 exit(0);
diff --git a/src/firejail/main.c b/src/firejail/main.c
index e171919d1..3afecbe62 100644
--- a/src/firejail/main.c
+++ b/src/firejail/main.c
@@ -536,9 +536,44 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
536 // get file 536 // get file
537 pid_t pid; 537 pid_t pid;
538 if (read_pid(argv[i] + 6, &pid) == 0) 538 if (read_pid(argv[i] + 6, &pid) == 0)
539 sandboxfs(SANDBOX_FS_GET, pid, path); 539 sandboxfs(SANDBOX_FS_GET, pid, path, NULL);
540 else 540 else
541 sandboxfs_name(SANDBOX_FS_GET, argv[i] + 6, path); 541 sandboxfs_name(SANDBOX_FS_GET, argv[i] + 6, path, NULL);
542 exit(0);
543 }
544 else {
545 fprintf(stderr, "Error: --get feature is disabled in Firejail configuration file\n");
546 exit(1);
547 }
548 }
549 else if (strncmp(argv[i], "--put=", 6) == 0) {
550 if (checkcfg(CFG_FILE_TRANSFER)) {
551 logargs(argc, argv);
552
553 // verify path
554 if ((i + 3) != argc) {
555 fprintf(stderr, "Error: invalid --put option, 2 paths expected\n");
556 exit(1);
557 }
558 char *path1 = argv[i + 1];
559 invalid_filename(path1);
560 if (strstr(path1, "..")) {
561 fprintf(stderr, "Error: invalid file name %s\n", path1);
562 exit(1);
563 }
564 char *path2 = argv[i + 2];
565 invalid_filename(path2);
566 if (strstr(path2, "..")) {
567 fprintf(stderr, "Error: invalid file name %s\n", path2);
568 exit(1);
569 }
570
571 // get file
572 pid_t pid;
573 if (read_pid(argv[i] + 6, &pid) == 0)
574 sandboxfs(SANDBOX_FS_PUT, pid, path1, path2);
575 else
576 sandboxfs_name(SANDBOX_FS_PUT, argv[i] + 6, path1, path2);
542 exit(0); 577 exit(0);
543 } 578 }
544 else { 579 else {
@@ -565,9 +600,9 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
565 // list directory contents 600 // list directory contents
566 pid_t pid; 601 pid_t pid;
567 if (read_pid(argv[i] + 5, &pid) == 0) 602 if (read_pid(argv[i] + 5, &pid) == 0)
568 sandboxfs(SANDBOX_FS_LS, pid, path); 603 sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
569 else 604 else
570 sandboxfs_name(SANDBOX_FS_LS, argv[i] + 5, path); 605 sandboxfs_name(SANDBOX_FS_LS, argv[i] + 5, path, NULL);
571 exit(0); 606 exit(0);
572 } 607 }
573 else { 608 else {
diff --git a/src/firejail/usage.c b/src/firejail/usage.c
index 52d9bbe7e..c08ec18a0 100644
--- a/src/firejail/usage.c
+++ b/src/firejail/usage.c
@@ -185,31 +185,6 @@ void usage(void) {
185 printf("\t$HOME/.firejail/<NAME> directory. (OverlayFS support is required in\n"); 185 printf("\t$HOME/.firejail/<NAME> directory. (OverlayFS support is required in\n");
186 printf("\tLinux kernel for this option to work). \n\n"); 186 printf("\tLinux kernel for this option to work). \n\n");
187 187
188#if 0 // disabled for now, it could be used to overwrite system directories
189 printf(" --overlay-path=path - mount a filesystem overlay on top of the current\n");
190 printf("\tfilesystem. The upper filesystem layer is persistent, and stored in\n");
191 printf("\tthe specified path. (OverlayFS support is required in Linux kernel for\n");
192 printf("\tthis option to work). \n\n");
193
194.TP
195\fB\-\-overlay-path=path
196Mount a filesystem overlay on top of the current filesystem. Unlike the regular filesystem container,
197the system directories are mounted read-write. All filesystem modifications go into the overlay.
198The overlay is stored in the specified path. The created overlay can be reused between multiple sessions.
199.br
200
201.br
202OverlayFS support is required in Linux kernel for this option to work.
203OverlayFS was officially introduced in Linux kernel version 3.18.
204This option is not available on Grsecurity systems.
205.br
206
207.br
208Example:
209.br
210$ firejail \-\-overlay-path=~/jails/jail1 firefox
211#endif
212
213 printf(" --overlay-tmpfs - mount a filesystem overlay on top of the current\n"); 188 printf(" --overlay-tmpfs - mount a filesystem overlay on top of the current\n");
214 printf("\tfilesystem. The upper layer is stored in a tmpfs filesystem,\n"); 189 printf("\tfilesystem. The upper layer is stored in a tmpfs filesystem,\n");
215 printf("\tand it is discarded when the sandbox is closed. (OverlayFS\n"); 190 printf("\tand it is discarded when the sandbox is closed. (OverlayFS\n");
@@ -246,6 +221,8 @@ $ firejail \-\-overlay-path=~/jails/jail1 firefox
246 printf(" --protocol.print=name|pid - print the protocol filter for the sandbox\n"); 221 printf(" --protocol.print=name|pid - print the protocol filter for the sandbox\n");
247 printf("\tidentified by name or PID.\n\n"); 222 printf("\tidentified by name or PID.\n\n");
248 223
224 printf(" --put=name|pid src-filename dest-filename - put a file in sandbox container.\n\n");
225
249 printf(" --quiet - turn off Firejail's output.\n\n"); 226 printf(" --quiet - turn off Firejail's output.\n\n");
250 printf(" --read-only=dirname_or_filename - set directory or file read-only..\n\n"); 227 printf(" --read-only=dirname_or_filename - set directory or file read-only..\n\n");
251 printf(" --read-write=dirname_or_filename - set directory or file read-write..\n\n"); 228 printf(" --read-write=dirname_or_filename - set directory or file read-write..\n\n");
diff --git a/src/man/firejail.txt b/src/man/firejail.txt
index a906de0c9..29b0f05a2 100644
--- a/src/man/firejail.txt
+++ b/src/man/firejail.txt
@@ -11,7 +11,7 @@ firejail [OPTIONS] [program and arguments]
11File transfer from an existing sandbox 11File transfer from an existing sandbox
12.PP 12.PP
13.RS 13.RS
14firejail {\-\-ls | \-\-get} dir_or_filename 14firejail {\-\-ls | \-\-get | \-\-put} dir_or_filename
15.RE 15.RE
16.PP 16.PP
17Network traffic shaping for an existing sandbox: 17Network traffic shaping for an existing sandbox:
@@ -1224,6 +1224,9 @@ $ firejail \-\-protocol.print=3272
1224.br 1224.br
1225unix,inet,inet6,netlink 1225unix,inet,inet6,netlink
1226.TP 1226.TP
1227\fB\-\-put=name|pid src-filename dest-filename
1228Put a file in sandbox container, see \fBFILE TRANSFER\fR section for more details.
1229.TP
1227\fB\-\-quiet 1230\fB\-\-quiet
1228Turn off Firejail's output. 1231Turn off Firejail's output.
1229.TP 1232.TP
@@ -1787,12 +1790,16 @@ and transfer files from the container to the host filesystem.
1787.TP 1790.TP
1788\fB\-\-get=name|pid filename 1791\fB\-\-get=name|pid filename
1789Retrieve the container file and store it on the host in the current working directory. 1792Retrieve the container file and store it on the host in the current working directory.
1790The container is specified by name or PID. Full path is needed for filename. 1793The container is specified by name or PID.
1791 1794
1792.TP 1795.TP
1793\fB\-\-ls=name|pid dir_or_filename 1796\fB\-\-ls=name|pid dir_or_filename
1794List container files. The container is specified by name or PID. 1797List container files. The container is specified by name or PID.
1795Full path is needed for dir_or_filename. 1798
1799.TP
1800\fB\-\-put=name|pid src-filename dest-filename
1801Put src-filename in sandbox container.
1802The container is specified by name or PID.
1796 1803
1797.TP 1804.TP
1798Examples: 1805Examples:
@@ -1818,7 +1825,11 @@ drwxr-xr-x netblue netblue 4096 ..
1818 1825
1819.br 1826.br
1820$ firejail \-\-get=mybrowser ~/Downloads/xpra-clipboard.png 1827$ firejail \-\-get=mybrowser ~/Downloads/xpra-clipboard.png
1828.br
1821 1829
1830.br
1831$ firejail \-\-put=mybrowser xpra-clipboard.png ~/Downloads/xpra-clipboard.png
1832.br
1822 1833
1823.SH TRAFFIC SHAPING 1834.SH TRAFFIC SHAPING
1824Network bandwidth is an expensive resource shared among all sandboxes running on a system. 1835Network bandwidth is an expensive resource shared among all sandboxes running on a system.