diff options
-rw-r--r-- | guts/glob.c | 24 | ||||
-rw-r--r-- | guts/glob64.c | 24 | ||||
-rw-r--r-- | guts/readlinkat.c | 13 | ||||
-rw-r--r-- | pseudo_util.c | 1 | ||||
-rw-r--r-- | pseudo_wrappers.c | 28 |
5 files changed, 76 insertions, 14 deletions
diff --git a/guts/glob.c b/guts/glob.c index a8eec64..0012179 100644 --- a/guts/glob.c +++ b/guts/glob.c @@ -6,9 +6,31 @@ * wrap_glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) { * int rc = -1; */ + char *rpattern = NULL; + int alloced = 0; - rc = real_glob(pattern, flags, errfunc, pglob); + /* note: no canonicalization */ + if (pattern && (*pattern == '/') && pseudo_chroot_len) { + size_t len = strlen(pattern) + pseudo_chroot_len + 2; + rpattern = malloc(len); + if (!rpattern) { + errno = ENOMEM; + return GLOB_NOSPACE; + } + snprintf(rpattern, len, "%s/%s", pseudo_chroot, pattern); + alloced = 1; + } + rc = real_glob(alloced ? rpattern : pattern, flags, errfunc, pglob); + + free(rpattern); + + if (rc == 0) { + unsigned int i; + for (i = 0; i < pglob->gl_pathc; ++i) { + pseudo_dechroot(pglob->gl_pathv[i], (size_t) -1); + } + } /* return rc; * } */ diff --git a/guts/glob64.c b/guts/glob64.c index 8258d47..ccac6e4 100644 --- a/guts/glob64.c +++ b/guts/glob64.c @@ -6,9 +6,31 @@ * wrap_glob64(const char *pattern, int flags, int (*errfunc)(const char *, int), glob64_t *pglob) { * int rc = -1; */ + char *rpattern = NULL; + int alloced = 0; - rc = real_glob64(pattern, flags, errfunc, pglob); + /* note: no canonicalization */ + if (pattern && (*pattern == '/') && pseudo_chroot_len) { + size_t len = strlen(pattern) + pseudo_chroot_len + 2; + rpattern = malloc(len); + if (!rpattern) { + errno = ENOMEM; + return GLOB_NOSPACE; + } + snprintf(rpattern, len, "%s/%s", pseudo_chroot, pattern); + alloced = 1; + } + rc = real_glob64(alloced ? rpattern : pattern, flags, errfunc, pglob); + + free(rpattern); + + if (rc == 0) { + unsigned int i; + for (i = 0; i < pglob->gl_pathc; ++i) { + pseudo_dechroot(pglob->gl_pathv[i], (size_t) -1); + } + } /* return rc; * } */ diff --git a/guts/readlinkat.c b/guts/readlinkat.c index 8009af5..d483ab5 100644 --- a/guts/readlinkat.c +++ b/guts/readlinkat.c @@ -9,18 +9,7 @@ rc = real_readlinkat(dirfd, path, buf, bufsiz); if (rc > 0) { - /* strip out a leading chrooted part */ - if (pseudo_chroot_len && - !memcmp(buf, pseudo_chroot, pseudo_chroot_len)) { - if (buf[pseudo_chroot_len] == '/') { - memmove(buf, buf + pseudo_chroot_len, rc - pseudo_chroot_len); - rc -= pseudo_chroot_len; - } else if (buf[pseudo_chroot_len] == '\0') { - buf[0] = '/'; - rc = 1; - } - /* otherwise, it's not really a match... */ - } + rc = pseudo_dechroot(buf, rc); } /* return rc; diff --git a/pseudo_util.c b/pseudo_util.c index 2cf6585..8b579f9 100644 --- a/pseudo_util.c +++ b/pseudo_util.c @@ -664,3 +664,4 @@ pseudo_etc_file(char *file, char **search_dirs, int dircount) { filename, file); return open(filename, O_RDONLY); } + diff --git a/pseudo_wrappers.c b/pseudo_wrappers.c index 84bdce7..fd864f1 100644 --- a/pseudo_wrappers.c +++ b/pseudo_wrappers.c @@ -37,6 +37,7 @@ static pthread_t pseudo_mutex_holder; static int pseudo_mutex_recursion = 0; static int pseudo_getlock(void); static void pseudo_droplock(void); +static size_t pseudo_dechroot(char *, size_t); extern char *program_invocation_short_name; @@ -86,6 +87,33 @@ pseudo_enosys(const char *func) { abort(); } +/* de-chroot a string. + * note that readlink() yields an unterminated buffer, so + * must pass in the correct length. Buffers are null-terminated + * unconditionally if they are modified -- the modification would + * shorten the string, so there will be space for the NUL, so + * this is safe even for stuff like readlink(). + */ +static size_t +pseudo_dechroot(char *s, size_t len) { + if (len == (size_t) -1) + len = strlen(s); + if (pseudo_chroot_len && len >= pseudo_chroot_len && + !memcmp(s, pseudo_chroot, pseudo_chroot_len)) { + if (s[pseudo_chroot_len] == '/') { + memmove(s, s + pseudo_chroot_len, len - pseudo_chroot_len); + len -= pseudo_chroot_len; + s[len] = '\0'; + } else if (s[pseudo_chroot_len] == '\0') { + s[0] = '/'; + len = 1; + s[len] = '\0'; + } + /* otherwise, it's not really a match... */ + } + return len; +} + static int pseudo_populate_wrappers(void) { int i; |