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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2915 - (show annotations) (download) (as text)
Mon Aug 17 10:56:21 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: 9206 byte(s)


1 /*
2 * security/ccsecurity/realpath.c
3 *
4 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 *
6 * Version: 1.7.0-pre 2009/08/08
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 0 on success, -ENOMEM 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 * Characters out of 0x20 < c < 0x7F range are converted to
70 * \ooo style octal string.
71 * Character \ is converted to \\ string.
72 */
73 static int ccs_get_absolute_path(struct path *path, char *buffer, int buflen)
74 {
75 /***** CRITICAL SECTION START *****/
76 char *start = buffer;
77 char *end = buffer + buflen;
78 struct dentry *dentry = path->dentry;
79 struct vfsmount *vfsmnt = path->mnt;
80 bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
81
82 if (buflen < 256)
83 goto out;
84
85 *--end = '\0';
86 buflen--;
87
88 for (;;) {
89 struct dentry *parent;
90
91 if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
92 /* Global root? */
93 if (vfsmnt->mnt_parent == vfsmnt)
94 break;
95 dentry = vfsmnt->mnt_mountpoint;
96 vfsmnt = vfsmnt->mnt_parent;
97 continue;
98 }
99 if (is_dir) {
100 is_dir = false;
101 *--end = '/';
102 buflen--;
103 }
104 parent = dentry->d_parent;
105 {
106 const char *sp = dentry->d_name.name;
107 const char *cp = sp + dentry->d_name.len - 1;
108 unsigned char c;
109
110 /*
111 * Exception: Use /proc/self/ rather than
112 * /proc/\$/ for current process.
113 */
114 if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' &&
115 parent->d_sb &&
116 parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
117 char *ep;
118 const pid_t pid
119 = (pid_t) simple_strtoul(sp, &ep, 10);
120 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
121 const pid_t tgid
122 = task_tgid_nr_ns(current,
123 dentry->d_sb->
124 s_fs_info);
125 if (!*ep && pid == tgid && tgid) {
126 sp = "self";
127 cp = sp + 3;
128 }
129 #else
130 if (!*ep && pid == sys_getpid()) {
131 sp = "self";
132 cp = sp + 3;
133 }
134 #endif
135 }
136
137 while (sp <= cp) {
138 c = *(unsigned char *) cp;
139 if (c == '\\') {
140 buflen -= 2;
141 if (buflen < 0)
142 goto out;
143 *--end = '\\';
144 *--end = '\\';
145 } else if (c > ' ' && c < 127) {
146 if (--buflen < 0)
147 goto out;
148 *--end = (char) c;
149 } else {
150 buflen -= 4;
151 if (buflen < 0)
152 goto out;
153 *--end = (c & 7) + '0';
154 *--end = ((c >> 3) & 7) + '0';
155 *--end = (c >> 6) + '0';
156 *--end = '\\';
157 }
158 cp--;
159 }
160 if (--buflen < 0)
161 goto out;
162 *--end = '/';
163 }
164 dentry = parent;
165 }
166 if (*end == '/') {
167 buflen++;
168 end++;
169 }
170 {
171 const char *sp = dentry->d_name.name;
172 const char *cp = sp + dentry->d_name.len - 1;
173 unsigned char c;
174 while (sp <= cp) {
175 c = *(unsigned char *) cp;
176 if (c == '\\') {
177 buflen -= 2;
178 if (buflen < 0)
179 goto out;
180 *--end = '\\';
181 *--end = '\\';
182 } else if (c > ' ' && c < 127) {
183 if (--buflen < 0)
184 goto out;
185 *--end = (char) c;
186 } else {
187 buflen -= 4;
188 if (buflen < 0)
189 goto out;
190 *--end = (c & 7) + '0';
191 *--end = ((c >> 3) & 7) + '0';
192 *--end = (c >> 6) + '0';
193 *--end = '\\';
194 }
195 cp--;
196 }
197 }
198 /* Move the pathname to the top of the buffer. */
199 memmove(start, end, strlen(end) + 1);
200 return 0;
201 out:
202 return -ENOMEM;
203 /***** CRITICAL SECTION END *****/
204 }
205
206 #define SOCKFS_MAGIC 0x534F434B
207
208 /**
209 * ccs_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
210 *
211 * @path: Pointer to "struct path".
212 * @newname: Pointer to buffer to return value in.
213 * @newname_len: Size of @newname.
214 *
215 * Returns 0 on success, negative value otherwise.
216 */
217 static int ccs_realpath_from_path2(struct path *path, char *newname,
218 int newname_len)
219 {
220 int error = -EINVAL;
221 struct dentry *dentry = path->dentry;
222 if (!dentry || !newname || newname_len <= 2048)
223 goto out;
224 /* Get better name for socket. */
225 if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
226 struct inode *inode = dentry->d_inode;
227 struct socket *sock = inode ? SOCKET_I(inode) : NULL;
228 struct sock *sk = sock ? sock->sk : NULL;
229 if (sk) {
230 snprintf(newname, newname_len - 1,
231 "socket:[family=%u:type=%u:protocol=%u]",
232 sk->sk_family, sk->sk_type, sk->sk_protocol);
233 } else {
234 snprintf(newname, newname_len - 1, "socket:[unknown]");
235 }
236 return 0;
237 }
238 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
239 if (dentry->d_op && dentry->d_op->d_dname) {
240 /* For "socket:[\$]" and "pipe:[\$]". */
241 static const int offset = 1536;
242 char *dp = newname;
243 char *sp = dentry->d_op->d_dname(dentry, newname + offset,
244 newname_len - offset);
245 if (IS_ERR(sp)) {
246 error = PTR_ERR(sp);
247 goto out;
248 }
249 error = -ENOMEM;
250 newname += offset;
251 while (1) {
252 const unsigned char c = *(unsigned char *) sp++;
253 if (c == '\\') {
254 if (dp + 2 >= newname)
255 break;
256 *dp++ = '\\';
257 *dp++ = '\\';
258 } else if (c > ' ' && c < 127) {
259 if (dp + 1 >= newname)
260 break;
261 *dp++ = (char) c;
262 } else if (c) {
263 if (dp + 4 >= newname)
264 break;
265 *dp++ = '\\';
266 *dp++ = (c >> 6) + '0';
267 *dp++ = ((c >> 3) & 7) + '0';
268 *dp++ = (c & 7) + '0';
269 } else {
270 *dp = '\0';
271 return 0;
272 }
273 }
274 goto out;
275 }
276 #endif
277 if (!path->mnt)
278 goto out;
279 path_get(path);
280 /***** CRITICAL SECTION START *****/
281 ccs_realpath_lock();
282 error = ccs_get_absolute_path(path, newname, newname_len);
283 ccs_realpath_unlock();
284 /***** CRITICAL SECTION END *****/
285 path_put(path);
286 out:
287 if (error)
288 printk(KERN_WARNING "ccs_realpath: Pathname too long. (%d)\n",
289 error);
290 return error;
291 }
292
293 /**
294 * ccs_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
295 *
296 * @path: Pointer to "struct path".
297 *
298 * Returns the realpath of the given @path on success, NULL otherwise.
299 *
300 * These functions use kzalloc(), so caller must kfree()
301 * if these functions didn't return NULL.
302 */
303 char *ccs_realpath_from_path(struct path *path)
304 {
305 char *buf = kzalloc(CCS_MAX_PATHNAME_LEN, GFP_KERNEL);
306 if (buf &&
307 ccs_realpath_from_path2(path, buf, CCS_MAX_PATHNAME_LEN - 2) == 0)
308 return buf;
309 kfree(buf);
310 return NULL;
311 }
312
313 /**
314 * ccs_symlink_path - Get symlink's pathname.
315 *
316 * @pathname: The pathname to solve.
317 * @ee: Pointer to "struct ccs_execve_entry".
318 *
319 * Returns 0 on success, negative value otherwise.
320 */
321 int ccs_symlink_path(const char *pathname, struct ccs_execve_entry *ee)
322 {
323 struct path path;
324 int ret;
325 if (ccs_kern_path(pathname, ccs_lookup_flags ^ LOOKUP_FOLLOW, &path))
326 return -ENOENT;
327 ret = ccs_realpath_from_path2(&path, ee->program_path,
328 CCS_MAX_PATHNAME_LEN - 1);
329 path_put(&path);
330 return ret;
331 }
332
333 /**
334 * ccs_encode: Encode binary string to ascii string.
335 *
336 * @str: String in binary format.
337 *
338 * Returns pointer to @str in ascii format on success, NULL otherwise.
339 *
340 * This function uses kzalloc(), so caller must kfree() if this function
341 * didn't return NULL.
342 */
343 char *ccs_encode(const char *str)
344 {
345 int len = 0;
346 const char *p = str;
347 char *cp;
348 char *cp0;
349 if (!p)
350 return NULL;
351 while (*p) {
352 const unsigned char c = *p++;
353 if (c == '\\')
354 len += 2;
355 else if (c > ' ' && c < 127)
356 len++;
357 else
358 len += 4;
359 }
360 len++;
361 cp = kzalloc(len, GFP_KERNEL);
362 if (!cp)
363 return NULL;
364 cp0 = cp;
365 p = str;
366 while (*p) {
367 const unsigned char c = *p++;
368 if (c == '\\') {
369 *cp++ = '\\';
370 *cp++ = '\\';
371 } else if (c > ' ' && c < 127) {
372 *cp++ = c;
373 } else {
374 *cp++ = '\\';
375 *cp++ = (c >> 6) + '0';
376 *cp++ = ((c >> 3) & 7) + '0';
377 *cp++ = (c & 7) + '0';
378 }
379 }
380 return cp0;
381 }
382
383 /**
384 * ccs_get_path - Get dentry/vfsmmount of a pathname.
385 *
386 * @pathname: The pathname to solve.
387 * @path: Pointer to "struct path".
388 *
389 * Returns 0 on success, negative value otherwise.
390 */
391 int ccs_get_path(const char *pathname, struct path *path)
392 {
393 return ccs_kern_path(pathname, ccs_lookup_flags, path);
394 }

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