selinux: fall back to SECURITY_FS_USE_GENFS if no xattr support
authorOndrej Mosnacek <omosnace@redhat.com>
Wed, 13 Jan 2021 12:38:02 +0000 (13:38 +0100)
committerPaul Moore <paul@paul-moore.com>
Wed, 13 Jan 2021 13:55:11 +0000 (08:55 -0500)
When a superblock is assigned the SECURITY_FS_USE_XATTR behavior by the
policy yet it lacks xattr support, try to fall back to genfs rather than
rejecting the mount. If a genfscon rule is found for the filesystem,
then change the behavior to SECURITY_FS_USE_GENFS, otherwise reject the
mount as before. A similar fallback is already done in security_fs_use()
if no behavior specification is found for the given filesystem.

This is needed e.g. for virtiofs, which may or may not support xattrs
depending on the backing host filesystem.

Example:
    # seinfo --genfs | grep ' ramfs'
       genfscon ramfs /  system_u:object_r:ramfs_t:s0
    # echo '(fsuse xattr ramfs (system_u object_r fs_t ((s0) (s0))))' >ramfs_xattr.cil
    # semodule -i ramfs_xattr.cil
    # mount -t ramfs none /mnt

Before:
    mount: /mnt: mount(2) system call failed: Operation not supported.

After:
    (mount succeeds)
    # ls -Zd /mnt
    system_u:object_r:ramfs_t:s0 /mnt

See also:
https://lore.kernel.org/selinux/20210105142148.GA3200@redhat.com/T/
https://github.com/fedora-selinux/selinux-policy/pull/478

Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Paul Moore <paul@paul-moore.com>
security/selinux/hooks.c

index 7fb7ff0..f2b272c 100644 (file)
@@ -484,6 +484,55 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
        }
 }
 
+static int sb_check_xattr_support(struct super_block *sb)
+{
+       struct superblock_security_struct *sbsec = sb->s_security;
+       struct dentry *root = sb->s_root;
+       struct inode *root_inode = d_backing_inode(root);
+       u32 sid;
+       int rc;
+
+       /*
+        * Make sure that the xattr handler exists and that no
+        * error other than -ENODATA is returned by getxattr on
+        * the root directory.  -ENODATA is ok, as this may be
+        * the first boot of the SELinux kernel before we have
+        * assigned xattr values to the filesystem.
+        */
+       if (!(root_inode->i_opflags & IOP_XATTR)) {
+               pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
+                       sb->s_id, sb->s_type->name);
+               goto fallback;
+       }
+
+       rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
+       if (rc < 0 && rc != -ENODATA) {
+               if (rc == -EOPNOTSUPP) {
+                       pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
+                               sb->s_id, sb->s_type->name);
+                       goto fallback;
+               } else {
+                       pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
+                               sb->s_id, sb->s_type->name, -rc);
+                       return rc;
+               }
+       }
+       return 0;
+
+fallback:
+       /* No xattr support - try to fallback to genfs if possible. */
+       rc = security_genfs_sid(&selinux_state, sb->s_type->name, "/",
+                               SECCLASS_DIR, &sid);
+       if (rc)
+               return -EOPNOTSUPP;
+
+       pr_warn("SELinux: (dev %s, type %s) falling back to genfs\n",
+               sb->s_id, sb->s_type->name);
+       sbsec->behavior = SECURITY_FS_USE_GENFS;
+       sbsec->sid = sid;
+       return 0;
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
        struct superblock_security_struct *sbsec = sb->s_security;
@@ -492,30 +541,9 @@ static int sb_finish_set_opts(struct super_block *sb)
        int rc = 0;
 
        if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
-               /* Make sure that the xattr handler exists and that no
-                  error other than -ENODATA is returned by getxattr on
-                  the root directory.  -ENODATA is ok, as this may be
-                  the first boot of the SELinux kernel before we have
-                  assigned xattr values to the filesystem. */
-               if (!(root_inode->i_opflags & IOP_XATTR)) {
-                       pr_warn("SELinux: (dev %s, type %s) has no "
-                              "xattr support\n", sb->s_id, sb->s_type->name);
-                       rc = -EOPNOTSUPP;
-                       goto out;
-               }
-
-               rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
-               if (rc < 0 && rc != -ENODATA) {
-                       if (rc == -EOPNOTSUPP)
-                               pr_warn("SELinux: (dev %s, type "
-                                      "%s) has no security xattr handler\n",
-                                      sb->s_id, sb->s_type->name);
-                       else
-                               pr_warn("SELinux: (dev %s, type "
-                                      "%s) getxattr errno %d\n", sb->s_id,
-                                      sb->s_type->name, -rc);
-                       goto out;
-               }
+               rc = sb_check_xattr_support(sb);
+               if (rc)
+                       return rc;
        }
 
        sbsec->flags |= SE_SBINITIALIZED;
@@ -554,7 +582,6 @@ static int sb_finish_set_opts(struct super_block *sb)
                spin_lock(&sbsec->isec_lock);
        }
        spin_unlock(&sbsec->isec_lock);
-out:
        return rc;
 }