Merge tag 'selinux-pr-20190305' of git://git.kernel.org/pub/scm/linux/kernel/git...
[muen/linux.git] / security / selinux / hooks.c
index 5d92167dbe0530edc1406c52e1fc28b665bb622f..2f82a54f870382440b621fde195ce69859bd286a 100644 (file)
@@ -490,16 +490,10 @@ static int may_context_mount_inode_relabel(u32 sid,
        return rc;
 }
 
-static int selinux_is_sblabel_mnt(struct super_block *sb)
+static int selinux_is_genfs_special_handling(struct super_block *sb)
 {
-       struct superblock_security_struct *sbsec = sb->s_security;
-
-       return sbsec->behavior == SECURITY_FS_USE_XATTR ||
-               sbsec->behavior == SECURITY_FS_USE_TRANS ||
-               sbsec->behavior == SECURITY_FS_USE_TASK ||
-               sbsec->behavior == SECURITY_FS_USE_NATIVE ||
-               /* Special handling. Genfs but also in-core setxattr handler */
-               !strcmp(sb->s_type->name, "sysfs") ||
+       /* Special handling. Genfs but also in-core setxattr handler */
+       return  !strcmp(sb->s_type->name, "sysfs") ||
                !strcmp(sb->s_type->name, "pstore") ||
                !strcmp(sb->s_type->name, "debugfs") ||
                !strcmp(sb->s_type->name, "tracefs") ||
@@ -509,6 +503,34 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
                  !strcmp(sb->s_type->name, "cgroup2")));
 }
 
+static int selinux_is_sblabel_mnt(struct super_block *sb)
+{
+       struct superblock_security_struct *sbsec = sb->s_security;
+
+       /*
+        * IMPORTANT: Double-check logic in this function when adding a new
+        * SECURITY_FS_USE_* definition!
+        */
+       BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
+
+       switch (sbsec->behavior) {
+       case SECURITY_FS_USE_XATTR:
+       case SECURITY_FS_USE_TRANS:
+       case SECURITY_FS_USE_TASK:
+       case SECURITY_FS_USE_NATIVE:
+               return 1;
+
+       case SECURITY_FS_USE_GENFS:
+               return selinux_is_genfs_special_handling(sb);
+
+       /* Never allow relabeling on context mounts */
+       case SECURITY_FS_USE_MNTPOINT:
+       case SECURITY_FS_USE_NONE:
+       default:
+               return 0;
+       }
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
@@ -2881,9 +2903,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
        if (IS_ERR(isec))
                return PTR_ERR(isec);
 
-       return avc_has_perm_flags(&selinux_state,
-                                 sid, isec->sid, isec->sclass, FILE__READ, &ad,
-                                 rcu ? MAY_NOT_BLOCK : 0);
+       return avc_has_perm(&selinux_state,
+                           sid, isec->sid, isec->sclass, FILE__READ, &ad);
 }
 
 static noinline int audit_inode_permission(struct inode *inode,
@@ -2938,7 +2959,9 @@ static int selinux_inode_permission(struct inode *inode, int mask)
                return PTR_ERR(isec);
 
        rc = avc_has_perm_noaudit(&selinux_state,
-                                 sid, isec->sid, isec->sclass, perms, 0, &avd);
+                                 sid, isec->sid, isec->sclass, perms,
+                                 (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
+                                 &avd);
        audited = avc_audit_required(perms, &avd, rc,
                                     from_access ? FILE__AUDIT_ACCESS : 0,
                                     &denied);
@@ -3197,12 +3220,16 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                                     const void *value, size_t size, int flags)
 {
        struct inode_security_struct *isec = inode_security_novalidate(inode);
+       struct superblock_security_struct *sbsec = inode->i_sb->s_security;
        u32 newsid;
        int rc;
 
        if (strcmp(name, XATTR_SELINUX_SUFFIX))
                return -EOPNOTSUPP;
 
+       if (!(sbsec->flags & SBLABEL_MNT))
+               return -EOPNOTSUPP;
+
        if (!value || !size)
                return -EACCES;
 
@@ -6236,7 +6263,10 @@ static void selinux_inode_invalidate_secctx(struct inode *inode)
  */
 static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
 {
-       return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
+       int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
+                                          ctx, ctxlen, 0);
+       /* Do not return error when suppressing label (SBLABEL_MNT not set). */
+       return rc == -EOPNOTSUPP ? 0 : rc;
 }
 
 /*