diff options
author | netblue30 <netblue30@yahoo.com> | 2016-11-03 09:30:30 -0400 |
---|---|---|
committer | netblue30 <netblue30@yahoo.com> | 2016-11-03 09:30:30 -0400 |
commit | e152e2d067e17be33c7e82ce438c8ae740af6a66 (patch) | |
tree | 34c1eb3a4b80b4d5973f95c23526bf4a8c1ee32f /src | |
parent | removed warning if --quiet is enabled (diff) | |
download | firejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.tar.gz firejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.tar.zst firejail-e152e2d067e17be33c7e82ce438c8ae740af6a66.zip |
fixed TOCTOU problem for --get and --put
Diffstat (limited to 'src')
-rw-r--r-- | src/firejail/ls.c | 192 | ||||
-rw-r--r-- | src/firejail/util.c | 6 |
2 files changed, 73 insertions, 125 deletions
diff --git a/src/firejail/ls.c b/src/firejail/ls.c index dba82be0b..7c5585324 100644 --- a/src/firejail/ls.c +++ b/src/firejail/ls.c | |||
@@ -324,22 +324,24 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
324 | 324 | ||
325 | // get file from sandbox and store it in the current directory | 325 | // get file from sandbox and store it in the current directory |
326 | else if (op == SANDBOX_FS_GET) { | 326 | else if (op == SANDBOX_FS_GET) { |
327 | // check source file (sandbox) | 327 | char *src_fname =fname1; |
328 | char *src_fname; | 328 | char *dest_fname = strrchr(fname1, '/'); |
329 | if (asprintf(&src_fname, "%s%s", rootdir, fname1) == -1) | 329 | if (!dest_fname || *(++dest_fname) == '\0') { |
330 | errExit("asprintf"); | 330 | fprintf(stderr, "Error: invalid file name %s\n", fname1); |
331 | EUID_ROOT(); | ||
332 | struct stat s; | ||
333 | if (stat(src_fname, &s) == -1) { | ||
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"); | ||
339 | exit(1); | 331 | exit(1); |
340 | } | 332 | } |
341 | 333 | ||
342 | // try to open the source file - we need to chroot | 334 | EUID_ROOT(); |
335 | if (arg_debug) | ||
336 | printf("copy %s to %s\n", src_fname, dest_fname); | ||
337 | |||
338 | // create a user-owned temporary file in /run/firejail directory | ||
339 | char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; | ||
340 | int fd = mkstemp(tmp_fname); | ||
341 | SET_PERMS_FD(fd, getuid(), getgid(), 0600); | ||
342 | close(fd); | ||
343 | |||
344 | // copy the source file into the temporary file - we need to chroot | ||
343 | pid_t child = fork(); | 345 | pid_t child = fork(); |
344 | if (child < 0) | 346 | if (child < 0) |
345 | errExit("fork"); | 347 | errExit("fork"); |
@@ -353,11 +355,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
353 | // drop privileges | 355 | // drop privileges |
354 | drop_privs(0); | 356 | drop_privs(0); |
355 | 357 | ||
356 | // try to read the file | 358 | // copy the file |
357 | if (access(fname1, R_OK) == -1) { | 359 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) |
358 | fprintf(stderr, "Error: Cannot read %s\n", fname1); | 360 | _exit(1); |
359 | exit(1); | ||
360 | } | ||
361 | _exit(0); | 361 | _exit(0); |
362 | } | 362 | } |
363 | 363 | ||
@@ -365,74 +365,54 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
365 | int status = 0; | 365 | int status = 0; |
366 | waitpid(child, &status, 0); | 366 | waitpid(child, &status, 0); |
367 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | 367 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); |
368 | else | 368 | else { |
369 | exit(1); | 369 | unlink(tmp_fname); |
370 | EUID_USER(); | ||
371 | |||
372 | // check destination file (host) | ||
373 | char *dest_fname = strrchr(fname1, '/'); | ||
374 | if (!dest_fname || *(++dest_fname) == '\0') { | ||
375 | fprintf(stderr, "Error: invalid file name %s\n", fname1); | ||
376 | exit(1); | 370 | exit(1); |
377 | } | 371 | } |
378 | 372 | ||
379 | if (access(dest_fname, F_OK) == -1) { | 373 | // copy the temporary file into the destionation file |
380 | // try to create the file as a regular user | 374 | child = fork(); |
381 | pid_t child = fork(); | 375 | if (child < 0) |
382 | if (child < 0) | 376 | errExit("fork"); |
383 | errExit("fork"); | 377 | if (child == 0) { |
384 | if (child == 0) { | 378 | // drop privileges |
385 | // drop privileges | 379 | drop_privs(0); |
386 | drop_privs(0); | 380 | |
387 | 381 | // copy the file | |
388 | FILE *fp = fopen(dest_fname, "w"); | 382 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) |
389 | if (!fp) { | 383 | _exit(1); |
390 | fprintf(stderr, "Error: cannot create %s\n", dest_fname); | 384 | _exit(0); |
391 | exit(1); | ||
392 | } | ||
393 | fclose(fp); | ||
394 | _exit(0); | ||
395 | } | ||
396 | |||
397 | // wait for the child to finish | ||
398 | int status = 0; | ||
399 | waitpid(child, &status, 0); | ||
400 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | ||
401 | else | ||
402 | exit(1); | ||
403 | } | 385 | } |
386 | |||
387 | // wait for the child to finish | ||
388 | status = 0; | ||
389 | waitpid(child, &status, 0); | ||
390 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | ||
404 | else { | 391 | else { |
405 | if (access(dest_fname, W_OK) == -1) { | 392 | unlink(tmp_fname); |
406 | fprintf(stderr, "Error: cannot write %s\n", dest_fname); | 393 | exit(1); |
407 | exit(1); | ||
408 | } | ||
409 | } | 394 | } |
410 | 395 | ||
411 | // copy file | 396 | // remove the temporary file |
412 | if (arg_debug) | 397 | unlink(tmp_fname); |
413 | printf("copy %s to %s\n", src_fname, dest_fname); | ||
414 | EUID_ROOT(); | ||
415 | if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644)) | ||
416 | fprintf(stderr, "Error: transfer failed\n"); | ||
417 | else | ||
418 | printf("Transfer complete\n"); | ||
419 | EUID_USER(); | 398 | EUID_USER(); |
420 | } | 399 | } |
421 | // get file from host and store it in the sandbox | 400 | // get file from host and store it in the sandbox |
422 | else if (op == SANDBOX_FS_PUT && path2) { | 401 | else if (op == SANDBOX_FS_PUT && path2) { |
423 | // verify the source file | 402 | char *src_fname =fname1; |
424 | const char *src_fname = path1; | 403 | char *dest_fname = fname2; |
425 | struct stat s; | 404 | |
426 | if (stat(src_fname, &s) == -1) { | 405 | EUID_ROOT(); |
427 | fprintf(stderr, "Error: Cannot access %s\n", fname1); | 406 | if (arg_debug) |
428 | exit(1); | 407 | printf("copy %s to %s\n", src_fname, dest_fname); |
429 | } | 408 | |
430 | if (is_dir(src_fname)) { | 409 | // create a user-owned temporary file in /run/firejail directory |
431 | fprintf(stderr, "Error: source file name is a directory\n"); | 410 | char tmp_fname[] = "/run/firejail/tmpget-XXXXXX"; |
432 | exit(1); | 411 | int fd = mkstemp(tmp_fname); |
433 | } | 412 | SET_PERMS_FD(fd, getuid(), getgid(), 0600); |
434 | 413 | close(fd); | |
435 | // try to open the source file | 414 | |
415 | // copy the source file into the temporary file - we need to chroot | ||
436 | pid_t child = fork(); | 416 | pid_t child = fork(); |
437 | if (child < 0) | 417 | if (child < 0) |
438 | errExit("fork"); | 418 | errExit("fork"); |
@@ -440,11 +420,9 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
440 | // drop privileges | 420 | // drop privileges |
441 | drop_privs(0); | 421 | drop_privs(0); |
442 | 422 | ||
443 | // try to read the file | 423 | // copy the file |
444 | if (access(src_fname, R_OK) == -1) { | 424 | if (copy_file(src_fname, tmp_fname, getuid(), getgid(), 0600)) |
445 | fprintf(stderr, "Error: Cannot read %s\n", src_fname); | 425 | _exit(1); |
446 | exit(1); | ||
447 | } | ||
448 | _exit(0); | 426 | _exit(0); |
449 | } | 427 | } |
450 | 428 | ||
@@ -452,20 +430,12 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
452 | int status = 0; | 430 | int status = 0; |
453 | waitpid(child, &status, 0); | 431 | waitpid(child, &status, 0); |
454 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | 432 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); |
455 | else | 433 | else { |
456 | exit(1); | 434 | unlink(tmp_fname); |
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); | 435 | exit(1); |
466 | } | 436 | } |
467 | 437 | ||
468 | // check write access on destination | 438 | // copy the temporary file into the destionation file |
469 | child = fork(); | 439 | child = fork(); |
470 | if (child < 0) | 440 | if (child < 0) |
471 | errExit("fork"); | 441 | errExit("fork"); |
@@ -475,25 +445,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
475 | errExit("chroot"); | 445 | errExit("chroot"); |
476 | if (chdir("/") < 0) | 446 | if (chdir("/") < 0) |
477 | errExit("chdir"); | 447 | errExit("chdir"); |
478 | 448 | ||
479 | // drop privileges | 449 | // drop privileges |
480 | drop_privs(0); | 450 | drop_privs(0); |
481 | 451 | ||
482 | if (access(path2, F_OK) == -1) { | 452 | // copy the file |
483 | FILE *fp = fopen(path2, "w"); | 453 | if (copy_file(tmp_fname, dest_fname, getuid(), getgid(), 0600)) |
484 | if (!fp) { | 454 | _exit(1); |
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); | 455 | _exit(0); |
498 | } | 456 | } |
499 | 457 | ||
@@ -501,17 +459,13 @@ void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) { | |||
501 | status = 0; | 459 | status = 0; |
502 | waitpid(child, &status, 0); | 460 | waitpid(child, &status, 0); |
503 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); | 461 | if (WIFEXITED(status) && WEXITSTATUS(status) == 0); |
504 | else | 462 | else { |
463 | unlink(tmp_fname); | ||
505 | exit(1); | 464 | exit(1); |
506 | 465 | } | |
507 | // copy file | 466 | |
508 | if (arg_debug) | 467 | // remove the temporary file |
509 | printf("copy %s to %s\n", src_fname, dest_fname); | 468 | unlink(tmp_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(); | 469 | EUID_USER(); |
516 | } | 470 | } |
517 | 471 | ||
diff --git a/src/firejail/util.c b/src/firejail/util.c index 9752504e5..a7712441e 100644 --- a/src/firejail/util.c +++ b/src/firejail/util.c | |||
@@ -176,12 +176,6 @@ int copy_file(const char *srcname, const char *destname, uid_t uid, gid_t gid, m | |||
176 | assert(srcname); | 176 | assert(srcname); |
177 | assert(destname); | 177 | assert(destname); |
178 | 178 | ||
179 | struct stat s; | ||
180 | if (stat(destname, &s) == 0) { | ||
181 | fprintf(stderr, "Error: file %s already exists\n", destname); | ||
182 | return -1; | ||
183 | } | ||
184 | |||
185 | // open source | 179 | // open source |
186 | int src = open(srcname, O_RDONLY); | 180 | int src = open(srcname, O_RDONLY); |
187 | if (src < 0) { | 181 | if (src < 0) { |