Skip to content

Commit

Permalink
add files to sandbox container (--put)
Browse files Browse the repository at this point in the history
  • Loading branch information
netblue30 committed Sep 22, 2016
1 parent 45167c5 commit 6163ff2
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 71 deletions.
1 change: 1 addition & 0 deletions RELNOTES
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ firejail (0.9.43) baseline; urgency=low
* modifs: make deb builds package based on the current configuration
* modifs: --private-tmp whitelists /tmp/.X11-unix directory
* modifs: Nvidia drivers added to --privte-dev
* feature: add files to sandbox container (--put)
* feature: blocking x11 (--x11=block)
* feature: x11 xpra, x11 xephyr, x11 block profile commands
* bugfixes
Expand Down
12 changes: 8 additions & 4 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -629,10 +629,14 @@ void x11_start_xephyr(int argc, char **argv);
void x11_block(void);

// ls.c
#define SANDBOX_FS_LS 0
#define SANDBOX_FS_GET 1
void sandboxfs_name(int op, const char *name, const char *path);
void sandboxfs(int op, pid_t pid, const char *patqh);
enum {
SANDBOX_FS_LS = 0,
SANDBOX_FS_GET,
SANDBOX_FS_PUT,
SANDBOX_FS_MAX // this should always be the last entry
};
void sandboxfs_name(int op, const char *name, const char *path1, const char *path2);
void sandboxfs(int op, pid_t pid, const char *path1, const char *path2);

