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

Subversion リポジトリの参照

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1015 - (hide annotations) (download) (as text)
Tue Mar 4 04:04:39 2008 UTC (16 years, 2 months ago) by kumaneko
Original Path: trunk/1.6.x/ccs-patch/fs/realpath.c
File MIME type: text/x-csrc
File size: 12330 byte(s)


1 kumaneko 111 /*
2     * fs/realpath.c
3     *
4     * Get the canonicalized absolute pathnames. The basis for SAKURA and TOMOYO.
5     *
6 kumaneko 856 * Copyright (C) 2005-2008 NTT DATA CORPORATION
7 kumaneko 111 *
8 kumaneko 1015 * Version: 1.6.0-pre 2008/03/04
9 kumaneko 111 *
10     * This file is applicable to both 2.4.30 and 2.6.11 and later.
11     * See README.ccs for ChangeLog.
12     *
13     */
14     #include <linux/string.h>
15     #include <linux/mm.h>
16     #include <linux/utime.h>
17     #include <linux/file.h>
18     #include <linux/smp_lock.h>
19     #include <linux/module.h>
20     #include <linux/slab.h>
21     #include <asm/uaccess.h>
22     #include <asm/atomic.h>
23     #include <linux/version.h>
24     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
25     #include <linux/namei.h>
26     #include <linux/mount.h>
27     static const int lookup_flags = LOOKUP_FOLLOW;
28     #else
29     static const int lookup_flags = LOOKUP_FOLLOW | LOOKUP_POSITIVE;
30     #endif
31     #include <linux/realpath.h>
32     #include <linux/proc_fs.h>
33     #include <linux/ccs_common.h>
34    
35     /***** realpath handler *****/
36    
37     /*
38     * GetAbsolutePath - return the path of a dentry but ignores chroot'ed root.
39     * @dentry: dentry to report
40     * @vfsmnt: vfsmnt to which the dentry belongs
41     * @buffer: buffer to return value in
42     * @buflen: buffer length
43     *
44     * Caller holds the dcache_lock.
45     * Based on __d_path() in fs/dcache.c
46     *
47     * If dentry is a directory, trailing '/' is appended.
48     * Characters other than ' ' < c < 127 are converted to \ooo style octal string.
49     * Character \ is converted to \\ string.
50     */
51     static int GetAbsolutePath(struct dentry *dentry, struct vfsmount *vfsmnt, char *buffer, int buflen)
52     {
53     char *start = buffer;
54     char *end = buffer + buflen;
55 kumaneko 621 bool is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
56 kumaneko 111
57     if (buflen < 256) goto out;
58    
59     *--end = '\0';
60     buflen--;
61    
62     for (;;) {
63     struct dentry *parent;
64    
65     if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
66     /* Global root? */
67     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
68     spin_lock(&vfsmount_lock);
69     #endif
70     if (vfsmnt->mnt_parent == vfsmnt) {
71     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
72     spin_unlock(&vfsmount_lock);
73     #endif
74     break;
75     }
76     dentry = vfsmnt->mnt_mountpoint;
77     vfsmnt = vfsmnt->mnt_parent;
78     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
79     spin_unlock(&vfsmount_lock);
80     #endif
81     continue;
82     }
83     if (is_dir) {
84     is_dir = 0; *--end = '/'; buflen--;
85     }
86     parent = dentry->d_parent;
87     {
88     const char *sp = dentry->d_name.name;
89     const char *cp = sp + dentry->d_name.len - 1;
90     unsigned char c;
91    
92     /* Exception: Use /proc/self/ rather than /proc/\$/ for current process. */
93     if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' && parent->d_sb && parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
94     char *ep;
95     const pid_t pid = (pid_t) simple_strtoul(sp, &ep, 10);
96     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
97     if (!*ep && pid == current->tgid) { sp = "self"; cp = sp + 3; }
98     #else
99     if (!*ep && pid == current->pid) { sp = "self"; cp = sp + 3; }
100     #endif
101     }
102    
103     while (sp <= cp) {
104     c = * (unsigned char *) cp;
105     if (c == '\\') {
106     buflen -= 2;
107     if (buflen < 0) goto out;
108     *--end = '\\';
109     *--end = '\\';
110     } else if (c > ' ' && c < 127) {
111     if (--buflen < 0) goto out;
112     *--end = (char) c;
113     } else {
114     buflen -= 4;
115     if (buflen < 0) goto out;
116     *--end = (c & 7) + '0';
117     *--end = ((c >> 3) & 7) + '0';
118     *--end = (c >> 6) + '0';
119     *--end = '\\';
120     }
121     cp--;
122     }
123     if (--buflen < 0) goto out;
124     *--end = '/';
125     }
126     dentry = parent;
127     }
128     if (*end == '/') { buflen++; end++; }
129     {
130     const char *sp = dentry->d_name.name;
131     const char *cp = sp + dentry->d_name.len - 1;
132     unsigned char c;
133     while (sp <= cp) {
134     c = * (unsigned char *) cp;
135     if (c == '\\') {
136     buflen -= 2;
137     if (buflen < 0) goto out;
138     *--end = '\\';
139     *--end = '\\';
140     } else if (c > ' ' && c < 127) {
141     if (--buflen < 0) goto out;
142     *--end = (char) c;
143     } else {
144     buflen -= 4;
145     if (buflen < 0) goto out;
146     *--end = (c & 7) + '0';
147     *--end = ((c >> 3) & 7) + '0';
148     *--end = (c >> 6) + '0';
149     *--end = '\\';
150     }
151     cp--;
152     }
153     }
154     /* Move the pathname to the top of the buffer. */
155     memmove(start, end, strlen(end) + 1);
156     return 0;
157     out:
158     return -ENOMEM;
159     }
160    
161     /* Returns realpath(3) of the given dentry but ignores chroot'ed root. */
162     int realpath_from_dentry2(struct dentry *dentry, struct vfsmount *mnt, char *newname, int newname_len)
163     {
164     int error;
165     struct dentry *d_dentry;
166     struct vfsmount *d_mnt;
167     if (!dentry || !mnt || !newname || newname_len <= 0) return -EINVAL;
168     d_dentry = dget(dentry);
169     d_mnt = mntget(mnt);
170     /***** CRITICAL SECTION START *****/
171     spin_lock(&dcache_lock);
172     error = GetAbsolutePath(d_dentry, d_mnt, newname, newname_len);
173     spin_unlock(&dcache_lock);
174     /***** CRITICAL SECTION END *****/
175     dput(d_dentry);
176     mntput(d_mnt);
177     return error;
178     }
179    
180     /* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
181     /* These functions use ccs_alloc(), so caller must ccs_free() if these functions didn't return NULL. */
182     char *realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
183     {
184     char *buf = ccs_alloc(CCS_MAX_PATHNAME_LEN);
185     if (buf && realpath_from_dentry2(dentry, mnt, buf, CCS_MAX_PATHNAME_LEN - 1) == 0) return buf;
186     ccs_free(buf);
187     return NULL;
188     }
189    
190     char *realpath(const char *pathname)
191     {
192     struct nameidata nd;
193     if (pathname && path_lookup(pathname, lookup_flags, &nd) == 0) {
194 kumaneko 992 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
195 kumaneko 990 char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt);
196     path_put(&nd.path);
197     #else
198 kumaneko 111 char *buf = realpath_from_dentry(nd.dentry, nd.mnt);
199     path_release(&nd);
200 kumaneko 990 #endif
201 kumaneko 111 return buf;
202     }
203     return NULL;
204     }
205    
206     char *realpath_nofollow(const char *pathname)
207     {
208     struct nameidata nd;
209     if (pathname && path_lookup(pathname, lookup_flags ^ LOOKUP_FOLLOW, &nd) == 0) {
210 kumaneko 992 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
211 kumaneko 990 char *buf = realpath_from_dentry(nd.path.dentry, nd.path.mnt);
212     path_put(&nd.path);
213     #else
214 kumaneko 111 char *buf = realpath_from_dentry(nd.dentry, nd.mnt);
215     path_release(&nd);
216 kumaneko 990 #endif
217 kumaneko 111 return buf;
218     }
219     return NULL;
220     }
221    
222     /***** Private memory allocator. *****/
223    
224     /*
225     * Round up an integer so that the returned pointers are appropriately aligned.
226     * FIXME: Are there more requirements that is needed for assigning value atomically?
227     */
228     static inline unsigned int ROUNDUP(const unsigned int size) {
229     if (sizeof(void *) >= sizeof(long)) {
230     return ((size + sizeof(void *) - 1) / sizeof(void *)) * sizeof(void *);
231     } else {
232     return ((size + sizeof(long) - 1) / sizeof(long)) * sizeof(long);
233     }
234     }
235    
236     static unsigned int allocated_memory_for_elements = 0;
237    
238     unsigned int GetMemoryUsedForElements(void)
239     {
240     return allocated_memory_for_elements;
241     }
242    
243     /* Allocate memory for structures. The RAM is chunked, so NEVER try to kfree() the returned pointer. */
244 kumaneko 214 void *alloc_element(const unsigned int size)
245 kumaneko 111 {
246 kumaneko 652 static DEFINE_MUTEX(lock);
247 kumaneko 111 static char *buf = NULL;
248     static unsigned int buf_used_len = PAGE_SIZE;
249     char *ptr = NULL;
250     const unsigned int word_aligned_size = ROUNDUP(size);
251     if (word_aligned_size > PAGE_SIZE) return NULL;
252 kumaneko 652 mutex_lock(&lock);
253 kumaneko 111 if (buf_used_len + word_aligned_size > PAGE_SIZE) {
254     if ((ptr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) {
255     printk("ERROR: Out of memory for alloc_element().\n");
256     if (!sbin_init_started) panic("MAC Initialization failed.\n");
257     } else {
258     memset(ptr, 0, PAGE_SIZE);
259     buf = ptr;
260     allocated_memory_for_elements += PAGE_SIZE;
261     buf_used_len = word_aligned_size;
262     ptr = buf;
263     }
264     } else if (word_aligned_size) {
265     int i;
266     ptr = buf + buf_used_len;
267     buf_used_len += word_aligned_size;
268     for (i = 0; i < word_aligned_size; i++) {
269     if (ptr[i]) {
270     printk(KERN_ERR "WARNING: Reserved memory was tainted! The system might go wrong.\n");
271     ptr[i] = '\0';
272     }
273     }
274     }
275 kumaneko 652 mutex_unlock(&lock);
276 kumaneko 111 return ptr;
277     }
278    
279     /***** Shared memory allocator. *****/
280    
281     static unsigned int allocated_memory_for_savename = 0;
282    
283     unsigned int GetMemoryUsedForSaveName(void)
284     {
285     return allocated_memory_for_savename;
286     }
287    
288     #define MAX_HASH 256
289    
290 kumaneko 214 struct name_entry {
291 kumaneko 731 struct list1_head list;
292 kumaneko 111 struct path_info entry;
293 kumaneko 214 };
294 kumaneko 111
295 kumaneko 214 struct free_memory_block_list {
296 kumaneko 731 struct list_head list;
297 kumaneko 111 char *ptr; /* Pointer to a free area. */
298     int len; /* Length of the area. */
299 kumaneko 214 };
300 kumaneko 111
301 kumaneko 731 static struct list1_head name_list[MAX_HASH]; /* The list of names. */
302    
303 kumaneko 111 /* Keep the given name on the RAM. The RAM is shared, so NEVER try to modify or kfree() the returned name. */
304     const struct path_info *SaveName(const char *name)
305     {
306 kumaneko 731 static LIST_HEAD(fmb_list);
307 kumaneko 652 static DEFINE_MUTEX(lock);
308 kumaneko 731 struct name_entry *ptr;
309 kumaneko 111 unsigned int hash;
310 kumaneko 731 struct free_memory_block_list *fmb;
311 kumaneko 111 int len;
312 kumaneko 731 char *cp;
313 kumaneko 111 if (!name) return NULL;
314     len = strlen(name) + 1;
315     if (len > CCS_MAX_PATHNAME_LEN) {
316     printk("ERROR: Name too long for SaveName().\n");
317     return NULL;
318     }
319     hash = full_name_hash((const unsigned char *) name, len - 1);
320 kumaneko 652 mutex_lock(&lock);
321 kumaneko 731 list1_for_each_entry(ptr, &name_list[hash % MAX_HASH], list) {
322 kumaneko 111 if (hash == ptr->entry.hash && strcmp(name, ptr->entry.name) == 0) goto out;
323     }
324 kumaneko 731 list_for_each_entry(fmb, &fmb_list, list) {
325     if (len <= fmb->len) goto ready;
326 kumaneko 111 }
327 kumaneko 731 cp = kmalloc(PAGE_SIZE, GFP_KERNEL);
328     fmb = kmalloc(sizeof(*fmb), GFP_KERNEL);
329     if (!cp || !fmb) {
330     kfree(cp);
331     kfree(fmb);
332     printk("ERROR: Out of memory for SaveName().\n");
333     if (!sbin_init_started) panic("MAC Initialization failed.\n");
334     ptr = NULL;
335     goto out;
336     }
337     memset(cp, 0, PAGE_SIZE);
338     allocated_memory_for_savename += PAGE_SIZE;
339     list_add(&fmb->list, &fmb_list);
340     fmb->ptr = cp;
341     fmb->len = PAGE_SIZE;
342     ready:
343     ptr = alloc_element(sizeof(*ptr));
344     if (!ptr) goto out;
345 kumaneko 111 ptr->entry.name = fmb->ptr;
346     memmove(fmb->ptr, name, len);
347     fill_path_info(&ptr->entry);
348     fmb->ptr += len;
349     fmb->len -= len;
350 kumaneko 731 list1_add_tail_mb(&ptr->list, &name_list[hash % MAX_HASH]);
351 kumaneko 111 if (fmb->len == 0) {
352 kumaneko 731 list_del(&fmb->list);
353     kfree(fmb);
354 kumaneko 111 }
355     out:
356 kumaneko 652 mutex_unlock(&lock);
357 kumaneko 111 return ptr ? &ptr->entry : NULL;
358     }
359    
360     /***** Dynamic memory allocator. *****/
361    
362 kumaneko 214 struct cache_entry {
363 kumaneko 111 struct list_head list;
364     void *ptr;
365     int size;
366 kumaneko 214 };
367 kumaneko 111
368     #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
369     static struct kmem_cache *ccs_cachep = NULL;
370     #else
371     static kmem_cache_t *ccs_cachep = NULL;
372     #endif
373    
374     void __init realpath_Init(void)
375     {
376 kumaneko 731 int i;
377 kumaneko 316 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
378     ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL);
379     #else
380 kumaneko 214 ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 0, 0, NULL, NULL);
381 kumaneko 316 #endif
382 kumaneko 111 if (!ccs_cachep) panic("Can't create cache.\n");
383 kumaneko 731 for (i = 0; i < MAX_HASH; i++) {
384     INIT_LIST1_HEAD(&name_list[i]);
385     }
386     if (CCS_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size.");
387 kumaneko 722 INIT_LIST1_HEAD(&KERNEL_DOMAIN.acl_info_list);
388 kumaneko 708 KERNEL_DOMAIN.domainname = SaveName(ROOT_NAME);
389 kumaneko 722 list1_add_tail_mb(&KERNEL_DOMAIN.list, &domain_list);
390 kumaneko 708 if (FindDomain(ROOT_NAME) != &KERNEL_DOMAIN) panic("Can't register KERNEL_DOMAIN");
391 kumaneko 111 }
392    
393     static LIST_HEAD(cache_list);
394     static spinlock_t cache_list_lock = SPIN_LOCK_UNLOCKED;
395     static unsigned int dynamic_memory_size = 0;
396    
397     unsigned int GetMemoryUsedForDynamic(void)
398     {
399     return dynamic_memory_size;
400     }
401    
402 kumaneko 581 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
403     static int round2(size_t size)
404     {
405     #if PAGE_SIZE == 4096
406     size_t bsize = 32;
407     #else
408     size_t bsize = 64;
409     #endif
410     while (size > bsize) bsize <<= 1;
411     return bsize;
412     }
413     #endif
414    
415 kumaneko 214 void *ccs_alloc(const size_t size)
416 kumaneko 111 {
417     void *ret = kmalloc(size, GFP_KERNEL);
418     if (ret) {
419 kumaneko 214 struct cache_entry *new_entry = kmem_cache_alloc(ccs_cachep, GFP_KERNEL);
420 kumaneko 111 if (!new_entry) {
421     kfree(ret); ret = NULL;
422     } else {
423     INIT_LIST_HEAD(&new_entry->list);
424     new_entry->ptr = ret;
425 kumaneko 581 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
426     new_entry->size = ksize(ret);
427     #else
428     new_entry->size = round2(size);
429     #endif
430 kumaneko 111 spin_lock(&cache_list_lock);
431     list_add_tail(&new_entry->list, &cache_list);
432 kumaneko 581 dynamic_memory_size += new_entry->size;
433 kumaneko 111 spin_unlock(&cache_list_lock);
434     memset(ret, 0, size);
435     }
436     }
437 kumaneko 214 return ret;
438 kumaneko 111 }
439    
440     void ccs_free(const void *p)
441     {
442     struct list_head *v;
443 kumaneko 214 struct cache_entry *entry = NULL;
444 kumaneko 111 if (!p) return;
445     spin_lock(&cache_list_lock);
446     list_for_each(v, &cache_list) {
447 kumaneko 214 entry = list_entry(v, struct cache_entry, list);
448 kumaneko 111 if (entry->ptr != p) {
449     entry = NULL; continue;
450     }
451     list_del(&entry->list);
452     dynamic_memory_size -= entry->size;
453     break;
454     }
455     spin_unlock(&cache_list_lock);
456     if (entry) {
457     kfree(p);
458     kmem_cache_free(ccs_cachep, entry);
459     } else {
460     printk("BUG: ccs_free() with invalid pointer.\n");
461     }
462     }

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