オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Diff of /trunk/1.7.x/ccs-patch/security/ccsecurity/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2930 by kumaneko, Fri Aug 21 01:55:58 2009 UTC revision 2932 by kumaneko, Fri Aug 21 08:26:08 2009 UTC
# Line 60  static int ccs_kern_path(const char *pat Line 60  static int ccs_kern_path(const char *pat
60   * @buffer: Pointer to buffer to return value in.   * @buffer: Pointer to buffer to return value in.
61   * @buflen: Sizeof @buffer.   * @buflen: Sizeof @buffer.
62   *   *
63   * Returns 0 on success, -ENOMEM otherwise.   * Returns the buffer on success, an error code otherwise.
64   *   *
65   * Caller holds the dcache_lock and vfsmount_lock.   * Caller holds the dcache_lock and vfsmount_lock.
66   * Based on __d_path() in fs/dcache.c   * Based on __d_path() in fs/dcache.c
67   *   *
68   * If dentry is a directory, trailing '/' is appended.   * If dentry is a directory, trailing '/' is appended.
69   * Characters out of 0x20 < c < 0x7F range are converted to   * /proc/pid is represented as /proc/self if pid is current.
  * \ooo style octal string.  
  * Character \ is converted to \\ string.  
70   */   */
71  static int ccs_get_absolute_path(struct path *path, char *buffer, int buflen)  static char *ccs_get_absolute_path(struct path *path, char * const buffer,
72                                       const int buflen)
73  {  {
74          char *start = buffer;          char *pos = buffer + buflen - 1;
         char *end = buffer + buflen;  
75          struct dentry *dentry = path->dentry;          struct dentry *dentry = path->dentry;
76          struct vfsmount *vfsmnt = path->mnt;          struct vfsmount *vfsmnt = path->mnt;
77          bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));          bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
78            const char *name;
79            int len;
80    
81          if (buflen < 256)          if (buflen < 256)
82                  goto out;                  goto out;
83            
84          *--end = '\0';          *pos = '\0';
         buflen--;  
   
85          for (;;) {          for (;;) {
86                  struct dentry *parent;                  struct dentry *parent;
   
87                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {                  if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
                         /* Global root? */  
88                          if (vfsmnt->mnt_parent == vfsmnt)                          if (vfsmnt->mnt_parent == vfsmnt)
89                                  break;                                  break;
90                          dentry = vfsmnt->mnt_mountpoint;                          dentry = vfsmnt->mnt_mountpoint;
# Line 97  static int ccs_get_absolute_path(struct Line 93  static int ccs_get_absolute_path(struct
93                  }                  }
94                  if (is_dir) {                  if (is_dir) {
95                          is_dir = false;                          is_dir = false;
96                          *--end = '/';                          *--pos = '/';
                         buflen--;  
97                  }                  }
98                  parent = dentry->d_parent;                  parent = dentry->d_parent;
99                  {                  name = dentry->d_name.name;
100                          const char *sp = dentry->d_name.name;                  len = dentry->d_name.len;
101                          const char *cp = sp + dentry->d_name.len - 1;                  if (IS_ROOT(parent) && *name > '0' && *name <= '9' &&
102                          unsigned char c;                      parent->d_sb &&
103                        parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
104                          /*                          char *ep;
105                           * Exception: Use /proc/self/ rather than                          const pid_t pid = (pid_t) simple_strtoul(name, &ep,
106                           * /proc/\$/ for current process.                                                                   10);
                          */  
                         if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' &&  
                             parent->d_sb &&  
                             parent->d_sb->s_magic == PROC_SUPER_MAGIC) {  
                                 char *ep;  
                                 const pid_t pid  
                                         = (pid_t) simple_strtoul(sp, &ep, 10);  
107  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
108                                  const pid_t tgid                          const pid_t tgid = task_tgid_nr_ns(current,
109                                          = task_tgid_nr_ns(current,                                                             dentry->d_sb->
110                                                            dentry->d_sb->                                                             s_fs_info);
111                                                            s_fs_info);                          if (!*ep && pid == tgid && tgid) {
112                                  if (!*ep && pid == tgid && tgid) {                                  name = "self";
113                                          sp = "self";                                  len = 4;
                                         cp = sp + 3;  
                                 }  
 #else  
                                 if (!*ep && pid == sys_getpid()) {  
                                         sp = "self";  
                                         cp = sp + 3;  
                                 }  
 #endif  
114                          }                          }
115    #else
116                          while (sp <= cp) {                          if (!*ep && pid == sys_getpid()) {
117                                  c = *(unsigned char *) cp;                                  name = "self";
118                                  if (c == '\\') {                                  len = 4;
                                         buflen -= 2;  
                                         if (buflen < 0)  
                                                 goto out;  
                                         *--end = '\\';  
                                         *--end = '\\';  
                                 } else if (c > ' ' && c < 127) {  
                                         if (--buflen < 0)  
                                                 goto out;  
                                         *--end = (char) c;  
                                 } else {  
                                         buflen -= 4;  
                                         if (buflen < 0)  
                                                 goto out;  
                                         *--end = (c & 7) + '0';  
                                         *--end = ((c >> 3) & 7) + '0';  
                                         *--end = (c >> 6) + '0';  
                                         *--end = '\\';  
                                 }  
                                 cp--;  
119                          }                          }
120                          if (--buflen < 0)  #endif
                                 goto out;  
                         *--end = '/';  
121                  }                  }
122                    pos -= len;
123                    if (pos <= buffer)
124                            goto out;
125                    memmove(pos, name, len);
126                    *--pos = '/';
127                  dentry = parent;                  dentry = parent;
128          }          }
129          if (*end == '/') {          if (*pos == '/')
130                  buflen++;                  pos++;
131                  end++;          len = dentry->d_name.len;
132          }          pos -= len;
133          {          if (pos < buffer)
134                  const char *sp = dentry->d_name.name;                  goto out;
135                  const char *cp = sp + dentry->d_name.len - 1;          memmove(pos, dentry->d_name.name, len);
136                  unsigned char c;          return pos;
                 while (sp <= cp) {  
                         c = *(unsigned char *) cp;  
                         if (c == '\\') {  
                                 buflen -= 2;  
                                 if (buflen < 0)  
                                         goto out;  
                                 *--end = '\\';  
                                 *--end = '\\';  
                         } else if (c > ' ' && c < 127) {  
                                 if (--buflen < 0)  
                                         goto out;  
                                 *--end = (char) c;  
                         } else {  
                                 buflen -= 4;  
                                 if (buflen < 0)  
                                         goto out;  
                                 *--end = (c & 7) + '0';  
                                 *--end = ((c >> 3) & 7) + '0';  
                                 *--end = (c >> 6) + '0';  
                                 *--end = '\\';  
                         }  
                         cp--;  
                 }  
         }  
         /* Move the pathname to the top of the buffer. */  
         memmove(start, end, strlen(end) + 1);  
         return 0;  
