@@ -734,7 +734,24 @@ static int selinux_set_mnt_opts(struct super_block *sb,
/* previously mounted with options, but not on this attempt? */
if ((sbsec->flags & SE_MNTMASK) && !opts)
goto out_double_mount;
+
+ /*
+ * If we are checking an already initialized mount and the
+ * options match, make sure to return back the
+ * SECURITY_LSM_NATIVE_LABELS flag if applicable. If the
+ * superblock has the NATIVE behavior set and the FS is not
+ * signaling its support (or vice versa), then it is a
+ * programmer error, so emit a WARNING and return -EINVAL.
+ */
rc = 0;
+ if (sbsec->behavior == SECURITY_FS_USE_NATIVE) {
+ if (WARN_ON(!(kern_flags & SECURITY_LSM_NATIVE_LABELS)))
+ rc = -EINVAL;
+ else
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ } else if (WARN_ON(kern_flags & SECURITY_LSM_NATIVE_LABELS)) {
+ rc = -EINVAL;
+ }
goto out;
}
When mounting an NFS export that is a mountpoint on the host, doing the same mount a second time leads to a security_sb_set_mnt_opts() call on an already intialized superblock, which leaves the SECURITY_LSM_NATIVE_LABELS flag unset even if it's provided by the FS. NFS then obediently clears NFS_CAP_SECURITY_LABEL from its server capability set, leading to any newly created inodes for this superblock to end up without labels. To fix this, make sure to return the SECURITY_LSM_NATIVE_LABELS flag when security_sb_set_mnt_opts() is called on an already initialized superblock with matching security options. While there, also do a sanity check to ensure that SECURITY_LSM_NATIVE_LABELS is set in kflags if and only if sbsec->behavior == SECURITY_FS_USE_NATIVE. Minimal reproducer: # systemctl start nfs-server # exportfs -o rw,no_root_squash,security_label localhost:/ # mount -t nfs -o "nfsvers=4.2" localhost:/etc /mnt # mount -t nfs -o "nfsvers=4.2" localhost:/etc /mnt # ls -lZ /mnt [all labels are system_u:object_r:unlabeled_t:s0] Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com> --- security/selinux/hooks.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)