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

Subversion リポジトリの参照

Contents of /branches/ccs-patch/security/ccsecurity/realpath.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3871 - (show annotations) (download) (as text)
Sun Aug 1 01:42:05 2010 UTC (13 years, 10 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 8599 byte(s)


1 /*
2 * security/ccsecurity/realpath.c
3 *
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 *
6 * Version: 1.8.0-pre 2010/08/01
7 *
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
13 #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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
24 #include <linux/namei.h>
25 #include <linux/mount.h>
26 static const int ccs_lookup_flags = LOOKUP_FOLLOW;
27 #else
28 static const int ccs_lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
29 #endif
30 #include <net/sock.h>
31 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0)
32 #include <linux/kthread.h>
33 #endif
34 #include <linux/proc_fs.h>
35 #include "internal.h"
36
37 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 /**
57 * ccs_get_absolute_path - Get the path of a dentry but ignores chroot'ed root.
58 *
59 * @path: Pointer to "struct path".
60 * @buffer: Pointer to buffer to return value in.
61 * @buflen: Sizeof @buffer.
62 *
63 * Returns the buffer on success, an error code otherwise.
64 *
65 * Caller holds the dcache_lock and vfsmount_lock.
66 * Based on __d_path() in fs/dcache.c
67 *
68 * If dentry is a directory, trailing '/' is appended.
69 */
70 static char *ccs_get_absolute_path(struct path *path, char * const buffer,
71 const int buflen)
72 {
73 char *pos = buffer + buflen - 1;
74 struct dentry *dentry = path->dentry;
75 struct vfsmount *vfsmnt = path->mnt;
76 const char *name;
77 int len;
78
79 if (buflen < 256)
80 goto out;
81
82 *pos = '\0';
83 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
84 *--pos = '/';
85 for (;;) {
86 struct dentry *parent;
87 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
88 if (vfsmnt->mnt_parent == vfsmnt)
89 break;
90 dentry = vfsmnt->mnt_mountpoint;
91 vfsmnt = vfsmnt->mnt_parent;
92 continue;
93 }
94 parent = dentry->d_parent;
95 name = dentry->d_name.name;
96 len = dentry->d_name.len;
97 pos -= len;
98 if (pos <= buffer)
99 goto out;
100 memmove(pos, name, len);
101 *--pos = '/';
102 dentry = parent;
103 }
104 if (*pos == '/')
105 pos++;
106 len = dentry->d_name.len;
107 pos -= len;
108 if (pos < buffer)
109 goto out;
110 memmove(pos, dentry->d_name.name, len);
111 return pos;
112 out:
113 return ERR_PTR(-ENOMEM);
114 }
115
116 /**
117 * ccs_get_dentry_path - Get the path of a dentry but ignores chroot'ed root.
118 *
119 * @dentry: Pointer to "struct dentry".
120 * @buffer: Pointer to buffer to return value in.
121 * @buflen: Sizeof @buffer.
122 *
123 * Returns the buffer on success, an error code otherwise.
124 *
125 * Caller holds the dcache_lock.
126 * Based on dentry_path() in fs/dcache.c
127 *
128 * If dentry is a directory, trailing '/' is appended.
129 */
130 static char *ccs_get_dentry_path(struct dentry *dentry, char * const buffer,
131 const int buflen)
132 {
133 char *pos = buffer + buflen - 1;
134 if (buflen < 256)
135 goto out;
136 *pos = '\0';
137 if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
138 *--pos = '/';
139 while (!IS_ROOT(dentry)) {
140 struct dentry *parent = dentry->d_parent;
141 const char *name = dentry->d_name.name;
142 const int len = dentry->d_name.len;
143 pos -= len;
144 if (pos <= buffer)
145 goto out;
146 memmove(pos, name, len);
147 *--pos = '/';
148 dentry = parent;
149 }
150 return pos;
151 out:
152 return ERR_PTR(-ENOMEM);
153 }
154
155 #define SOCKFS_MAGIC 0x534F434B
156
157 /**
158 * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
159 *
160 * @path: Pointer to "struct path".
161 *
162 * Returns the realpath of the given @path on success, NULL otherwise.
163 *
164 * This function uses kzalloc(), so caller must kfree() if this function
165 * didn't return NULL.
166 */
167 char *ccs_realpath_from_path(struct path *path)
168 {
169 char *buf = NULL;
170 char *name = NULL;
171 unsigned int buf_len = PAGE_SIZE / 2;
172 struct dentry *dentry = path->dentry;
173 struct super_block *sb;
174 if (!dentry)
175 return NULL;
176 sb = dentry->d_sb;
177 while (1) {
178 char *pos;
179 buf_len <<= 1;
180 kfree(buf);
181 buf = kmalloc(buf_len, CCS_GFP_FLAGS);
182 if (!buf)
183 break;
184 /* Get better name for socket. */
185 if (sb->s_magic == SOCKFS_MAGIC) {
186 struct inode *inode = dentry->d_inode;
187 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
188 struct sock *sk = sock ? sock->sk : NULL;
189 if (sk) {
190 snprintf(buf, buf_len - 1, "socket:[family=%u:"
191 "type=%u:protocol=%u]", sk->sk_family,
192 sk->sk_type, sk->sk_protocol);
193 } else {
194 snprintf(buf, buf_len - 1, "socket:[unknown]");
195 }
196 name = ccs_encode(buf);
197 break;
198 }
199 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
200 /* For "socket:[\$]" and "pipe:[\$]". */
201 if (dentry->d_op && dentry->d_op->d_dname) {
202 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
203 if (IS_ERR(pos))
204 continue;
205 name = ccs_encode(pos);
206 break;
207 }
208 #endif
209 /*
210 * Get local name for filesystems without rename() operation.
211 */
212 if (sb->s_root->d_inode && sb->s_root->d_inode->i_op &&
213 !sb->s_root->d_inode->i_op->rename) {
214 spin_lock(&dcache_lock);
215 pos = ccs_get_dentry_path(dentry, buf, buf_len - 1);
216 spin_unlock(&dcache_lock);
217 if (IS_ERR(pos))
218 continue;
219 /*
220 * Convert from $PID to self if $PID is current thread.
221 */
222 if (sb->s_magic == PROC_SUPER_MAGIC && *pos == '/') {
223 char *ep;
224 const pid_t pid = (pid_t)
225 simple_strtoul(pos + 1, &ep, 10);
226 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
227 if (*ep == '/' && pid && pid ==
228 task_tgid_nr_ns(current, sb->s_fs_info)) {
229 pos = ep - 5;
230 if (pos < buf)
231 continue;
232 memmove(pos, "/self", 5);
233 }
234 #else
235 if (*ep == '/' &&
236 pid == ccsecurity_exports.sys_getpid()) {
237 pos = ep - 5;
238 if (pos < buf)
239 continue;
240 memmove(pos, "/self", 5);
241 }
242 #endif
243 }
244 /* Prepend filesystem name. */
245 {
246 const char *name = sb->s_type->name;
247 const int name_len = strlen(name);
248 pos -= name_len + 1;
249 if (pos < buf)
250 continue;
251 memmove(pos, name, name_len);
252 pos[name_len] = ':';
253 }
254 name = ccs_encode(pos);
255 break;
256 }
257 if (!path->mnt)
258 break;
259 path_get(path);
260 ccs_realpath_lock();
261 pos = ccs_get_absolute_path(path, buf, buf_len - 1);
262 ccs_realpath_unlock();
263 path_put(path);
264 if (IS_ERR(pos))
265 continue;
266 name = ccs_encode(pos);
267 break;
268 }
269 kfree(buf);
270 if (!name)
271 ccs_warn_oom(__func__);
272 return name;
273 }
274
275 /**
276 * ccs_symlink_path - Get symlink's pathname.
277 *
278 * @pathname: The pathname to solve.
279 * @name: Pointer to "struct ccs_path_info".
280 *
281 * Returns 0 on success, negative value otherwise.
282 *
283 * This function uses kzalloc(), so caller must kfree() if this function
284 * didn't return NULL.
285 */
286 int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
287 {
288 char *buf;
289 struct path path;
290 if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
291 return -ENOENT;
292 buf = ccs_realpath_from_path(&path);
293 path_put(&path);
294 if (buf) {
295 name->name = buf;
296 ccs_fill_path_info(name);
297 return 0;
298 }
299 return -ENOMEM;
300 }
301
302 /**
303 * ccs_encode: Encode binary string to ascii string.
304 *
305 * @str: String in binary format.
306 *
307 * Returns pointer to @str in ascii format on success, NULL otherwise.
308 *
309 * This function uses kzalloc(), so caller must kfree() if this function
310 * didn't return NULL.
311 */
312 char *ccs_encode(const char *str)
313 {
314 int len = 0;
315 const char *p = str;
316 char *cp;
317 char *cp0;
318 if (!p)
319 return NULL;
320 while (*p) {
321 const unsigned char c = *p++;
322 if (c == '\\')
323 len += 2;
324 else if (c > ' ' && c < 127)
325 len++;
326 else
327 len += 4;
328 }
329 len++;
330 /* Reserve space for appending "/". */
331 cp = kzalloc(len + 10, CCS_GFP_FLAGS);
332 if (!cp)
333 return NULL;
334 cp0 = cp;
335 p = str;
336 while (*p) {
337 const unsigned char c = *p++;
338 if (c == '\\') {
339 *cp++ = '\\';
340 *cp++ = '\\';
341 } else if (c > ' ' && c < 127) {
342 *cp++ = c;
343 } else {
344 *cp++ = '\\';
345 *cp++ = (c >> 6) + '0';
346 *cp++ = ((c >> 3) & 7) + '0';
347 *cp++ = (c & 7) + '0';
348 }
349 }
350 return cp0;
351 }
352
353 /**
354 * ccs_get_path - Get dentry/vfsmmount of a pathname.
355 *
356 * @pathname: The pathname to solve.
357 * @path: Pointer to "struct path".
358 *
359 * Returns 0 on success, negative value otherwise.
360 */
361 int ccs_get_path(const char *pathname, struct path *path)
362 {
363 return ccs_kern_path(pathname, ccs_lookup_flags, path);
364 }

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