We limit the maximum length of any string data (such as domainname and 
pathnames)
to TOMOYO_MAX_PATHNAME_LEN (which is 4000) bytes to fit within a single page.

Userland programs can obtain the amount of RAM currently used by TOMOYO from 
/proc interface.

Signed-off-by: Kentaro Takeda <[EMAIL PROTECTED]>
Signed-off-by: Tetsuo Handa <[EMAIL PROTECTED]>

---------------
security/tomoyo/include/realpath.h |   46 +++++
security/tomoyo/realpath.c         |  445 
+++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 491 insertions(+)

diff -ubBpErN linux-2.6.21.5/security/tomoyo/include/realpath.h 
linux-2.6.21.5-tomoyo/security/tomoyo/include/realpath.h
--- linux-2.6.21.5/security/tomoyo/include/realpath.h   1970-01-01 
09:00:00.000000000 +0900
+++ linux-2.6.21.5-tomoyo/security/tomoyo/include/realpath.h    2007-06-05 
00:00:00.000000000 +0900
@@ -0,0 +1,46 @@
+/*
+ * security/tomoyo/include/realpath.h
+ *
+ * Get the canonicalized absolute pathnames. The basis for TOMOYO.
+ *
+ * Copyright (C) 2005-2007  NTT DATA CORPORATION
+ *
+ * Version: 2.0   2007/06/05
+ *
+ */
+
+#ifndef _TOMOYO_REALPATH_H
+#define _TOMOYO_REALPATH_H
+
+struct path_info;
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+int tomoyo_realpath_from_dentry2(struct dentry *dentry,
+                                 struct vfsmount *mnt,
+                                 char *newname,
+                                 int newname_len);
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+/* These functions use tomoyo_alloc(), so caller must tomoyo_free() */
+/* if these functions didn't return NULL. */
+char *tomoyo_realpath(const char *pathname);
+char *tomoyo_realpath_nofollow(const char *pathname);
+char *tomoyo_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt);
+
+/* Allocate memory for structures. */
+/* The RAM is chunked, so NEVER try to kfree() the returned pointer. */
+void *tomoyo_alloc_element(const unsigned int size);
+
+/* Get used RAM size for tomoyo_alloc_elements(). */
+unsigned int tomoyo_get_memory_used_for_elements(void);
+
+/* Keep the given name on the RAM. */
+/* The RAM is shared, so NEVER try to modify or kfree() the returned name. */
+const struct path_info *tomoyo_save_name(const char *name);
+
+/* Get used RAM size for tomoyo_save_name(). */
+unsigned int tomoyo_get_memory_used_for_save_name(void);
+
+unsigned int tomoyo_get_memory_used_for_dynamic(void);
+
+#endif
diff -ubBpErN linux-2.6.21.5/security/tomoyo/realpath.c 
linux-2.6.21.5-tomoyo/security/tomoyo/realpath.c
--- linux-2.6.21.5/security/tomoyo/realpath.c   1970-01-01 09:00:00.000000000 
+0900
+++ linux-2.6.21.5-tomoyo/security/tomoyo/realpath.c    2007-06-14 
15:06:37.000000000 +0900
@@ -0,0 +1,445 @@
+/*
+ * security/tomoyo/realpath.c
+ *
+ * Get the canonicalized absolute pathnames.
+ * The basis for TOMOYO Linux.
+ *
+ * Copyright (C) 2005-2007  NTT DATA CORPORATION
+ *
+ * Version: 2.0   2007/06/05
+ */
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/utime.h>
+#include <linux/file.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/proc_fs.h>
+#include "realpath.h"
+#include "tomoyo.h"
+
+extern int sbin_init_started;
+
+/***** realpath handler *****/
+
+/*
+ * tomoyo_get_absolute_path - return the path of a dentry but ignores 
chroot'ed root.
+ * @dentry: dentry to report
+ * @vfsmnt: vfsmnt to which the dentry belongs
+ * @buffer: buffer to return value in
+ * @buflen: buffer length
+ *
+ * Caller holds the dcache_lock.
+ * Based on __d_path() in fs/dcache.c
+ *
+ * If dentry is a directory, trailing '/' is appended.
+ * Characters other than ' ' < c < 127 are converted to \ooo style octal 
string.
+ * Character \ is converted to \\ string.
+ */
+static int tomoyo_get_absolute_path(struct dentry *dentry,
+                                    struct vfsmount *vfsmnt,
+                                    char *buffer,
+                                    int buflen)
+{
+       char *start = buffer;
+       char *end = buffer + buflen;
+       int is_dir = (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode));
+
+       if (buflen < 256) goto out;
+
+       *--end = '\0';
+       buflen--;
+
+       for (;;) {
+               struct dentry *parent;
+
+               if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
+                       /* Global root? */
+                       spin_lock(&vfsmount_lock);
+                       if (vfsmnt->mnt_parent == vfsmnt) {
+                               spin_unlock(&vfsmount_lock);
+                               break;
+                       }
+                       dentry = vfsmnt->mnt_mountpoint;
+                       vfsmnt = vfsmnt->mnt_parent;
+                       spin_unlock(&vfsmount_lock);
+                       continue;
+               }
+               if (is_dir) {
+                       is_dir = 0;
+                       *--end = '/';
+                       buflen--;
+               }
+               parent = dentry->d_parent;
+               {
+                       const char *sp = dentry->d_name.name;
+                       const char *cp = sp + dentry->d_name.len - 1;
+                       unsigned char c;
+
+                       /* Exception: Use /proc/self/ rather than /proc/\$/ for 
current process. */
+                       if (IS_ROOT(parent) && *sp > '0' && *sp <= '9' && 
parent->d_sb
+                           && parent->d_sb->s_magic == PROC_SUPER_MAGIC) {
+                               char *ep;
+                               const pid_t pid = (pid_t) simple_strtoul(sp, 
&ep, 10);
+                               if (!*ep && pid == current->tgid) {
+                                       sp = "self";
+                                       cp = sp + 3;
+                               }
+                               if (!*ep && pid == current->pid) {
+                                       sp = "self";
+                                       cp = sp + 3;
+                               }
+                       }
+
+                       while (sp <= cp) {
+                               c = * (unsigned char *) cp;
+                               if (c == '\\') {
+                                       buflen -= 2;
+                                       if (buflen < 0) goto out;
+                                       *--end = '\\';
+                                       *--end = '\\';
+                               } else if (c > ' ' && c < 127) {
+                                       if (--buflen < 0) goto out;
+                                       *--end = (char) c;
+                               } else {
+                                       buflen -= 4;
+                                       if (buflen < 0) goto out;
+                                       *--end = (c & 7) + '0';
+                                       *--end = ((c >> 3) & 7) + '0';
+                                       *--end = (c >> 6) + '0';
+                                       *--end = '\\';
+                               }
+                               cp--;
+                       }
+                       if (--buflen < 0) goto out;
+                       *--end = '/';
+               }
+               dentry = parent;
+       }
+       if (*end == '/') {
+               buflen++;
+               end++;
+       }
+       {
+               const char *sp = dentry->d_name.name;
+               const char *cp = sp + dentry->d_name.len - 1;
+               unsigned char c;
+               while (sp <= cp) {
+                       c = * (unsigned char *) cp;
+                       if (c == '\\') {
+                               buflen -= 2;
+                               if (buflen < 0) goto out;
+                               *--end = '\\';
+                               *--end = '\\';
+                       } else if (c > ' ' && c < 127) {
+                               if (--buflen < 0) goto out;
+                               *--end = (char) c;
+                       } else {
+                               buflen -= 4;
+                               if (buflen < 0) goto out;
+                               *--end = (c & 7) + '0';
+                               *--end = ((c >> 3) & 7) + '0';
+                               *--end = (c >> 6) + '0';
+                               *--end = '\\';
+                       }
+                       cp--;
+               }
+       }
+       /* Move the pathname to the top of the buffer. */
+       memmove(start, end, strlen(end) + 1);
+       return 0;
+ out:
+       return -ENOMEM;
+}
+
+/* Returns realpath(3) of the given dentry but ignores chroot'ed root. */
+int tomoyo_realpath_from_dentry2(struct dentry *dentry,
+                                 struct vfsmount *mnt,
+                                 char *newname,
+                                 int newname_len)
+{
+       int error;
+       struct dentry *d_dentry;
+       struct vfsmount *d_mnt;
+       if (!dentry || !mnt || !newname || newname_len <= 0) return -EINVAL;
+       if (!current->fs) {
+               printk("%s: current->fs == NULL for pid=%d\n", __FUNCTION__, 
current->pid);
+               return -ENOENT;
+       }
+       d_dentry = dget(dentry);
+       d_mnt = mntget(mnt);
+       /***** CRITICAL SECTION START *****/
+       spin_lock(&dcache_lock);
+       error = tomoyo_get_absolute_path(d_dentry, d_mnt, newname, newname_len);
+       spin_unlock(&dcache_lock);
+       /***** CRITICAL SECTION END *****/
+       dput(d_dentry);
+       mntput(d_mnt);
+       return error;
+}
+
+/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
+/* These functions use tomoyo_alloc(), so caller must tomoyo_free() */
+/* if these functions didn't return NULL. */
+char *tomoyo_realpath_from_dentry(struct dentry *dentry, struct vfsmount *mnt)
+{
+       char *buf = tomoyo_alloc(TOMOYO_MAX_PATHNAME_LEN);
+       if (buf && tomoyo_realpath_from_dentry2(dentry, mnt, buf, 
TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
+               return buf;
+       tomoyo_free(buf);
+       return NULL;
+}
+
+char *tomoyo_realpath(const char *pathname)
+{
+       struct nameidata nd;
+       if (pathname && path_lookup(pathname, LOOKUP_FOLLOW, &nd) == 0) {
+               char *buf = tomoyo_realpath_from_dentry(nd.dentry, nd.mnt);
+               path_release(&nd);
+               return buf;
+       }
+       return NULL;
+}
+
+char *tomoyo_realpath_nofollow(const char *pathname)
+{
+       struct nameidata nd;
+       if (pathname && path_lookup(pathname, 0, &nd) == 0) {
+               char *buf = tomoyo_realpath_from_dentry(nd.dentry, nd.mnt);
+               path_release(&nd);
+               return buf;
+       }
+       return NULL;
+}
+
+/***** Private memory allocator. *****/
+
+/*
+ * Round up an integer so that the returned pointers are appropriately aligned.
+ * FIXME: Are there more requirements that is needed for assigning value 
atomically?
+ */
+static inline unsigned int tomoyo_roundup(const unsigned int size) {
+       if (sizeof(void *) >= sizeof(long)) {
+               return ((size + sizeof(void *) - 1) / sizeof(void *)) * 
sizeof(void *);
+       } else {
+               return ((size + sizeof(long) - 1) / sizeof(long)) * 
sizeof(long);
+       }
+}
+
+static unsigned int allocated_memory_for_elements = 0;
+
+unsigned int tomoyo_get_memory_used_for_elements(void)
+{
+       return allocated_memory_for_elements;
+}
+
+/* Allocate memory for structures. */
+/* The RAM is chunked, so NEVER try to kfree() the returned pointer. */
+void *tomoyo_alloc_element(const unsigned int size)
+{
+       static DECLARE_MUTEX(lock);
+       static char *buf = NULL;
+       static unsigned int buf_used_len = PAGE_SIZE;
+       char *ptr = NULL;
+       const unsigned int word_aligned_size = tomoyo_roundup(size);
+       if (word_aligned_size > PAGE_SIZE) return NULL;
+       down(&lock);
+       if (buf_used_len + word_aligned_size > PAGE_SIZE) {
+               if ((ptr = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL) {
+                       printk("ERROR: Out of memory for 
tomoyo_alloc_element().\n");
+                       if (!sbin_init_started) panic("MAC Initialization 
failed.\n");
+               } else {
+                       memset(ptr, 0, PAGE_SIZE);
+                       buf = ptr;
+                       allocated_memory_for_elements += PAGE_SIZE;
+                       buf_used_len = word_aligned_size;
+                       ptr = buf;
+               }
+       } else if (word_aligned_size) {
+               int i;
+               ptr = buf + buf_used_len;
+               buf_used_len += word_aligned_size;
+               for (i = 0; i < word_aligned_size; i++) {
+                       if (ptr[i]) {
+                               printk(KERN_ERR "WARNING: Reserved memory was 
tainted! "
+                                               "The system might go wrong.\n");
+                               ptr[i] = '\0';
+                       }
+               }
+       }
+       up(&lock);
+       return ptr;
+}
+
+/***** Shared memory allocator. *****/
+
+static unsigned int allocated_memory_for_savename = 0;
+
+unsigned int tomoyo_get_memory_used_for_save_name(void)
+{
+       return allocated_memory_for_savename;
+}
+
+#define MAX_HASH 256
+
+struct name_entry {
+       struct name_entry *next; /* Pointer to next record. NULL if none.       
      */
+       struct path_info entry;
+};
+
+struct free_memory_block_list {
+       struct free_memory_block_list *next; /* Pointer to next record. NULL if 
none. */
+       char *ptr;                           /* Pointer to a free area.         
      */
+       int len;                             /* Length of the area.             
      */
+};
+
+/* Keep the given name on the RAM. */
+/* The RAM is shared, so NEVER try to modify or kfree() the returned name. */
+const struct path_info *tomoyo_save_name(const char *name)
+{
+       static struct free_memory_block_list fmb_list = { NULL, NULL, 0 };
+       static struct name_entry name_list[MAX_HASH]; /* The list of names. */
+       static DECLARE_MUTEX(lock);
+       struct name_entry *ptr, *prev = NULL;
+       unsigned int hash;
+       struct free_memory_block_list *fmb = &fmb_list;
+       int len;
+       static int first_call = 1;
+       if (!name) return NULL;
+       len = strlen(name) + 1;
+       if (len > TOMOYO_MAX_PATHNAME_LEN) {
+               printk("ERROR: Name too long for tomoyo_save_name().\n");
+               return NULL;
+       }
+       hash = full_name_hash((const unsigned char *) name, len - 1);
+       down(&lock);
+       if (first_call) {
+               int i;
+               first_call = 0;
+               memset(&name_list, 0, sizeof(name_list));
+               for (i = 0; i < MAX_HASH; i++) {
+                       name_list[i].entry.name = "/";
+                       tomoyo_fill_path_info(&name_list[i].entry);
+               }
+               if (TOMOYO_MAX_PATHNAME_LEN > PAGE_SIZE) panic("Bad size.");
+       }
+       ptr = &name_list[hash % MAX_HASH];
+       while (ptr) {
+               if (hash == ptr->entry.hash && strcmp(name, ptr->entry.name) == 
0) goto out;
+               prev = ptr;
+               ptr = ptr->next;
+       }
+       while (len > fmb->len) {
+               if (fmb->next) {
+                       fmb = fmb->next;
+               } else {
+                       char *cp;
+                       if ((cp = kmalloc(PAGE_SIZE, GFP_KERNEL)) == NULL ||
+                           (fmb->next = tomoyo_alloc_element(sizeof(*fmb))) == 
NULL) {
+                               kfree(cp);
+                               printk("ERROR: Out of memory for 
tomoyo_save_name().\n");
+                               if (!sbin_init_started) panic("MAC Initialization 
failed.\n");
+                               goto out; /* ptr == NULL */
+                       }
+                       memset(cp, 0, PAGE_SIZE);
+                       allocated_memory_for_savename += PAGE_SIZE;
+                       fmb = fmb->next;
+                       fmb->ptr = cp;
+                       fmb->len = PAGE_SIZE;
+               }
+       }
+       if ((ptr = tomoyo_alloc_element(sizeof(*ptr))) == NULL) goto out;
+       ptr->entry.name = fmb->ptr;
+       memmove(fmb->ptr, name, len);
+       tomoyo_fill_path_info(&ptr->entry);
+       fmb->ptr += len;
+       fmb->len -= len;
+       prev->next = ptr; /* prev != NULL because name_list is not empty. */
+       if (fmb->len == 0) {
+               struct free_memory_block_list *ptr = &fmb_list;
+               while (ptr->next != fmb)
+                       ptr = ptr->next;
+               ptr->next = fmb->next;
+       }
+ out:
+       up(&lock);
+       return ptr ? &ptr->entry : NULL;
+}
+
+/***** Dynamic memory allocator. *****/
+
+struct cache_entry {
+       struct list_head list;
+       void *ptr;
+       int size;
+};
+
+static struct kmem_cache *ccs_cachep = NULL;
+
+void tomoyo_realpath_init(void)
+{
+       ccs_cachep = kmem_cache_create("ccs_cache", sizeof(struct cache_entry), 
0, 0, NULL, NULL);
+       if (!ccs_cachep) panic("Can't create cache.\n");
+}
+
+static LIST_HEAD(cache_list);
+static spinlock_t cache_list_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int dynamic_memory_size = 0;
+
+unsigned int tomoyo_get_memory_used_for_dynamic(void)
+{
+       return dynamic_memory_size;
+}
+
+void *tomoyo_alloc(const size_t size)
+{
+       void *ret = kmalloc(size, GFP_KERNEL);
+       if (ret) {
+               struct cache_entry *new_entry = kmem_cache_alloc(ccs_cachep, 
GFP_KERNEL);
+               if (!new_entry) {
+                       kfree(ret);
+                       ret = NULL;
+               } else {
+                       INIT_LIST_HEAD(&new_entry->list);
+                       new_entry->ptr = ret;
+                       new_entry->size = size;
+                       spin_lock(&cache_list_lock);
+                       list_add_tail(&new_entry->list, &cache_list);
+                       dynamic_memory_size += size;
+                       spin_unlock(&cache_list_lock);
+                       memset(ret, 0, size);
+               }
+       }
+       return ret;
+}
+
+void tomoyo_free(const void *p)
+{
+       struct list_head *v;
+       struct cache_entry *entry = NULL;
+       if (!p) return;
+       spin_lock(&cache_list_lock);
+       list_for_each(v, &cache_list) {
+               entry = list_entry(v, struct cache_entry, list);
+               if (entry->ptr != p) {
+                       entry = NULL;
+                       continue;
+               }
+               list_del(&entry->list);
+               dynamic_memory_size -= entry->size;
+               break;
+       }
+       spin_unlock(&cache_list_lock);
+       if (entry) {
+               kfree(p);
+               kmem_cache_free(ccs_cachep, entry);
+       } else {
+               printk("BUG: tomoyo_free() with invalid pointer.\n");
+       }
+}
---------------


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to