@@ -605,6 +605,13 @@ static int selinux_set_mnt_opts(struct super_block *sb,
u32 defcontext_sid = 0;
int rc = 0;
+ /*
+ * Specifying internal flags without providing a place to
+ * place the results is not allowed
+ */
+ if (kern_flags && !set_kern_flags)
+ return -EINVAL;
+
mutex_lock(&sbsec->lock);
if (!selinux_initialized()) {
@@ -612,6 +619,10 @@ static int selinux_set_mnt_opts(struct super_block *sb,
/* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security
server is ready to handle calls. */
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ sbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
goto out;
}
rc = -EINVAL;
@@ -619,12 +630,6 @@ static int selinux_set_mnt_opts(struct super_block *sb,
"before the security server is initialized\n");
goto out;
}
- if (kern_flags && !set_kern_flags) {
- /* Specifying internal flags without providing a place to
- * place the results is not allowed */
- rc = -EINVAL;
- goto out;
- }
/*
* Binary mount data FS will come through this function twice. Once
@@ -757,7 +762,17 @@ static int selinux_set_mnt_opts(struct super_block *sb,
* sets the label used on all file below the mountpoint, and will set
* the superblock context if not already set.
*/
- if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
+ if (sbsec->flags & SE_SBNATIVE) {
+ /*
+ * This means we are initializing a superblock that has been
+ * mounted before the SELinux was initialized and the
+ * filesystem requested native labeling. We had already
+ * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
+ * in the original mount attempt, so now we just need to set
+ * the SECURITY_FS_USE_NATIVE behavior.
+ */
+ sbsec->behavior = SECURITY_FS_USE_NATIVE;
+ } else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
sbsec->behavior = SECURITY_FS_USE_NATIVE;
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
}
@@ -868,13 +883,6 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
int set_context = (oldsbsec->flags & CONTEXT_MNT);
int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT);
- /*
- * if the parent was able to be mounted it clearly had no special lsm
- * mount options. thus we can safely deal with this superblock later
- */
- if (!selinux_initialized())
- return 0;
-
/*
* Specifying internal flags without providing a place to
* place the results is not allowed.
@@ -882,18 +890,31 @@ static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
if (kern_flags && !set_kern_flags)
return -EINVAL;
+ mutex_lock(&newsbsec->lock);
+
+ /*
+ * if the parent was able to be mounted it clearly had no special lsm
+ * mount options. thus we can safely deal with this superblock later
+ */
+ if (!selinux_initialized()) {
+ if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
+ newsbsec->flags |= SE_SBNATIVE;
+ *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
+ }
+ goto out;
+ }
+
/* how can we clone if the old one wasn't set up?? */
BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
/* if fs is reusing a sb, make sure that the contexts match */
if (newsbsec->flags & SE_SBINITIALIZED) {
+ mutex_unlock(&newsbsec->lock);
if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
return selinux_cmp_sb_context(oldsb, newsb);
}
- mutex_lock(&newsbsec->lock);
-
newsbsec->flags = oldsbsec->flags;
newsbsec->sid = oldsbsec->sid;
@@ -1394,8 +1415,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
spin_unlock(&isec->lock);
switch (sbsec->behavior) {
+ /*
+ * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
+ * via xattr when called from delayed_superblock_init().
+ */
case SECURITY_FS_USE_NATIVE:
- break;
case SECURITY_FS_USE_XATTR:
if (!(inode->i_opflags & IOP_XATTR)) {
sid = sbsec->def_sid;
@@ -65,6 +65,7 @@
#define SE_SBPROC 0x0200
#define SE_SBGENFS 0x0400
#define SE_SBGENFS_XATTR 0x0800
+#define SE_SBNATIVE 0x1000
#define CONTEXT_STR "context"
#define FSCONTEXT_STR "fscontext"