linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / security / selinux / hooks.c
index 9fcb30d..b65c201 100644 (file)
@@ -101,8 +101,6 @@ 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. */
@@ -119,34 +117,6 @@ 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)
@@ -176,11 +146,10 @@ static int inode_alloc_security(struct inode *inode)
        struct task_security_struct *tsec = current->security;
        struct inode_security_struct *isec;
 
-       isec = kmem_cache_alloc(sel_inode_cache, SLAB_KERNEL);
+       isec = kzalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
        if (!isec)
                return -ENOMEM;
 
-       memset(isec, 0, sizeof(*isec));
        init_MUTEX(&isec->sem);
        INIT_LIST_HEAD(&isec->list);
        isec->inode = inode;
@@ -203,7 +172,7 @@ static void inode_free_security(struct inode *inode)
        spin_unlock(&sbsec->isec_lock);
 
        inode->i_security = NULL;
-       kmem_cache_free(sel_inode_cache, isec);
+       kfree(isec);
 }
 
 static int file_alloc_security(struct file *file)
@@ -1960,6 +1929,7 @@ 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;
@@ -1967,6 +1937,7 @@ 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;
@@ -1986,7 +1957,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 
        inode_security_set_sid(inode, newsid);
 
-       if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
+       if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
                return -EOPNOTSUPP;
 
        if (name) {
@@ -2238,11 +2209,6 @@ 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
@@ -2250,14 +2216,47 @@ static const char *selinux_inode_xattr_getsuffix(void)
  *
  * Permission check is handled by selinux_inode_getxattr hook.
  */
-static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void *buffer, size_t size, int err)
+static int selinux_inode_getsecurity(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))
-               return -EOPNOTSUPP;
+       if (strcmp(name, XATTR_SELINUX_SUFFIX)) {
+               rc = -EOPNOTSUPP;
+               goto out;
+       }
 
-       return selinux_getsecurity(isec->sid, buffer, size);
+       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 (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;
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -2366,6 +2365,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
 
 static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
 {
+#ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) {
                /*
                 * We are making executable an anonymous mapping or a
@@ -2376,6 +2376,7 @@ static int file_map_prot_check(struct file *file, unsigned long prot, int shared
                if (rc)
                        return rc;
        }
+#endif
 
        if (file) {
                /* read access is always possible with a mapping */
@@ -2422,6 +2423,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
        if (selinux_checkreqprot)
                prot = reqprot;
 
+#ifndef CONFIG_PPC32
        if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
                rc = 0;
                if (vma->vm_start >= vma->vm_mm->start_brk &&
@@ -2446,6 +2448,7 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
                if (rc)
                        return rc;
        }
+#endif
 
        return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
 }
@@ -3227,7 +3230,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 == htons(ETH_P_IP))
+       if (family == PF_INET6 && skb->protocol == ntohs(ETH_P_IP))
                family = PF_INET;
 
        read_lock_bh(&sk->sk_callback_lock);
@@ -3315,38 +3318,24 @@ out:
        return err;
 }
 
-static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
-                                           int __user *optlen, unsigned len)
+static int selinux_socket_getpeersec(struct socket *sock, char __user *optval,
+                                    int __user *optlen, unsigned len)
 {
        int err = 0;
        char *scontext;
        u32 scontext_len;
        struct sk_security_struct *ssec;
        struct inode_security_struct *isec;
-       u32 peer_sid = 0;
 
        isec = SOCK_INODE(sock)->i_security;
-
-       /* if UNIX_STREAM check peer_sid, if TCP check dst for labelled sa */
-       if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET) {
-               ssec = sock->sk->sk_security;
-               peer_sid = ssec->peer_sid;
-       }
-       else if (isec->sclass == SECCLASS_TCP_SOCKET) {
-               peer_sid = selinux_socket_getpeer_stream(sock->sk);
-
-               if (peer_sid == SECSID_NULL) {
-                       err = -ENOPROTOOPT;
-                       goto out;
-               }
-       }
-       else {
+       if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
                err = -ENOPROTOOPT;
                goto out;
        }
 
-       err = security_sid_to_context(peer_sid, &scontext, &scontext_len);
-
+       ssec = sock->sk->sk_security;
+       
+       err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
        if (err)
                goto out;
 
@@ -3367,23 +3356,6 @@ out:
        return err;
 }
 
-static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
-{
-       int err = 0;
-       u32 peer_sid = selinux_socket_getpeer_dgram(skb);
-
-       if (peer_sid == SECSID_NULL)
-               return -EINVAL;
-
-       err = security_sid_to_context(peer_sid, secdata, seclen);
-       if (err)
-               return err;
-
-       return 0;
-}
-
-
-
 static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
 {
        return sk_alloc_security(sk, family, priority);
@@ -4091,7 +4063,8 @@ static int selinux_getprocattr(struct task_struct *p,
                               char *name, void *value, size_t size)
 {
        struct task_security_struct *tsec;
-       u32 sid;
+       u32 sid, len;
+       char *context;
        int error;
 
        if (current != p) {
@@ -4100,6 +4073,9 @@ static int selinux_getprocattr(struct task_struct *p,
                        return error;
        }
 
+       if (!size)
+               return -ERANGE;
+
        tsec = p->security;
 
        if (!strcmp(name, "current"))
@@ -4116,7 +4092,16 @@ static int selinux_getprocattr(struct task_struct *p,
        if (!sid)
                return 0;
 
-       return selinux_getsecurity(sid, value, size);
+       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;
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -4274,7 +4259,6 @@ 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,
@@ -4360,8 +4344,7 @@ static struct security_operations selinux_ops = {
        .socket_setsockopt =            selinux_socket_setsockopt,
        .socket_shutdown =              selinux_socket_shutdown,
        .socket_sock_rcv_skb =          selinux_socket_sock_rcv_skb,
-       .socket_getpeersec_stream =     selinux_socket_getpeersec_stream,
-       .socket_getpeersec_dgram =      selinux_socket_getpeersec_dgram,
+       .socket_getpeersec =            selinux_socket_getpeersec,
        .sk_alloc_security =            selinux_sk_alloc_security,
        .sk_free_security =             selinux_sk_free_security,
        .sk_getsid =                    selinux_sk_getsid_security,
@@ -4393,9 +4376,6 @@ 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;
@@ -4418,7 +4398,6 @@ 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)) {
@@ -4427,20 +4406,19 @@ next_sb:
                                           struct superblock_security_struct,
                                           list);
                struct super_block *sb = sbsec->sb;
+               spin_lock(&sb_lock);
                sb->s_count++;
-               spin_unlock(&sb_security_lock);
                spin_unlock(&sb_lock);
+               spin_unlock(&sb_security_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
@@ -4535,7 +4513,6 @@ 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;