security: update selinux
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / security / selinux / hooks.c
index fdead625043cc10ba457c58a415ea25aa7f2d159..55bb7c6a1b419295e482e243e3c039cbe0642ee4 100644 (file)
 #include <linux/msg.h>
 #include <linux/shm.h>
 
+// [ SEC_SELINUX_PORTING COMMON
+#include <linux/delay.h>
+// ] SEC_SELINUX_PORTING COMMON
+
 #include "avc.h"
 #include "objsec.h"
 #include "netif.h"
@@ -110,6 +114,7 @@ static int __init enforcing_setup(char *str)
        unsigned long enforcing;
        if (!strict_strtoul(str, 0, &enforcing))
                selinux_enforcing = enforcing ? 1 : 0;
+
        return 1;
 }
 __setup("enforcing=", enforcing_setup);
@@ -123,6 +128,7 @@ static int __init selinux_enabled_setup(char *str)
        unsigned long enabled;
        if (!strict_strtoul(str, 0, &enabled))
                selinux_enabled = enabled ? 1 : 0;
+
        return 1;
 }
 __setup("selinux=", selinux_enabled_setup);
@@ -419,15 +425,12 @@ static int sb_finish_set_opts(struct super_block *sb)
            sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
                sbsec->flags &= ~SE_SBLABELSUPP;
 
-       /* Special handling for sysfs. Is genfs but also has setxattr handler*/
-       if (strncmp(sb->s_type->name, "sysfs", sizeof("sysfs")) == 0)
-               sbsec->flags |= SE_SBLABELSUPP;
-
-       /*
-        * Special handling for rootfs. Is genfs but supports
-        * setting SELinux context on in-core inodes.
-        */
-       if (strncmp(sb->s_type->name, "rootfs", sizeof("rootfs")) == 0)
+       /* Special handling. Is genfs but also has in-core setxattr handler*/
+       if (!strcmp(sb->s_type->name, "sysfs") ||
+           !strcmp(sb->s_type->name, "pstore") ||
+           !strcmp(sb->s_type->name, "debugfs") ||
+           !strcmp(sb->s_type->name, "tmpfs") ||
+           !strcmp(sb->s_type->name, "rootfs"))
                sbsec->flags |= SE_SBLABELSUPP;
 
        /* Initialize the root inode. */
@@ -870,7 +873,6 @@ static int selinux_parse_opts_str(char *options,
        char *context = NULL, *defcontext = NULL;
        char *fscontext = NULL, *rootcontext = NULL;
        int rc, num_mnt_opts = 0;
-
        opts->num_mnt_opts = 0;
 
        /* Standard string-based options. */
@@ -1234,6 +1236,13 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
                goto out_unlock;
 
        sbsec = inode->i_sb->s_security;
+       /* To prevent Null pointer exception */
+       if (!sbsec) {
+               printk(KERN_ERR "[SELinux] sbsec is NULL, inode->i_sb->s_security is already freed. \n");
+               rc = -EINVAL;
+               goto out_unlock;
+       }
+
        if (!(sbsec->flags & SE_SBINITIALIZED)) {
                /* Defer initialization until selinux_complete_init,
                   after the initial policy is loaded and the security
@@ -1463,8 +1472,10 @@ static int task_has_perm(const struct task_struct *tsk1,
        u32 sid1, sid2;
 
        rcu_read_lock();
+
        __tsec1 = __task_cred(tsk1)->security;  sid1 = __tsec1->sid;
        __tsec2 = __task_cred(tsk2)->security;  sid2 = __tsec2->sid;
+
        rcu_read_unlock();
        return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL);
 }
@@ -1556,6 +1567,11 @@ static int inode_has_perm(const struct cred *cred,
        sid = cred_sid(cred);
        isec = inode->i_security;
 
+       if (unlikely(!isec)){
+               printk(KERN_CRIT "[SELinux] isec is NULL, inode->i_security is already freed. \n");
+               return -EINVAL;
+       }
+
        return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags);
 }
 
@@ -1891,6 +1907,7 @@ static int selinux_binder_transfer_binder(struct task_struct *from, struct task_
 {
        u32 fromsid = task_sid(from);
        u32 tosid = task_sid(to);
+
        return avc_has_perm(fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, NULL);
 }
 
@@ -2590,7 +2607,6 @@ static int selinux_mount(const char *dev_name,
                         void *data)
 {
        const struct cred *cred = current_cred();
-
        if (flags & MS_REMOUNT)
                return superblock_has_perm(cred, path->dentry->d_sb,
                                           FILESYSTEM__REMOUNT, NULL);
@@ -2786,6 +2802,25 @@ static int selinux_inode_permission(struct inode *inode, int mask)
        sid = cred_sid(cred);
        isec = inode->i_security;
 
+// [ SEC_SELINUX_PORTING COMMON
+       /* skip sid == 1(kernel), it means first boot time */
+       if(isec->initialized != 1 && sid != 1) {
+               int count = 5;
+
+               while(count-- > 0) {
+                       printk(KERN_ERR "SELinux : inode->i_security is not initialized. waiting...(%d/5)\n", 5-count); 
+                       udelay(500);
+                       if(isec->initialized == 1) {
+                               printk(KERN_ERR "SELinux : inode->i_security is INITIALIZED.\n"); 
+                               break;
+                       }
+               }
+               if(isec->initialized != 1) {
+                       printk(KERN_ERR "SELinux : inode->i_security is not initialized. not fixed.\n"); 
+               }
+       }
+// ] SEC_SELINUX_PORTING COMMON
+
        rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd);
        audited = avc_audit_required(perms, &avd, rc,
                                     from_access ? FILE__AUDIT_ACCESS : 0,
@@ -2817,7 +2852,8 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
                        ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
                return dentry_has_perm(cred, dentry, FILE__SETATTR);
 
-       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE))
+       if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE)
+                       && !(ia_valid & ATTR_FILE))
                av |= FILE__OPEN;
 
        return dentry_has_perm(cred, dentry, av);
