(linenum→info "unix/slp.c:2238")

glibc/2.7/elf/chroot_canon.c

    1: /* Return the canonical absolute name of a given file inside chroot.
    2:    Copyright (C) 1996,1997,1998,1999,2000,2001,2004,2005
    3:         Free Software Foundation, Inc.
    4:    This file is part of the GNU C Library.
    5: 
    6:    This program is free software; you can redistribute it and/or modify
    7:    it under the terms of the GNU General Public License as published
    8:    by the Free Software Foundation; version 2 of the License, or
    9:    (at your option) any later version.
   10: 
   11:    This program is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:    GNU General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU General Public License
   17:    along with this program; if not, write to the Free Software Foundation,
   18:    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
   19: 
   20: #include <stdlib.h>
   21: #include <string.h>
   22: #include <unistd.h>
   23: #include <limits.h>
   24: #include <sys/param.h>
   25: #include <sys/stat.h>
   26: #include <errno.h>
   27: #include <stddef.h>
   28: #include <stdint.h>
   29: 
   30: #include <ldconfig.h>
   31: 
   32: #ifndef PATH_MAX
   33: #define PATH_MAX 1024
   34: #endif
   35: 
   36: /* Return the canonical absolute name of file NAME as if chroot(CHROOT) was
   37:    done first.  A canonical name does not contain any `.', `..' components
   38:    nor any repeated path separators ('/') or symlinks.  All path components
   39:    must exist and NAME must be absolute filename.  The result is malloc'd.
   40:    The returned name includes the CHROOT prefix.  */
   41: 
   42: char *
   43: chroot_canon (const char *chroot, const char *name)
   44: {
   45:   char *rpath;
   46:   char *dest;
   47:   char *extra_buf = NULL;
   48:   char *rpath_root;
   49:   const char *start;
   50:   const char *end;
   51:   const char *rpath_limit;
   52:   int num_links = 0;
   53:   size_t chroot_len = strlen (chroot);
   54: 
   55:   if (chroot_len < 1)
   56:     {
   57:       __set_errno (EINVAL);
   58:       return NULL;
   59:     }
   60: 
   61:   rpath = malloc (chroot_len + PATH_MAX);
   62:   if (rpath == NULL)
   63:     return NULL;
   64: 
   65:   rpath_limit = rpath + chroot_len + PATH_MAX;
   66: 
   67:   rpath_root = (char *) mempcpy (rpath, chroot, chroot_len) - 1;
   68:   if (*rpath_root != '/')
   69:     *++rpath_root = '/';
   70:   dest = rpath_root + 1;
   71: 
   72:   for (start = end = name; *start; start = end)
   73:     {
   74:       struct stat64 st;
   75:       int n;
   76: 
   77:       /* Skip sequence of multiple path-separators.  */
   78:       while (*start == '/')
   79:         ++start;
   80: 
   81:       /* Find end of path component.  */
   82:       for (end = start; *end && *end != '/'; ++end)
   83:         /* Nothing.  */;
   84: 
   85:       if (end - start == 0)
   86:         break;
   87:       else if (end - start == 1 && start[0] == '.')
   88:         /* nothing */;
   89:       else if (end - start == 2 && start[0] == '.' && start[1] == '.')
   90:         {
   91:           /* Back up to previous component, ignore if at root already.  */
   92:           if (dest > rpath_root + 1)
   93:             while ((--dest)[-1] != '/');
   94:         }
   95:       else
   96:         {
   97:           size_t new_size;
   98: 
   99:           if (dest[-1] != '/')
  100:             *dest++ = '/';
  101: 
  102:           if (dest + (end - start) >= rpath_limit)
  103:             {
  104:               ptrdiff_t dest_offset = dest - rpath;
  105:               char *new_rpath;
  106: 
  107:               new_size = rpath_limit - rpath;
  108:               if (end - start + 1 > PATH_MAX)
  109:                 new_size += end - start + 1;
  110:               else
  111:                 new_size += PATH_MAX;
  112:               new_rpath = (char *) realloc (rpath, new_size);
  113:               if (new_rpath == NULL)
  114:                 goto error;
  115:               rpath = new_rpath;
  116:               rpath_limit = rpath + new_size;
  117: 
  118:               dest = rpath + dest_offset;
  119:             }
  120: 
  121:           dest = mempcpy (dest, start, end - start);
  122:           *dest = '\0';
  123: 
  124:           if (lstat64 (rpath, &st) < 0)
  125:             {
  126:               if (*end == '\0')
  127:                 goto done;
  128:               goto error;
  129:             }
  130: 
  131:           if (S_ISLNK (st.st_mode))
  132:             {
  133:               char *buf = alloca (PATH_MAX);
  134:               size_t len;
  135: 
  136:               if (++num_links > MAXSYMLINKS)
  137:                 {
  138:                   __set_errno (ELOOP);
  139:                   goto error;
  140:                 }
  141: 
  142:               n = readlink (rpath, buf, PATH_MAX);
  143:               if (n < 0)
  144:                 {
  145:                   if (*end == '\0')
  146:                     goto done;
  147:                   goto error;
  148:                 }
  149:               buf[n] = '\0';
  150: 
  151:               if (!extra_buf)
  152:                 extra_buf = alloca (PATH_MAX);
  153: 
  154:               len = strlen (end);
  155:               if ((long int) (n + len) >= PATH_MAX)
  156:                 {
  157:                   __set_errno (ENAMETOOLONG);
  158:                   goto error;
  159:                 }
  160: 
  161:               /* Careful here, end may be a pointer into extra_buf... */
  162:               memmove (&extra_buf[n], end, len + 1);
  163:               name = end = memcpy (extra_buf, buf, n);
  164: 
  165:               if (buf[0] == '/')
  166:                 dest = rpath_root + 1;        /* It's an absolute symlink */
  167:               else
  168:                 /* Back up to previous component, ignore if at root already: */
  169:                 if (dest > rpath_root + 1)
  170:                   while ((--dest)[-1] != '/');
  171:             }
  172:         }
  173:     }
  174:  done:
  175:   if (dest > rpath_root + 1 && dest[-1] == '/')
  176:     --dest;
  177:   *dest = '\0';
  178: 
  179:   return rpath;
  180: 
  181:  error:
  182:   free (rpath);
  183:   return NULL;
  184: }
Syntax (Markdown)