// checkcfg.c
enum {
Expand Down
187 changes: 152 additions & 35 deletions src/firejail/ls.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static void print_directory(const char *path) {
free(namelist);
}

void sandboxfs_name(int op, const char *name, const char *path) {
void sandboxfs_name(int op, const char *name, const char *path1, const char *path2) {
EUID_ASSERT();

if (!name || strlen(name) == 0) {
Expand All @@ -198,10 +198,29 @@ void sandboxfs_name(int op, const char *name, const char *path) {
exit(1);
}

sandboxfs(op, pid, path);
sandboxfs(op, pid, path1, path2);
}

void sandboxfs(int op, pid_t pid, const char *path) {
char *expand_path(const char *path) {
char *fname = NULL;
if (*path == '/') {
fname = strdup(path);
if (!fname)
errExit("strdup");
}
else if (*path == '~') {
if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1)
errExit("asprintf");
}
else {
// assume the file is in current working directory
if (asprintf(&fname, "%s/%s", cfg.cwd, path) == -1)
errExit("asprintf");
}
return fname;
}

void sandboxfs(int op, pid_t pid, const char *path1, const char *path2) {
EUID_ASSERT();

// if the pid is that of a firejail process, use the pid of the first child process
Expand All @@ -228,22 +247,17 @@ void sandboxfs(int op, pid_t pid, const char *path) {
}
}

// full path or file in current directory?
char *fname;
if (*path == '/') {
fname = strdup(path);
if (!fname)
errExit("strdup");
// expand paths
char *fname1 = expand_path(path1);;
char *fname2 = NULL;
if (path2 != NULL) {
fname2 = expand_path(path2);
}
else if (*path == '~') {
if (asprintf(&fname, "%s%s", cfg.homedir, path + 1) == -1)
errExit("asprintf");
if (arg_debug) {
printf("file1 %s\n", fname1);
printf("file2 %s\n", fname2);
}
else {
fprintf(stderr, "Error: Cannot access %s\n", path);
exit(1);
}


// sandbox root directory
char *rootdir;
if (asprintf(&rootdir, "/proc/%d/root", pid) == -1)
Expand All @@ -260,21 +274,21 @@ void sandboxfs(int op, pid_t pid, const char *path) {
// drop privileges
drop_privs(0);

if (access(fname, R_OK) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname);
if (access(fname1, R_OK) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}

// list directory contents
struct stat s;
if (stat(fname, &s) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname);
if (stat(fname1, &s) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}
if (S_ISDIR(s.st_mode)) {
char *rp = realpath(fname, NULL);
char *rp = realpath(fname1, NULL);
if (!rp) {
fprintf(stderr, "Error: Cannot access %s\n", fname);
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}
if (arg_debug)
Expand All @@ -289,9 +303,9 @@ void sandboxfs(int op, pid_t pid, const char *path) {
free(dir);
}
else {
char *rp = realpath(fname, NULL);
char *rp = realpath(fname1, NULL);
if (!rp) {
fprintf(stderr, "Error: Cannot access %s\n", fname);
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}
if (arg_debug)
Expand All @@ -312,15 +326,18 @@ void sandboxfs(int op, pid_t pid, const char *path) {
else if (op == SANDBOX_FS_GET) {
// check source file (sandbox)
char *src_fname;
if (asprintf(&src_fname, "%s%s", rootdir, fname) == -1)
if (asprintf(&src_fname, "%s%s", rootdir, fname1) == -1)
errExit("asprintf");
EUID_ROOT();
struct stat s;
if (stat(src_fname, &s) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname);
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}
if (is_dir(src_fname)) {
fprintf(stderr, "Error: source file name is a directory\n");
exit(1);
}


// try to open the source file - we need to chroot
pid_t child = fork();
Expand All @@ -337,8 +354,8 @@ void sandboxfs(int op, pid_t pid, const char *path) {
drop_privs(0);

// try to read the file
if (access(fname, R_OK) == -1) {
fprintf(stderr, "Error: Cannot read %s\n", fname);
if (access(fname1, R_OK) == -1) {
fprintf(stderr, "Error: Cannot read %s\n", fname1);
exit(1);
}
exit(0);
Expand All @@ -353,9 +370,9 @@ void sandboxfs(int op, pid_t pid, const char *path) {
EUID_USER();

// check destination file (host)
char *dest_fname = strrchr(fname, '/');
char *dest_fname = strrchr(fname1, '/');
if (!dest_fname || *(++dest_fname) == '\0') {
fprintf(stderr, "Error: invalid file name %s\n", fname);
fprintf(stderr, "Error: invalid file name %s\n", fname1);
exit(1);
}

Expand All @@ -376,7 +393,7 @@ void sandboxfs(int op, pid_t pid, const char *path) {
fclose(fp);
exit(0);
}

// wait for the child to finish
int status = 0;
waitpid(child, &status, 0);
Expand All @@ -392,15 +409,115 @@ void sandboxfs(int op, pid_t pid, const char *path) {
}

// copy file
if (arg_debug)
printf("copy %s to %s\n", src_fname, dest_fname);
EUID_ROOT();
if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
fprintf(stderr, "Error: transfer failed\n");
else
printf("Transfer complete\n");
EUID_USER();
}

free(fname);
// get file from host and store it in the sandbox
else if (op == SANDBOX_FS_PUT) {
// verify the source file
const char *src_fname = path1;
struct stat s;
if (stat(src_fname, &s) == -1) {
fprintf(stderr, "Error: Cannot access %s\n", fname1);
exit(1);
}
if (is_dir(src_fname)) {
fprintf(stderr, "Error: source file name is a directory\n");
exit(1);
}

// try to open the source file
pid_t child = fork();
if (child < 0)
errExit("fork");
if (child == 0) {
// drop privileges
drop_privs(0);

// try to read the file
if (access(src_fname, R_OK) == -1) {
fprintf(stderr, "Error: Cannot read %s\n", src_fname);
exit(1);
}
exit(0);
}

// wait for the child to finish
int status = 0;
waitpid(child, &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
else
exit(1);

// check destination file (sandbox)
char *dest_fname;
if (asprintf(&dest_fname, "%s%s", rootdir, fname2) == -1)
errExit("asprintf");
EUID_ROOT();
if (is_dir(dest_fname)) {
fprintf(stderr, "Error: destination file name is a directory inside the sandbox\n");
exit(1);
}

// check write access on destination
child = fork();
if (child < 0)
errExit("fork");
if (child == 0) {
// chroot
if (chroot(rootdir) < 0)
errExit("chroot");
if (chdir("/") < 0)
errExit("chdir");

// drop privileges
drop_privs(0);

if (access(path2, F_OK) == -1) {
FILE *fp = fopen(path2, "w");
if (!fp) {
fprintf(stderr, "Error: cannot create %s\n", path2);
exit(1);
}
fclose(fp);
}
else {
if (access(path2, W_OK) == -1) {
fprintf(stderr, "Error: cannot write %s\n", path2);
exit(1);
}
}

exit(0);
}

// wait for the child to finish
status = 0;
waitpid(child, &status, 0);
if (WIFEXITED(status) && WEXITSTATUS(status) == 0);
else
exit(1);

// copy file
if (arg_debug)
printf("copy %s to %s\n", src_fname, dest_fname);
EUID_ROOT();
if (copy_file(src_fname, dest_fname, getuid(), getgid(), 0644))
fprintf(stderr, "Error: transfer failed\n");
else
printf("Transfer complete\n");
EUID_USER();
}

if (fname2)
free(fname2);
free(fname1);
free(rootdir);

exit(0);
Expand Down
43 changes: 39 additions & 4 deletions src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,9 +536,44 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
// get file
pid_t pid;
if (read_pid(argv[i] + 6, &pid) == 0)
sandboxfs(SANDBOX_FS_GET, pid, path);
sandboxfs(SANDBOX_FS_GET, pid, path, NULL);
else
sandboxfs_name(SANDBOX_FS_GET, argv[i] + 6, path);
sandboxfs_name(SANDBOX_FS_GET, argv[i] + 6, path, NULL);
exit(0);
}
else {
fprintf(stderr, "Error: --get feature is disabled in Firejail configuration file\n");
exit(1);
}
}
else if (strncmp(argv[i], "--put=", 6) == 0) {
if (checkcfg(CFG_FILE_TRANSFER)) {
logargs(argc, argv);

// verify path
if ((i + 3) != argc) {
fprintf(stderr, "Error: invalid --put option, 2 paths expected\n");
exit(1);
}
char *path1 = argv[i + 1];
invalid_filename(path1);
if (strstr(path1, "..")) {
fprintf(stderr, "Error: invalid file name %s\n", path1);
exit(1);
}
char *path2 = argv[i + 2];
invalid_filename(path2);
if (strstr(path2, "..")) {
fprintf(stderr, "Error: invalid file name %s\n", path2);
exit(1);
}

// get file
pid_t pid;
if (read_pid(argv[i] + 6, &pid) == 0)
sandboxfs(SANDBOX_FS_PUT, pid, path1, path2);
else
sandboxfs_name(SANDBOX_FS_PUT, argv[i] + 6, path1, path2);
exit(0);
}
else {
Expand All @@ -565,9 +600,9 @@ static void run_cmd_and_exit(int i, int argc, char **argv) {
// list directory contents
pid_t pid;
if (read_pid(argv[i] + 5, &pid) == 0)
sandboxfs(SANDBOX_FS_LS, pid, path);
sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
else
sandboxfs_name(SANDBOX_FS_LS, argv[i] + 5, path);
sandboxfs_name(SANDBOX_FS_LS, argv[i] + 5, path, NULL);
exit(0);
}
else {
Expand Down
Loading

0 comments on commit 6163ff2

Please sign in to comment.