137   out:   out:
138          return -ENOMEM;          return ERR_PTR(-ENOMEM);
139  }  }
140    
141  #define SOCKFS_MAGIC 0x534F434B  #define SOCKFS_MAGIC 0x534F434B
142    
143  /**  /**
144   * ccs_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.   * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
145   *   *
146   * @path:        Pointer to "struct path".   * @path: Pointer to "struct path".
  * @newname:     Pointer to buffer to return value in.  
  * @newname_len: Size of @newname.  
147   *   *
148   * Returns 0 on success, negative value otherwise.   * Returns the realpath of the given @path on success, NULL otherwise.
149     *
150     * This function uses kzalloc(), so caller must kfree() if this function
151     * didn't return NULL.
152   */   */
153  static int ccs_realpath_from_path2(struct path *path, char *newname,  char *ccs_realpath_from_path(struct path *path)
                                    int newname_len)  
154  {  {
155          int error = -EINVAL;          char *buf = NULL;
156            char *cp = NULL;
157            unsigned int buf_len = PAGE_SIZE / 2;
158          struct dentry *dentry = path->dentry;          struct dentry *dentry = path->dentry;
159          if (!dentry || !newname || newname_len <= 2048)          if (!dentry)
160                  goto out;                  return NULL;
161     retry:
162            buf_len <<= 1;
163            kfree(buf);
164            buf = kmalloc(buf_len, GFP_KERNEL);
165            if (!buf)
166                    goto done;
167          /* Get better name for socket. */          /* Get better name for socket. */
168          if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {          if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
169                  struct inode *inode = dentry->d_inode;                  struct inode *inode = dentry->d_inode;
170                  struct socket *sock = inode ? SOCKET_I(inode) : NULL;                  struct socket *sock = inode ? SOCKET_I(inode) : NULL;
171                  struct sock *sk = sock ? sock->sk : NULL;                  struct sock *sk = sock ? sock->sk : NULL;
172                  if (sk) {                  if (sk) {
173                          snprintf(newname, newname_len - 1,                          snprintf(buf, buf_len - 1,
174                                   "socket:[family=%u:type=%u:protocol=%u]",                                   "socket:[family=%u:type=%u:protocol=%u]",
175                                   sk->sk_family, sk->sk_type, sk->sk_protocol);                                   sk->sk_family, sk->sk_type, sk->sk_protocol);
176                  } else {                  } else {
177                          snprintf(newname, newname_len - 1, "socket:[unknown]");                          snprintf(buf, buf_len - 1, "socket:[unknown]");
178                  }                  }
179                  return 0;                  cp = ccs_encode(buf);
180                    goto done;
181          }          }
182  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)  #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
183            /* For "socket:[\$]" and "pipe:[\$]". */
184          if (dentry->d_op && dentry->d_op->d_dname) {          if (dentry->d_op && dentry->d_op->d_dname) {
185                  /* For "socket:[\$]" and "pipe:[\$]". */                  cp = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
186                  static const int offset = 1536;                  if (IS_ERR(cp))
187                  char *dp = newname;                          goto retry;
188                  char *sp = dentry->d_op->d_dname(dentry, newname + offset,                  cp = ccs_encode(cp);
189                                                   newname_len - offset);                  goto done;
                 if (IS_ERR(sp)) {  
                         error = PTR_ERR(sp);  
                         goto out;  
                 }  
                 error = -ENOMEM;  
                 newname += offset;  
                 while (1) {  
                         const unsigned char c = *(unsigned char *) sp++;  
                         if (c == '\\') {  
                                 if (dp + 2 >= newname)  
                                         break;  
                                 *dp++ = '\\';  
                                 *dp++ = '\\';  
                         } else if (c > ' ' && c < 127) {  
                                 if (dp + 1 >= newname)  
                                         break;  
                                 *dp++ = (char) c;  
                         } else if (c) {  
                                 if (dp + 4 >= newname)  
                                         break;  
                                 *dp++ = '\\';  
                                 *dp++ = (c >> 6) + '0';  
                                 *dp++ = ((c >> 3) & 7) + '0';  
                                 *dp++ = (c & 7) + '0';  
                         } else {  
                                 *dp = '\0';  
                                 return 0;  
                         }  
                 }  
                 goto out;  
190          }          }
191  #endif  #endif
192          if (!path->mnt)          if (!path->mnt) {
193                  goto out;                  kfree(buf);
194                    return NULL;
195            }
196          path_get(path);          path_get(path);
197          ccs_realpath_lock();          ccs_realpath_lock();
198          error = ccs_get_absolute_path(path, newname, newname_len);          cp = ccs_get_absolute_path(path, buf, buf_len - 1);
199          ccs_realpath_unlock();          ccs_realpath_unlock();
200          path_put(path);          path_put(path);
201   out:          if (IS_ERR(cp))
202          if (error)                  goto retry;
203                  printk(KERN_WARNING "ccs_realpath: Pathname too long. (%d)\n",          cp = ccs_encode(cp);
204                         error);   done:
         return error;  
 }  
   
 /**  
  * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.  
  *  
  * @path: Pointer to "struct path".  
  *  
  * Returns the realpath of the given @path on success, NULL otherwise.  
  *  
  * These functions use kzalloc(), so caller must kfree()  
  * if these functions didn't return NULL.  
  */  
 char *ccs_realpath_from_path(struct path *path)  
 {  
         char *buf = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);  
         if (buf &&  
             ccs_realpath_from_path2(path, buf, CCS_MAX_PATHNAME_LEN - 2) == 0)  
                 return buf;  
