Skip to content

Commit

Permalink
Merge pull request #3998 from Tomin1/first_fixes
Browse files Browse the repository at this point in the history
Upstreaming a set of fixes from Sailfish's packaging
  • Loading branch information
netblue30 authored Feb 24, 2021
2 parents 9c54ed4 + 89ba89b commit 9a47e2d
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 15 deletions.
56 changes: 48 additions & 8 deletions src/fcopy/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,47 @@ static void mkdir_attr(const char *fname, mode_t mode, uid_t uid, gid_t gid) {
}
}

static char *proc_pid_to_self(const char *target)
{
char *use_target = 0;
char *proc_pid = 0;

if (!(use_target = canonicalize_file_name(target)))
goto done;

// target is under /proc/<PID>?
static const char proc[] = "/proc/";
if (strncmp(use_target, proc, sizeof proc - 1))
goto done;

int digit = use_target[sizeof proc - 1];
if (digit < '1' || digit > '9')
goto done;

// check where /proc/self points to
static const char proc_self[] = "/proc/self";
if (!(proc_pid = canonicalize_file_name(proc_self)))
goto done;

// redirect /proc/PID/xxx -> /proc/self/XXX
size_t pfix = strlen(proc_pid);
if (strncmp(use_target, proc_pid, pfix))
goto done;

if (use_target[pfix] != 0 && use_target[pfix] != '/')
goto done;

char *tmp;
if (asprintf(&tmp, "%s%s", proc_self, use_target + pfix) != -1) {
if (arg_debug)
fprintf(stderr, "SYMLINK %s\n --> %s\n", use_target, tmp);
free(use_target), use_target = tmp;
}

done:
free(proc_pid);
return use_target;
}

void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) {
(void) mode;
Expand All @@ -183,7 +224,7 @@ void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid,
if (lstat(linkpath, &s) == 0)
return;

char *rp = realpath(target, NULL);
char *rp = proc_pid_to_self(target);
if (rp) {
if (symlink(rp, linkpath) == -1) {
free(rp);
Expand Down Expand Up @@ -227,16 +268,14 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str
first = 0;
else if (!arg_quiet)
fprintf(stderr, "Warning fcopy: skipping %s, file already present\n", infname);
free(outfname);
return 0;
goto out;
}

// extract mode and ownership
if (stat(infname, &s) != 0) {
if (!arg_quiet)
fprintf(stderr, "Warning fcopy: skipping %s, cannot find inode\n", infname);
free(outfname);
return 0;
goto out;
}
uid_t uid = s.st_uid;
gid_t gid = s.st_gid;
Expand All @@ -246,8 +285,7 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str
if ((s.st_size + size_cnt) > copy_limit) {
fprintf(stderr, "Error fcopy: size limit of %lu MB reached\n", (copy_limit / 1024) / 1024);
size_limit_reached = 1;
free(outfname);
return 0;
goto out;
}

file_cnt++;
Expand All @@ -262,7 +300,8 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str
else if (ftype == FTW_SL) {
copy_link(infname, outfname, mode, uid, gid);
}

out:
free(outfname);
return(0);
}

Expand Down Expand Up @@ -295,6 +334,7 @@ static char *check(const char *src) {
return rsrc; // normal exit from the function

errexit:
free(rsrc);
fprintf(stderr, "Error fcopy: invalid file %s\n", src);
exit(1);
}
Expand Down
2 changes: 2 additions & 0 deletions src/firejail/firejail.h
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,8 @@ void network_set_run_file(pid_t pid);

// fs_etc.c
void fs_machineid(void);
void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list);
void fs_private_dir_mount(const char *private_dir, const char *private_run_dir);
void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list);

// no_sandbox.c
Expand Down
20 changes: 19 additions & 1 deletion src/firejail/fs_etc.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ static void duplicate(const char *fname, const char *private_dir, const char *pr
}


void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) {
void fs_private_dir_copy(const char *private_dir, const char *private_run_dir, const char *private_list) {
assert(private_dir);
assert(private_run_dir);
assert(private_list);
Expand Down Expand Up @@ -185,6 +185,19 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c
free(dlist);
fs_logger_print();
}
}

