diff options
Diffstat (limited to 'REORG.TODO/elf/chroot_canon.c')
-rw-r--r-- | REORG.TODO/elf/chroot_canon.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/REORG.TODO/elf/chroot_canon.c b/REORG.TODO/elf/chroot_canon.c new file mode 100644 index 0000000000..78cd6f4a5e --- /dev/null +++ b/REORG.TODO/elf/chroot_canon.c @@ -0,0 +1,177 @@ +/* Return the canonical absolute name of a given file inside chroot. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <limits.h> +#include <sys/stat.h> +#include <errno.h> +#include <stddef.h> +#include <stdint.h> + +#include <eloop-threshold.h> +#include <ldconfig.h> + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +/* Return the canonical absolute name of file NAME as if chroot(CHROOT) was + done first. A canonical name does not contain any `.', `..' components + nor any repeated path separators ('/') or symlinks. All path components + must exist and NAME must be absolute filename. The result is malloc'd. + The returned name includes the CHROOT prefix. */ + +char * +chroot_canon (const char *chroot, const char *name) +{ + char *rpath; + char *dest; + char *extra_buf = NULL; + char *rpath_root; + const char *start; + const char *end; + const char *rpath_limit; + int num_links = 0; + size_t chroot_len = strlen (chroot); + + if (chroot_len < 1) + { + __set_errno (EINVAL); + return NULL; + } + + rpath = xmalloc (chroot_len + PATH_MAX); + + rpath_limit = rpath + chroot_len + PATH_MAX; + + rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1; + if (*rpath_root != '/') + *++rpath_root = '/'; + dest = rpath_root + 1; + + for (start = end = name; *start; start = end) + { + struct stat64 st; + + /* Skip sequence of multiple path-separators. */ + while (*start == '/') + ++start; + + /* Find end of path component. */ + for (end = start; *end && *end != '/'; ++end) + /* Nothing. */; + + if (end - start == 0) + break; + else if (end - start == 1 && start[0] == '.') + /* nothing */; + else if (end - start == 2 && start[0] == '.' && start[1] == '.') + { + /* Back up to previous component, ignore if at root already. */ + if (dest > rpath_root + 1) + while ((--dest)[-1] != '/'); + } + else + { + size_t new_size; + + if (dest[-1] != '/') + *dest++ = '/'; + + if (dest + (end - start) >= rpath_limit) + { + ptrdiff_t dest_offset = dest - rpath; + char *new_rpath; + + new_size = rpath_limit - rpath; + if (end - start + 1 > PATH_MAX) + new_size += end - start + 1; + else + new_size += PATH_MAX; + new_rpath = (char *) xrealloc (rpath, new_size); + rpath = new_rpath; + rpath_limit = rpath + new_size; + + dest = rpath + dest_offset; + } + + dest = mempcpy (dest, start, end - start); + *dest = '\0'; + + if (lstat64 (rpath, &st) < 0) + { + if (*end == '\0') + goto done; + goto error; + } + + if (S_ISLNK (st.st_mode)) + { + char *buf = alloca (PATH_MAX); + size_t len; + + if (++num_links > __eloop_threshold ()) + { + __set_errno (ELOOP); + goto error; + } + + ssize_t n = readlink (rpath, buf, PATH_MAX - 1); + if (n < 0) + { + if (*end == '\0') + goto done; + goto error; + } + buf[n] = '\0'; + + if (!extra_buf) + extra_buf = alloca (PATH_MAX); + + len = strlen (end); + if (len >= PATH_MAX - n) + { + __set_errno (ENAMETOOLONG); + goto error; + } + + /* Careful here, end may be a pointer into extra_buf... */ + memmove (&extra_buf[n], end, len + 1); + name = end = memcpy (extra_buf, buf, n); + + if (buf[0] == '/') + dest = rpath_root + 1; /* It's an absolute symlink */ + else + /* Back up to previous component, ignore if at root already: */ + if (dest > rpath_root + 1) + while ((--dest)[-1] != '/'); + } + } + } + done: + if (dest > rpath_root + 1 && dest[-1] == '/') + --dest; + *dest = '\0'; + + return rpath; + + error: + free (rpath); + return NULL; +} |