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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2932 - (hide annotations) (download) (as text)
Fri Aug 21 08:26:08 2009 UTC (14 years, 9 months ago) by kumaneko
Original Path: branches/ccs-patch/security/ccsecurity/realpath.c
File MIME type: text/x-csrc
File size: 6966 byte(s)


1 kumaneko 111 /*
2 kumaneko 2864 * security/ccsecurity/realpath.c
3 kumaneko 111 *
4 kumaneko 2030 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 kumaneko 111 *
6 kumaneko 2869 * Version: 1.7.0-pre 2009/08/08
7 kumaneko 111 *
8     * This file is applicable to both 2.4.30 and 2.6.11 and later.
9     * See README.ccs for ChangeLog.
10     *
11     */
12 kumaneko 2763
13 kumaneko 111 #include <linux/string.h>
14     #include <linux/mm.h>
15     #include <linux/utime.h>
16     #include <linux/file.h>
17     #include <linux/smp_lock.h>
18     #include <linux/module.h>
19     #include <linux/slab.h>
20     #include <asm/uaccess.h>
21     #include <asm/atomic.h>
22     #include <linux/version.h>
23 kumaneko 1052 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
24 kumaneko 111 #include <linux/namei.h>
25     #include <linux/mount.h>
26 kumaneko 2002 static const int ccs_lookup_flags = LOOKUP_FOLLOW;
27 kumaneko 111 #else
28 kumaneko 2002 static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
29 kumaneko 111 #endif
30 kumaneko 2271 #include <net/sock.h>
31 kumaneko 2719 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
32     #include <linux/kthread.h>
33     #endif
34 kumaneko 2763 #include <linux/proc_fs.h>
35 kumaneko 2854 #include "internal.h"
36 kumaneko 111
37 kumaneko 2911 static int ccs_kern_path(const char *pathname, int flags, struct path *path)
38     {
39     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
40     if (!pathname || kern_path(pathname, flags, path))
41     return -ENOENT;
42     #else
43     struct nameidata nd;
44     if (!pathname || path_lookup(pathname, flags, &nd))
45     return -ENOENT;
46     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
47     *path = nd.path;
48     #else
49     path->dentry = nd.dentry;
50     path->mnt = nd.mnt;
51     #endif
52     #endif
53     return 0;
54     }
55    
56 kumaneko 1052 /**
57 kumaneko 2002 * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
58 kumaneko 111 *
59 kumaneko 2911 * @path: Pointer to "struct path".
60 kumaneko 1052 * @buffer: Pointer to buffer to return value in.
61     * @buflen: Sizeof @buffer.
62     *
63 kumaneko 2932 * Returns the buffer on success, an error code otherwise.
64 kumaneko 1052 *
65 kumaneko 1064 * Caller holds the dcache_lock and vfsmount_lock.
66 kumaneko 111 * Based on __d_path() in fs/dcache.c
67     *
68     * If dentry is a directory, trailing '/' is appended.
69 kumaneko 2932 * /proc/pid is represented as /proc/self if pid is current.
70 kumaneko 111 */
71 kumaneko 2932 static char *ccs_get_absolute_path(struct path *path, char * const buffer,
72     const int buflen)
73 kumaneko 111 {
74 kumaneko 2932 char *pos = buffer + buflen - 1;
75 kumaneko 2911 struct dentry *dentry = path->dentry;
76     struct vfsmount *vfsmnt = path->mnt;
77 kumaneko 621 bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
78 kumaneko 2932 const char *name;
79     int len;
80 kumaneko 111
81 kumaneko 1052 if (buflen < 256)
82     goto out;
83 kumaneko 2932
84     *pos = '\0';
85 kumaneko 111 for (;;) {
86     struct dentry *parent;
87     if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
88 kumaneko 1052 if (vfsmnt->mnt_parent == vfsmnt)
89 kumaneko 111 break;
90     dentry = vfsmnt->mnt_mountpoint;
91     vfsmnt = vfsmnt->mnt_parent;
92     continue;
93     }
94     if (is_dir) {
95 kumaneko 1052 is_dir = false;
96 kumaneko 2932 *--pos = '/';
97 kumaneko 111 }
98     parent = dentry->d_parent;
99 kumaneko 2932 name = dentry->d_name.name;
100     len = dentry->d_name.len;
101     if (IS_ROOT(parent) && *name > '0' && *name <= '9' &&
102     parent->d_sb &&
103     parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
104     char *ep;
105     const pid_t pid = (pid_t) simple_strtoul(name, &ep,
106     10);
107 kumaneko 1778 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
108 kumaneko 2932 const pid_t tgid = task_tgid_nr_ns(current,
109     dentry->d_sb->
110     s_fs_info);
111     if (!*ep && pid == tgid && tgid) {
112     name = "self";
113     len = 4;
114     }
115 kumaneko 111 #else
116 kumaneko 2932 if (!*ep && pid == sys_getpid()) {
117     name = "self";
118     len = 4;
119     }
120 kumaneko 111 #endif
121     }
122 kumaneko 2932 pos -= len;
123     if (pos <= buffer)
124     goto out;
125     memmove(pos, name, len);
126     *--pos = '/';
127 kumaneko 111 dentry = parent;
128     }
129 kumaneko 2932 if (*pos == '/')
130     pos++;
131     len = dentry->d_name.len;
132     pos -= len;
133     if (pos < buffer)
134     goto out;
135     memmove(pos, dentry->d_name.name, len);
136     return pos;
137 kumaneko 111 out:
138 kumaneko 2932 return ERR_PTR(-ENOMEM);
139 kumaneko 111 }
140    
141 kumaneko 2271 #define SOCKFS_MAGIC 0x534F434B
142    
143 kumaneko 1052 /**
144 kumaneko 2932 * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
145 kumaneko 1052 *
146 kumaneko 2932 * @path: Pointer to "struct path".
147 kumaneko 1052 *
148 kumaneko 2932 * 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 kumaneko 1052 */
153 kumaneko 2932 char *ccs_realpath_from_path(struct path *path)
154 kumaneko 111 {
155 kumaneko 2932 char *buf = NULL;
156     char *cp = NULL;
157     unsigned int buf_len = PAGE_SIZE / 2;
158 kumaneko 2911 struct dentry *dentry = path->dentry;
159 kumaneko 2932 if (!dentry)
160     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 kumaneko 2271 /* Get better name for socket. */
168     if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
169     struct inode *inode = dentry->d_inode;
170 kumaneko 2284 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
171     struct sock *sk = sock ? sock->sk : NULL;
172     if (sk) {
173 kumaneko 2932 snprintf(buf, buf_len - 1,
174 kumaneko 2284 "socket:[family=%u:type=%u:protocol=%u]",
175     sk->sk_family, sk->sk_type, sk->sk_protocol);
176 kumaneko 2271 } else {
177 kumaneko 2932 snprintf(buf, buf_len - 1, "socket:[unknown]");
178 kumaneko 2271 }
179 kumaneko 2932 cp = ccs_encode(buf);
180     goto done;
181 kumaneko 2271 }
182 kumaneko 1259 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
183 kumaneko 2932 /* For "socket:[\$]" and "pipe:[\$]". */
184 kumaneko 1259 if (dentry->d_op && dentry->d_op->d_dname) {
185 kumaneko 2932 cp = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
186     if (IS_ERR(cp))
187     goto retry;
188     cp = ccs_encode(cp);
189     goto done;
190 kumaneko 1259 }
191     #endif
192 kumaneko 2932 if (!path->mnt) {
193     kfree(buf);
194     return NULL;
195     }
196 kumaneko 2911 path_get(path);
197 kumaneko 1474 ccs_realpath_lock();
198 kumaneko 2932 cp = ccs_get_absolute_path(path, buf, buf_len - 1);
199 kumaneko 1474 ccs_realpath_unlock();
200 kumaneko 2911 path_put(path);
201 kumaneko 2932 if (IS_ERR(cp))
202     goto retry;
203     cp = ccs_encode(cp);
204     done:
205 kumaneko 2711 kfree(buf);
206 kumaneko 2932 if (!cp)
207     ccs_warn_oom(__func__);
208     return cp;
209 kumaneko 111 }
210    
211 kumaneko 1052 /**
212 kumaneko 2738 * ccs_symlink_path - Get symlink's pathname.
213 kumaneko 1052 *
214     * @pathname: The pathname to solve.
215 kumaneko 2932 * @name: Pointer to "struct ccs_path_info".
216 kumaneko 1052 *
217 kumaneko 2075 * Returns 0 on success, negative value otherwise.
218 kumaneko 2932 *
219     * This function uses kzalloc(), so caller must kfree() if this function
220     * didn't return NULL.
221 kumaneko 1052 */
222 kumaneko 2932 int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
223 kumaneko 111 {
224 kumaneko 2932 char *buf;
225 kumaneko 2911 struct path path;
226     if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
227 kumaneko 2075 return -ENOENT;
228 kumaneko 2932 buf = ccs_realpath_from_path(&path);
229 kumaneko 2911 path_put(&path);
230 kumaneko 2932 if (buf) {
231     name->name = buf;
232     ccs_fill_path_info(name);
233     return 0;
234     }
235     return -ENOMEM;
236 kumaneko 111 }
237    
238 kumaneko 1052 /**
239 kumaneko 2519 * ccs_encode: Encode binary string to ascii string.
240     *
241     * @str: String in binary format.
242     *
243     * Returns pointer to @str in ascii format on success, NULL otherwise.
244     *
245 kumaneko 2711 * This function uses kzalloc(), so caller must kfree() if this function
246 kumaneko 2519 * didn't return NULL.
247     */
248     char *ccs_encode(const char *str)
249     {
250     int len = 0;
251     const char *p = str;
252     char *cp;
253     char *cp0;
254     if (!p)
255     return NULL;
256     while (*p) {
257     const unsigned char c = *p++;
258     if (c == '\\')
259     len += 2;
260     else if (c > ' ' && c < 127)
261     len++;
262     else
263     len += 4;
264     }
265     len++;
266 kumaneko 2932 /* Reserve space for appending "/". */
267     cp = kzalloc(len + 10, GFP_KERNEL);
268 kumaneko 2519 if (!cp)
269     return NULL;
270     cp0 = cp;
271     p = str;
272     while (*p) {
273     const unsigned char c = *p++;
274     if (c == '\\') {
275     *cp++ = '\\';
276     *cp++ = '\\';
277     } else if (c > ' ' && c < 127) {
278     *cp++ = c;
279     } else {
280     *cp++ = '\\';
281     *cp++ = (c >> 6) + '0';
282     *cp++ = ((c >> 3) & 7) + '0';
283     *cp++ = (c & 7) + '0';
284     }
285     }
286     return cp0;
287     }
288    
289 kumaneko 2911 /**
290     * ccs_get_path - Get dentry/vfsmmount of a pathname.
291     *
292     * @pathname: The pathname to solve.
293     * @path: Pointer to "struct path".
294     *
295     * Returns 0 on success, negative value otherwise.
296     */
297     int ccs_get_path(const char *pathname, struct path *path)
298     {
299     return ccs_kern_path(pathname, ccs_lookup_flags, path);
300     }

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