@@ -3049,6 +3085,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
 {
        const int len = sizeof(XATTR_NAME_SELINUX);
+
        if (buffer && len <= buffer_size)
                memcpy(buffer, XATTR_NAME_SELINUX, len);
        return len;
@@ -3104,6 +3141,46 @@ static void selinux_file_free_security(struct file *file)
        file_free_security(file);
 }
 
+/*
+ * Check whether a task has the ioctl permission and cmd
+ * operation to an inode.
+ */
+int ioctl_has_perm(const struct cred *cred, struct file *file,
+               u32 requested, u16 cmd)
+{
+       struct common_audit_data ad;
+       struct file_security_struct *fsec = file->f_security;
+       struct inode *inode = file_inode(file);
+       struct inode_security_struct *isec = inode->i_security;
+       struct lsm_ioctlop_audit ioctl;
+       u32 ssid = cred_sid(cred);
+       int rc;
+       u8 driver = cmd >> 8;
+       u8 xperm = cmd & 0xff;
+
+       ad.type = LSM_AUDIT_DATA_IOCTL_OP;
+       ad.u.op = &ioctl;
+       ad.u.op->cmd = cmd;
+       ad.u.op->path = file->f_path;
+
+       if (ssid != fsec->sid) {
+               rc = avc_has_perm(ssid, fsec->sid,
+                               SECCLASS_FD,
+                               FD__USE,
+                               &ad);
+               if (rc)
+                       goto out;
+       }
+
+       if (unlikely(IS_PRIVATE(inode)))
+               return 0;
+
+       rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
+                       requested, driver, xperm, &ad);
+out:
+       return rc;
+}
+
 static int selinux_file_ioctl(struct file *file, unsigned int cmd,
                              unsigned long arg)
 {
@@ -3146,7 +3223,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd,
         * to the file's ioctl() function.
         */
        default:
-               error = file_has_perm(cred, file, FILE__IOCTL);
+               error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
        }
        return error;
 }
@@ -3526,7 +3603,6 @@ static int selinux_task_setnice(struct task_struct *p, int nice)
 static int selinux_task_setioprio(struct task_struct *p, int ioprio)
 {
        int rc;
-
        rc = cap_task_setioprio(p, ioprio);
        if (rc)
                return rc;
@@ -3885,6 +3961,11 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms)
        struct lsm_network_audit net = {0,};
        u32 tsid = task_sid(task);
 
+       if (unlikely(!sksec)){
+               printk(KERN_CRIT "[SELinux] sksec is NULL, socket is already freed. \n");
+               return -EINVAL;
+       }
+
        if (sksec->sid == SECINITSID_KERNEL)
                return 0;
 
@@ -5647,6 +5728,7 @@ static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
 static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
 {
        int len = 0;
+
        len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
                                                ctx, true);
        if (len < 0)
@@ -6032,7 +6114,6 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
 static int __init selinux_nf_ip_init(void)
 {
        int err = 0;
-
        if (!selinux_enabled)
                goto out;