void fs_private_dir_mount(const char *private_dir, const char *private_run_dir) {
assert(private_dir);
assert(private_run_dir);

// nothing to do if directory does not exist
struct stat s;
if (stat(private_dir, &s) == -1) {
if (arg_debug)
printf("Cannot find %s\n", private_dir);
return;
}

if (arg_debug)
printf("Mount-bind %s on top of %s\n", private_run_dir, private_dir);
Expand All @@ -199,3 +212,8 @@ void fs_private_dir_list(const char *private_dir, const char *private_run_dir, c

fmessage("Private %s installed in %0.2f ms\n", private_dir, timetrace_end());
}

void fs_private_dir_list(const char *private_dir, const char *private_run_dir, const char *private_list) {
fs_private_dir_copy(private_dir, private_run_dir, private_list);
fs_private_dir_mount(private_dir, private_run_dir);
}
4 changes: 2 additions & 2 deletions src/firejail/fs_mkdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ static void mkdir_recursive(char *path) {
struct stat s;

if (chdir("/")) {
fprintf(stderr, "Error: can't chdir to /");
fprintf(stderr, "Error: can't chdir to /\n");
return;
}

Expand All @@ -63,7 +63,7 @@ static void mkdir_recursive(char *path) {
return;
}
if (chdir(subdir)) {
fprintf(stderr, "Error: can't chdir to %s", subdir);
fprintf(stderr, "Error: can't chdir to %s\n", subdir);
return;
}

Expand Down
2 changes: 1 addition & 1 deletion src/firejail/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ static void check_network(Bridge *br) {
else if (br->ipsandbox) { // for macvlan check network range
char *rv = in_netrange(br->ipsandbox, br->ip, br->mask);
if (rv) {
fprintf(stderr, "%s", rv);
fprintf(stderr, "%s\n", rv);
exit(1);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/firejail/network_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void net_configure_sandbox_ip(Bridge *br) {
// check network range
char *rv = in_netrange(br->ipsandbox, br->ip, br->mask);
if (rv) {
fprintf(stderr, "%s", rv);
fprintf(stderr, "%s\n", rv);
exit(1);
}
// send an ARP request and check if there is anybody on this IP address
Expand Down
25 changes: 23 additions & 2 deletions src/firejail/sandbox.c
Original file line number Diff line number Diff line change
Expand Up @@ -969,8 +969,29 @@ int sandbox(void* sandbox_arg) {
else if (arg_overlay)
fwarning("private-etc feature is disabled in overlay\n");
else {
fs_private_dir_list("/etc", RUN_ETC_DIR, cfg.etc_private_keep);
fs_private_dir_list("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE
/* Current /etc/passwd and /etc/group files are bind
* mounted filtered versions of originals. Leaving
* them underneath private-etc mount causes problems
* in devices with older kernels, e.g. attempts to
* update the real /etc/passwd file yield EBUSY.
*
* As we do want to retain filtered /etc content:
* 1. duplicate /etc content to RUN_ETC_DIR
* 2. unmount bind mounts from /etc
* 3. mount RUN_ETC_DIR at /etc
*/
fs_private_dir_copy("/etc", RUN_ETC_DIR, cfg.etc_private_keep);
fs_private_dir_copy("/usr/etc", RUN_USR_ETC_DIR, cfg.etc_private_keep); // openSUSE

if (umount2("/etc/group", MNT_DETACH) == -1)
fprintf(stderr, "/etc/group: unmount: %m\n");

if (umount2("/etc/passwd", MNT_DETACH) == -1)
fprintf(stderr, "/etc/passwd: unmount: %m\n");

fs_private_dir_mount("/etc", RUN_ETC_DIR);
fs_private_dir_mount("/usr/etc", RUN_USR_ETC_DIR);

// create /etc/ld.so.preload file again
if (need_preload)
fs_trace_preload();
Expand Down

0 comments on commit 9a47e2d

Please sign in to comment.