Merge branch 'upstream' of git://lost.foo-projects.org/~ahkok/git/netdev-2.6 into tmp
[powerpc.git] / security / selinux / hooks.c
index 5b16196..90b4cdc 100644 (file)
@@ -101,6 +101,8 @@ static int __init selinux_enabled_setup(char *str)
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
+#else
+int selinux_enabled = 1;
 #endif
 
 /* Original (dummy) security module. */
@@ -117,6 +119,34 @@ static struct security_operations *secondary_ops = NULL;
 static LIST_HEAD(superblock_security_head);
 static DEFINE_SPINLOCK(sb_security_lock);
 
+static kmem_cache_t *sel_inode_cache;
+
+/* Return security context for a given sid or just the context 
+   length if the buffer is null or length is 0 */
+static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
+{
+       char *context;
+       unsigned len;
+       int rc;
+
+       rc = security_sid_to_context(sid, &context, &len);
+       if (rc)
+               return rc;
+
+       if (!buffer || !size)
+               goto getsecurity_exit;
+
+       if (size < len) {
+               len = -ERANGE;
+               goto getsecurity_exit;
+       }
+       memcpy(buffer, context, len);
+
+getsecurity_exit:
+       kfree(context);
+       return len;
+}
+
 /* Allocate and free functions for each kind of security blob. */
 
 static int task_alloc_security(struct task_struct *task)
@@ -146,10 +176,11 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
+       isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL);
        if (!isec)
                return -ENOMEM;
 
+       memset(isec, 0, sizeof(*isec));
        init_MUTEX(&isec->sem);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@ -172,7 +203,7 @@ static void inode_free_security(struct inode *inode)
        spin_unlock(&sbsec->isec_lock);
 
        inode->i_security = NULL;
-       kfree(isec);
+       kmem_cache_free(sel_inode_cache, isec);
 }
 
 static int file_alloc_security(struct file *file)
@@ -1929,7 +1960,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        struct task_security_struct *tsec;
        struct inode_security_struct *dsec;
        struct superblock_security_struct *sbsec;
-       struct inode_security_struct *isec;
        u32 newsid, clen;
        int rc;
        char *namep = NULL, *context;
@@ -1937,7 +1967,6 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
        tsec = current->security;
        dsec = dir->i_security;
        sbsec = dir->i_sb->s_security;
-       isec = inode->i_security;
 
        if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) {
                newsid = tsec->create_sid;
@@ -1957,7 +1986,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        inode_security_set_sid(inode, newsid);
 
-       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
        if (name) {
@@ -2209,6 +2238,11 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
        return -EACCES;
 }
 
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+      return XATTR_SELINUX_SUFFIX;
+}
+
 /*
  * Copy the in-core inode security context value to the user.  If the
  * getxattr() prior to this succeeded, check to see if we need to
@@ -2216,47 +2250,14 @@ static int selinux_inode_removexattr (struct dentry *dentry, char *name)
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
 {
        struct inode_security_struct *isec = inode->i_security;
-       char *context;
-       unsigned len;
-       int rc;
-
-       if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
-               rc = -EOPNOTSUPP;
-               goto out;
-       }
-
-       rc = security_sid_to_context(isec->sid, &context, &len);
-       if (rc)
-               goto out;
 
-       /* Probe for required buffer size */
-       if (!buffer || !size) {
-               rc = len;
-               goto out_free;
-       }
-
-       if (size < len) {
-               rc = -ERANGE;
-               goto out_free;
-       }
+       if (strcmp(name, XATTR_SELINUX_SUFFIX))
+               return -EOPNOTSUPP;
 
-       if (err > 0) {
-               if ((len == err) && !(memcmp(context, buffer, len))) {
-                       /* Don't need to canonicalize value */
-                       rc = err;
-                       goto out_free;
-               }
-               memset(buffer, 0, size);
-       }
-       memcpy(buffer, context, len);
-       rc = len;
-out_free:
-       kfree(context);
-out:
-       return rc;
+       return selinux_getsecurity(isec->sid, buffer, size);
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -3230,7 +3231,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
                goto out;
 
        /* Handle mapped IPv4 packets arriving via IPv6 sockets */
-       if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
+       if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
                family = PF_INET;
 
        read_lock_bh(&sk->sk_callback_lock);
@@ -4094,8 +4095,7 @@ static int selinux_getprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
-       u32 sid, len;
-       char *context;
+       u32 sid;
        int error;
 
        if (current != p) {
@@ -4104,9 +4104,6 @@ static int selinux_getprocattr(struct task_struct *p,
                        return error;
        }
 
-       if (!size)
-               return -ERANGE;
-
        tsec = p->security;
 
        if (!strcmp(name, "current"))
@@ -4123,16 +4120,7 @@ static int selinux_getprocattr(struct task_struct *p,
        if (!sid)
                return 0;
 
-       error = security_sid_to_context(sid, &context, &len);
-       if (error)
-               return error;
-       if (len > size) {
-               kfree(context);
-               return -ERANGE;
-       }
-       memcpy(value, context, len);
-       kfree(context);
-       return len;
+       return selinux_getsecurity(sid, value, size);
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -4290,6 +4278,7 @@ static struct security_operations selinux_ops = {
        .inode_getxattr =               selinux_inode_getxattr,
        .inode_listxattr =              selinux_inode_listxattr,
        .inode_removexattr =            selinux_inode_removexattr,
+       .inode_xattr_getsuffix =        selinux_inode_xattr_getsuffix,
        .inode_getsecurity =            selinux_inode_getsecurity,
        .inode_setsecurity =            selinux_inode_setsecurity,
        .inode_listsecurity =           selinux_inode_listsecurity,
@@ -4408,6 +4397,9 @@ static __init int selinux_init(void)
        tsec = current->security;
        tsec->osid = tsec->sid = SECINITSID_KERNEL;
 
+       sel_inode_cache = kmem_cache_create("selinux_inode_security",
+                                           sizeof(struct inode_security_struct),
+                                           0, SLAB_PANIC, NULL, NULL);
        avc_init();
 
        original_ops = secondary_ops = security_ops;
@@ -4430,6 +4422,7 @@ void selinux_complete_init(void)
 
        /* Set up any superblocks initialized prior to the policy load. */
        printk(KERN_INFO "SELinux:  Setting up existing superblocks.\n");
+       spin_lock(&sb_lock);
        spin_lock(&sb_security_lock);
 next_sb:
        if (!list_empty(&superblock_security_head)) {
@@ -4438,19 +4431,20 @@ next_sb:
                                           struct superblock_security_struct,
                                           list);
                struct super_block *sb = sbsec->sb;
-               spin_lock(&sb_lock);
                sb->s_count++;
-               spin_unlock(&sb_lock);
                spin_unlock(&sb_security_lock);
+               spin_unlock(&sb_lock);
                down_read(&sb->s_umount);
                if (sb->s_root)
                        superblock_doinit(sb, NULL);
                drop_super(sb);
+               spin_lock(&sb_lock);
                spin_lock(&sb_security_lock);
                list_del_init(&sbsec->list);
                goto next_sb;
        }
        spin_unlock(&sb_security_lock);
+       spin_unlock(&sb_lock);
 }
 
 /* SELinux requires early initialization in order to label
@@ -4545,6 +4539,7 @@ int selinux_disable(void)
        printk(KERN_INFO "SELinux:  Disabled at runtime.\n");
 
        selinux_disabled = 1;
+       selinux_enabled = 0;
 
        /* Reset security_ops to the secondary module, dummy or capability. */
        security_ops = secondary_ops;