205          kfree(buf);          kfree(buf);
206          return NULL;          if (!cp)
207                    ccs_warn_oom(__func__);
208            return cp;
209  }  }
210    
211  /**  /**
212   * ccs_symlink_path - Get symlink's pathname.   * ccs_symlink_path - Get symlink's pathname.
213   *   *
214   * @pathname: The pathname to solve.   * @pathname: The pathname to solve.
215   * @ee:       Pointer to "struct ccs_execve_entry".   * @name:     Pointer to "struct ccs_path_info".
216   *   *
217   * Returns 0 on success, negative value otherwise.   * Returns 0 on success, negative value otherwise.
218     *
219     * This function uses kzalloc(), so caller must kfree() if this function
220     * didn't return NULL.
221   */   */
222  int ccs_symlink_path(const char *pathname, struct ccs_execve_entry *ee)  int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
223  {  {
224            char *buf;
225          struct path path;          struct path path;
         int ret;  
226          if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))          if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
227                  return -ENOENT;                  return -ENOENT;
228          ret = ccs_realpath_from_path2(&path, ee->program_path,          buf = ccs_realpath_from_path(&path);
                                       CCS_MAX_PATHNAME_LEN - 1);  
229          path_put(&path);          path_put(&path);
230          return ret;          if (buf) {
231                    name->name = buf;
232                    ccs_fill_path_info(name);
233                    return 0;
234            }
235            return -ENOMEM;
236  }  }
237    
238  /**  /**
# Line 354  char *ccs_encode(const char *str) Line 263  char *ccs_encode(const char *str)
263                          len += 4;                          len += 4;
264          }          }
265          len++;          len++;
266          cp = kzalloc(len, GFP_KERNEL);          /* Reserve space for appending "/". */
267            cp = kzalloc(len + 10, GFP_KERNEL);
268          if (!cp)          if (!cp)
269                  return NULL;                  return NULL;
270          cp0 = cp;          cp0 = cp;

Legend:
Removed from v.2930  
changed lines
  Added in v.2932

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26