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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3519 - (show annotations) (download) (as text)
Sun Mar 21 08:31:39 2010 UTC (14 years, 2 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 7649 byte(s)
Improve garbage collector.
1 /*
2 * security/ccsecurity/realpath.c
3 *
4 * Copyright (C) 2005-2010 NTT DATA CORPORATION
5 *
6 * Version: 1.7.2-pre 2010/03/21
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 * /proc/pid is represented as /proc/self if pid is current.
70 */
71 static char *ccs_get_absolute_path(struct path *path, char * const buffer,
72 const int buflen)
73 {
74 char *pos = buffer + buflen - 1;
75 struct dentry *dentry = path->dentry;
76 struct vfsmount *vfsmnt = path->mnt;
77 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)
82 goto out;
83
84 *pos = '\0';
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 if (is_dir) {
95 is_dir = false;
96 *--pos = '/';
97 }
98 parent = dentry->d_parent;
99 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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
108 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 #else
116 if (!*ep && pid == ccsecurity_exports.sys_getpid()) {
117 name = "self";
118 len = 4;
119 }
120 #endif
121 }
122 pos -= len;
123 if (pos <= buffer)
124 goto out;
125 memmove(pos, name, len);
126 *--pos = '/';
127 dentry = parent;
128 }
129 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 out:
138 return ERR_PTR(-ENOMEM);
139 }
140
141 #define SOCKFS_MAGIC 0x534F434B
142
143 /**
144 * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
145 *
146 * @path: Pointer to "struct path".
147 *
148 * 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 char *ccs_realpath_from_path(struct path *path)
154 {
155 char *buf = NULL;
156 char *name = NULL;
157 unsigned int buf_len = PAGE_SIZE / 2;
158 struct dentry *dentry = path->dentry;
159 if (!dentry)
160 return NULL;
161 while (1) {
162 char *pos;
163 buf_len <<= 1;
164 kfree(buf);
165 buf = kmalloc(buf_len, CCS_GFP_FLAGS);
166 if (!buf)
167 break;
168 /* Get better name for socket. */
169 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
170 struct inode *inode = dentry->d_inode;
171 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
172 struct sock *sk = sock ? sock->sk : NULL;
173 if (sk) {
174 snprintf(buf, buf_len - 1, "socket:[family=%u:"
175 "type=%u:protocol=%u]", sk->sk_family,
176 sk->sk_type, sk->sk_protocol);
177 } else {
178 snprintf(buf, buf_len - 1, "socket:[unknown]");
179 }
180 name = ccs_encode(buf);
181 break;
182 }
183 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
184 /* For "socket:[\$]" and "pipe:[\$]". */
185 if (dentry->d_op && dentry->d_op->d_dname) {
186 pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
187 if (IS_ERR(pos))
188 continue;
189 name = ccs_encode(pos);
190 break;
191 }
192 #endif
193 if (!path->mnt)
194 break;
195 path_get(path);
196 ccs_realpath_lock();
197 pos = ccs_get_absolute_path(path, buf, buf_len - 1);
198 ccs_realpath_unlock();
199 path_put(path);
200 if (IS_ERR(pos))
201 continue;
202 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
203 /* Prepend "/proc" prefix if using internal proc vfs mount. */
204 if (path->mnt->mnt_flags & MNT_INTERNAL &&
205 path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC) {
206 pos -= 5;
207 if (pos >= buf)
208 memmove(pos, "/proc", 5);
209 else
210 continue;
211 }
212 #elif LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 33)
213 /* Prepend "/proc" prefix if using internal proc vfs mount. */
214 if (path->mnt->mnt_parent == path->mnt &&
215 path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC) {
216 pos -= 5;
217 if (pos >= buf)
218 memmove(pos, "/proc", 5);
219 else
220 continue;
221 }
222 #endif
223 name = ccs_encode(pos);
224 break;
225 }
226 kfree(buf);
227 if (!name)
228 ccs_warn_oom(__func__);
229 return name;
230 }
231
232 /**
233 * ccs_symlink_path - Get symlink's pathname.
234 *
235 * @pathname: The pathname to solve.
236 * @name: Pointer to "struct ccs_path_info".
237 *
238 * Returns 0 on success, negative value otherwise.
239 *
240 * This function uses kzalloc(), so caller must kfree() if this function
241 * didn't return NULL.
242 */
243 int ccs_symlink_path(const char *pathname, struct ccs_path_info *name)
244 {
245 char *buf;
246 struct path path;
247 if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
248 return -ENOENT;
249 buf = ccs_realpath_from_path(&path);
250 path_put(&path);
251 if (buf) {
252 name->name = buf;
253 ccs_fill_path_info(name);
254 return 0;
255 }
256 return -ENOMEM;
257 }
258
259 /**
260 * ccs_encode: Encode binary string to ascii string.
261 *
262 * @str: String in binary format.
263 *
264 * Returns pointer to @str in ascii format on success, NULL otherwise.
265 *
266 * This function uses kzalloc(), so caller must kfree() if this function
267 * didn't return NULL.
268 */
269 char *ccs_encode(const char *str)
270 {
271 int len = 0;
272 const char *p = str;
273 char *cp;
274 char *cp0;
275 if (!p)
276 return NULL;
277 while (*p) {
278 const unsigned char c = *p++;
279 if (c == '\\')
280 len += 2;
281 else if (c > ' ' && c < 127)
282 len++;
283 else
284 len += 4;
285 }
286 len++;
287 /* Reserve space for appending "/". */
288 cp = kzalloc(len + 10, CCS_GFP_FLAGS);
289 if (!cp)
290 return NULL;
291 cp0 = cp;
292 p = str;
293 while (*p) {
294 const unsigned char c = *p++;
295 if (c == '\\') {
296 *cp++ = '\\';
297 *cp++ = '\\';
298 } else if (c > ' ' && c < 127) {
299 *cp++ = c;
300 } else {
301 *cp++ = '\\';
302 *cp++ = (c >> 6) + '0';
303 *cp++ = ((c >> 3) & 7) + '0';
304 *cp++ = (c & 7) + '0';
305 }
306 }
307 return cp0;
308 }
309
310 /**
311 * ccs_get_path - Get dentry/vfsmmount of a pathname.
312 *
313 * @pathname: The pathname to solve.
314 * @path: Pointer to "struct path".
315 *
316 * Returns 0 on success, negative value otherwise.
317 */
318 int ccs_get_path(const char *pathname, struct path *path)
319 {
320 return ccs_kern_path(pathname, ccs_lookup_flags, path);
321 }

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