Search
SailfishOS Open Build Service
>
Projects
>
nemo
:
devel:hw
:
samsung
:
treltexx
>
firejail
> _service:tar_git:0005-Retain-symlink-chains.patch
Log In
Username
Password
Cancel
Overview
Repositories
Revisions
Requests
Users
Advanced
Attributes
Meta
File _service:tar_git:0005-Retain-symlink-chains.patch of Package firejail
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Simo Piiroinen <simo.piiroinen@jolla.com> Date: Tue, 19 Oct 2021 11:43:31 +0300 Subject: [PATCH] Retain symlink chains When firejail is constructing e.g. private-etc directory content, symlink targets are fully resolved during duplication. This breaks all symlink chains and can be problematic if such chains are intentional. For example Sailfish OS timezone setup relies on chain like /etc/localtime -> /var/lib/timed/localtime -> /usr/share/zoneinfo/xxx. Where the intermediate part is in a time daemon writable directory, and having firejail squeeze it into /etc/localtime -> /usr/share/zoneinfo/xxx effectively freezes timezone of sandboxed applications to whatever it was when the application was started. Similar problems occur with symlinks that go though dynamic/virtual entries such as /proc/self. Retain symlink chains by duplicating symlinks as-is instead of resolving the final target. Remove the now unnecessary special case code that was used to rectify /proc/PID/xxx type symlinks back into /proc/self/xxx form. Signed-off-by: Simo Piiroinen <simo.piiroinen@jolla.com> --- src/fcopy/main.c | 125 +++++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 75 deletions(-) diff --git a/src/fcopy/main.c b/src/fcopy/main.c index b0b7f7024..c99b56b7e 100644 --- a/src/fcopy/main.c +++ b/src/fcopy/main.c @@ -22,6 +22,7 @@ #include <ftw.h> #include <errno.h> #include <pwd.h> +#include <limits.h> #include <fcntl.h> #ifndef O_PATH @@ -181,78 +182,58 @@ 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) { - assert(target); - char *use_target = 0; - char *proc_pid = 0; +void copy_link(const char *target, const char *linkpath) { + int failed = 1; + char *linkdata = NULL; - if (!(use_target = realpath(target, NULL))) - goto done; - - // target is under /proc/<PID>? - static const char proc[] = "/proc/"; - if (strncmp(use_target, proc, sizeof(proc) - 1)) - goto done; + // if the link is already there, don't create it + struct stat s; + if (lstat(linkpath, &s) == 0) + goto success; - int digit = use_target[sizeof(proc) - 1]; - if (digit < '1' || digit > '9') - goto done; + // read source symlink + if (lstat(target, &s) == -1) + goto failure; - // check where /proc/self points to - static const char proc_self[] = "/proc/self"; - proc_pid = realpath(proc_self, NULL); - if (proc_pid == NULL) - goto done; + if (!S_ISLNK(s.st_mode)) + goto failure; - // redirect /proc/PID/xxx -> /proc/self/XXX - size_t pfix = strlen(proc_pid); - if (strncmp(use_target, proc_pid, pfix)) - goto done; + ssize_t linksize = s.st_size ? (s.st_size + 1) : PATH_MAX; + if (!(linkdata = malloc(linksize))) + goto failure; - if (use_target[pfix] != 0 && use_target[pfix] != '/') - goto done; + ssize_t rc = readlink(target, linkdata, linksize); + if (rc < 0) { + if (!arg_quiet) + fprintf(stderr, "Error fcopy: readlink %s failed: %m\n", target); + goto failure; + } - 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; + if (rc >= linksize) { + if (!arg_quiet) + fprintf(stderr, "Error fcopy: readlink %s buffer overflow\n", target); + goto failure; } - else - errExit("asprintf"); -done: - if (proc_pid) - free(proc_pid); - return use_target; -} + linkdata[rc] = 0; -void copy_link(const char *target, const char *linkpath, mode_t mode, uid_t uid, gid_t gid) { - (void) mode; - (void) uid; - (void) gid; + // duplicate at the given path + if (symlink(linkdata, linkpath) == -1) { + if (!arg_quiet) + fprintf(stderr, "Error fcopy: creating %s symlink failed: %m\n", linkpath); + goto failure; + } - // if the link is already there, don't create it - struct stat s; - if (lstat(linkpath, &s) == 0) - return; + if (arg_debug) + fprintf(stderr, "fcopy: created symlink: %s -> %s\n", linkpath, linkdata); - char *rp = proc_pid_to_self(target); - if (rp) { - if (symlink(rp, linkpath) == -1) { - free(rp); - goto errout; - } - free(rp); - } - else - goto errout; +success: + failed = 0; +failure: + if (failed && !arg_quiet) + fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", linkpath); - return; -errout: - if (!arg_quiet) - fprintf(stderr, "Warning fcopy: cannot create symbolic link %s\n", target); + free(linkdata); } @@ -310,7 +291,7 @@ static int fs_copydir(const char *infname, const struct stat *st, int ftype, str mkdir_attr(outfname, mode, uid, gid); } else if (ftype == FTW_SL) { - copy_link(infname, outfname, mode, uid, gid); + copy_link(infname, outfname); } out: free(outfname); @@ -396,22 +377,16 @@ static void duplicate_file(const char *src, const char *dest, struct stat *s) { static void duplicate_link(const char *src, const char *dest, struct stat *s) { char *rsrc = check(src); // we drop the result and use the original name char *rdest = check(dest); - uid_t uid = s->st_uid; - gid_t gid = s->st_gid; - mode_t mode = s->st_mode; - // build destination file name - char *name; - // char *ptr = strrchr(rsrc, '/'); - char *ptr = strrchr(src, '/'); - ptr++; - if (asprintf(&name, "%s/%s", rdest, ptr) == -1) - errExit("asprintf"); - - // copy - copy_link(rsrc, name, mode, uid, gid); + const char *linkname = strrchr(src, '/'); + if (linkname++) { + char *linkpath = NULL; + if (asprintf(&linkpath, "%s/%s", rdest, linkname) == -1) + errExit("asprintf"); + copy_link(src, linkpath); + free(linkpath); + } - free(name); free(rsrc); free(rdest); }