diff --git a/README.SELINUX-NAMESPACES b/README.SELINUX-NAMESPACES
new file mode 100644
index 000000000000..401f702bb583
--- /dev/null
+++ b/README.SELINUX-NAMESPACES
@@ -0,0 +1,22 @@
+Introduction.
+This experimental patch is designed to enable namespaces mode for LSM SELinux.
+
+This work is based on Stephen Smalley's patches https://github.com/stephensmalley/selinux-kernel/tree/working-selinuxns
+Some of which have been applied here, some of which have been reworked/fixed.
+
+Usage
+# create new namespace with name "ns", unshare previous one
+echo "ns" > /sys/fs/selinux/unshare; unshare --fork -m
+
+# remount selinuxfs, load policy
+umount /sys/fs/selinux; mount -t selinuxfs none /sys/fs/selinux/; load_policy
+
+# relabel everything
+restorecon / -Rv
+
+# check xattr's
+ls -Z
+
+# now enter enforcing mode
+setenforce 1
+
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index f02e31edae7c..b618c4e0ef36 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -106,6 +106,9 @@
 /* SECMARK reference count */
 static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
 
+/* Sequential namespace id */
+static atomic64_t selinux_namespace_id = ATOMIC_INIT(0);
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 static int selinux_enforcing_boot __initdata;
 
@@ -279,7 +282,8 @@ static int __inode_security_revalidate(struct inode *inode,
 	might_sleep_if(may_sleep);
 
 	if (selinux_initialized(current_selinux_state) &&
-	    isec->initialized != LABEL_INITIALIZED) {
+	    (isec->initialized != LABEL_INITIALIZED ||
+	     current_selinux_state->id != isec->namespace_id)) {
 		if (!may_sleep)
 			return -ECHILD;
 
@@ -288,6 +292,7 @@ static int __inode_security_revalidate(struct inode *inode,
 		 * @opt_dentry is NULL and no dentry for this inode can be
 		 * found; in that case, continue using the old label.
 		 */
+		isec->initialized = LABEL_INVALID;
 		inode_doinit_with_dentry(inode, dentry);
 	}
 	return 0;
@@ -497,6 +502,44 @@ static int selinux_is_sblabel_mnt(struct super_block *sb)
 	}
 }
 
+#define for_each_xattr_handler(handlers, handler)		\
+		for ((handler) = *(handlers)++;			\
+			(handler) != NULL;			\
+			(handler) = *(handlers)++)
+static const char *
+strcmp_prefix(const char *a, const char *a_prefix)
+{
+	while (*a_prefix && *a == *a_prefix) {
+		a++;
+		a_prefix++;
+	}
+	return *a_prefix ? NULL : a;
+}
+
+static int
+selinux_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
+		struct inode *inode, const char *name, void *value, size_t size)
+{
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(inode->i_sb);
+
+	if (strcmp(name, XATTR_SELINUX_SUFFIX) == 0 && selinux_initialized(current_selinux_state))
+		name = current_selinux_state->xattr_name;
+
+	return sbsech->xattr_handler->get(sbsech->xattr_handler, unused, inode, name, value, size);
+}
+
+static int selinux_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
+		struct inode *inode, const char *name, const void *value,
+		size_t size, int flags)
+{
+	struct superblock_security_head *sbsech = selinux_head_of_superblock(inode->i_sb);
+
+	if (strcmp(name, XATTR_SELINUX_SUFFIX) == 0 && selinux_initialized(current_selinux_state))
+		name = current_selinux_state->xattr_name;
+
+	return sbsech->xattr_handler->set(sbsech->xattr_handler, unused, inode, name, value, size, flags);
+}
+
 static int sb_finish_set_opts(struct super_block *sb)
 {
 	struct superblock_security_struct *sbsec = selinux_superblock(sb);
@@ -505,29 +548,77 @@ 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;
-		}
+		struct superblock_security_head *sbsech = selinux_head_of_superblock(sb);
+
+		/* Should check xattr support only once */
+		if (!sbsech->xattr_handler) {
+			const struct xattr_handler **handlers, *handler;
+			const struct xattr_handler *sec_handler = NULL;
+			const struct xattr_handler **s_xattr;
+			size_t count = 0;
+
+			/* 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 = __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;
+			}
+
+			handlers = sb->s_xattr;
+			for_each_xattr_handler(handlers, handler) {
+				count++;
+			}
+
+			s_xattr = kzalloc((1 + count) * sizeof(struct xattr_handler *) +
+							sizeof(struct xattr_handler),
+					GFP_KERNEL);
+			memcpy(s_xattr, sb->s_xattr, count * sizeof(struct xattr_handler *));
+			handlers = s_xattr;
+			for_each_xattr_handler(handlers, handler) {
+				const char *n = strcmp_prefix(XATTR_NAME_SELINUX, xattr_prefix(handler));
+				if (n) {
+					if (!handler->prefix ^ !*n) {
+						if (*n)
+							continue;
+						break;
+					}
+					sec_handler = handler;
+					break;
+				}
+			}
+
+			if (sec_handler) {
+				struct xattr_handler *hooked_handler = (void *)(s_xattr + count + 1);
+
+				*hooked_handler = *sec_handler;
+				hooked_handler->set = selinux_xattr_set;
+				hooked_handler->get = selinux_xattr_get;
+				sbsech->xattr_handler = sec_handler;
+				sbsech->old_s_xattr = sb->s_xattr;
+				*--handlers = hooked_handler;
+				sb->s_xattr = s_xattr;
+				pr_info("SELinux: (dev %s, type %s) installed xattr hook\n", sb->s_id, sb->s_type->name);
+			} else {
+				kfree(s_xattr);
+			}
 		}
 	}
 
@@ -812,6 +903,7 @@ static int selinux_set_mnt_opts(struct super_block *sb,
 			goto out;
 
 		root_isec->sid = rootcontext_sid;
+		root_isec->namespace_id = current_selinux_state->id;
 		root_isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -1395,6 +1487,102 @@ static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
 	return 0;
 }
 
+static int read_sid(struct inode *inode, u32 *psid)
+{
+	int rc;
+	struct superblock_security_struct *sbsec;
+	struct dentry *dentry;
+
+	sbsec = selinux_superblock(inode->i_sb);
+
+	if (sbsec->behavior == 0) {
+		*psid = SECINITSID_UNLABELED;
+		return 0;
+	}
+	if (sbsec->behavior != SECURITY_FS_USE_XATTR)
+		return -EINVAL;
+
+	dentry = d_find_alias(inode);
+
+	if (!dentry)
+		dentry = d_find_any_alias(inode);
+
+	if (!dentry)
+		return -EINVAL;
+
+	rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid, psid);
+
+	dput(dentry);
+	return rc;
+}
+
+static void update_sid_and_lock(struct inode_security_struct *isec)
+{
+	u32 sid;
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	sid = isec->sid;
+	if (nsid != cnsid) {
+		spin_unlock(&isec->lock);
+		if (read_sid(isec->inode, &sid) == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = sid;
+		}
+	}
+}
+static u32 update_sid(struct inode_security_struct *isec)
+{
+	u32 sid;
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	sid = isec->sid;
+	spin_unlock(&isec->lock);
+	if (nsid != cnsid) {
+		if (read_sid(isec->inode, &sid) == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = sid;
+			spin_unlock(&isec->lock);
+		}
+	}
+	return sid;
+}
+
+static int update_sid_rcu(struct inode_security_struct *isec, u32 *psid, bool rcu)
+{
+	u64 nsid, cnsid = current_selinux_state->id;
+
+//	TODO: atomic???
+	spin_lock(&isec->lock);
+	nsid = isec->namespace_id;
+	*psid = isec->sid;
+	spin_unlock(&isec->lock);
+	if (nsid != cnsid) {
+		int err;
+
+		if (rcu)
+			return -ECHILD;
+
+		err = read_sid(isec->inode, psid);
+		if (err == 0) {
+			spin_lock(&isec->lock);
+			isec->namespace_id = cnsid;
+			isec->sid = *psid;
+			spin_unlock(&isec->lock);
+		} else {
+			return err;
+		}
+	}
+	return 0;
+}
+
 /* The inode's security attributes must be initialized before first use. */
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
 {
@@ -1555,6 +1743,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
 
 		isec->initialized = LABEL_INITIALIZED;
 		isec->sid = sid;
+		isec->namespace_id = current_selinux_state->id;
 	}
 
 out_unlock:
@@ -1651,7 +1840,7 @@ static int inode_has_perm(const struct cred *cred,
 	isec = selinux_inode(inode);
 
 	return avc_has_perm(cred_selinux_state(cred),
-			    sid, isec->sid, isec->sclass, perms, adp);
+			    sid, update_sid(isec), isec->sclass, perms, adp);
 }
 
 /* Same as inode_has_perm, but pass explicit audit data containing
@@ -1781,7 +1970,7 @@ static int may_create(struct inode *dir,
 		      struct dentry *dentry,
 		      u16 tclass)
 {
-	const struct task_security_struct *tsec = selinux_cred(current_cred());
+	const struct task_security_struct *tsec = selinux_cred(current_real_cred());
 	struct inode_security_struct *dsec;
 	struct superblock_security_struct *sbsec;
 	u32 sid, newsid;
@@ -1844,7 +2033,7 @@ static int may_link(struct inode *dir,
 	av = DIR__SEARCH;
 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
 	rc = avc_has_perm(current_selinux_state,
-			  sid, dsec->sid, SECCLASS_DIR, av, &ad);
+			  sid, update_sid(dsec), SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 
@@ -1865,7 +2054,7 @@ static int may_link(struct inode *dir,
 	}
 
 	rc = avc_has_perm(current_selinux_state,
-			  sid, isec->sid, isec->sclass, av, &ad);
+			  sid, update_sid(isec), isec->sclass, av, &ad);
 	return rc;
 }
 
@@ -1890,18 +2079,18 @@ static inline int may_rename(struct inode *old_dir,
 
 	ad.u.dentry = old_dentry;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, old_dsec->sid, SECCLASS_DIR,
+			  sid, update_sid(old_dsec), SECCLASS_DIR,
 			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
 	if (rc)
 		return rc;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, old_isec->sid,
+			  sid, update_sid(old_isec),
 			  old_isec->sclass, FILE__RENAME, &ad);
 	if (rc)
 		return rc;
 	if (old_is_dir && new_dir != old_dir) {
 		rc = avc_has_perm(current_selinux_state,
-				  sid, old_isec->sid,
+				  sid, update_sid(old_isec),
 				  old_isec->sclass, DIR__REPARENT, &ad);
 		if (rc)
 			return rc;
@@ -1912,14 +2101,14 @@ static inline int may_rename(struct inode *old_dir,
 	if (d_is_positive(new_dentry))
 		av |= DIR__REMOVE_NAME;
 	rc = avc_has_perm(current_selinux_state,
-			  sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
+			  sid, update_sid(new_dsec), SECCLASS_DIR, av, &ad);
 	if (rc)
 		return rc;
 	if (d_is_positive(new_dentry)) {
 		new_isec = backing_inode_security(new_dentry);
 		new_is_dir = d_is_dir(new_dentry);
 		rc = avc_has_perm(current_selinux_state,
-				  sid, new_isec->sid,
+				  sid, update_sid(new_isec),
 				  new_isec->sclass,
 				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
 		if (rc)
@@ -2089,7 +2278,7 @@ static int selinux_binder_transfer_file(struct task_struct *from,
 
 	isec = backing_inode_security(dentry);
 	return avc_has_perm(current_selinux_state,
-			    sid, isec->sid, isec->sclass, file_to_av(file),
+			    sid, update_sid(isec), isec->sclass, file_to_av(file),
 			    &ad);
 }
 
@@ -2340,7 +2529,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 	} else {
 		/* Check for a default transition on this program. */
 		rc = security_transition_sid(current_selinux_state, old_tsec->sid,
-					     isec->sid, SECCLASS_PROCESS, NULL,
+					     update_sid(isec), SECCLASS_PROCESS, NULL,
 					     &new_tsec->sid);
 		if (rc)
 			return rc;
@@ -2359,7 +2548,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 
 	if (new_tsec->sid == old_tsec->sid) {
 		rc = avc_has_perm(current_selinux_state,
-				  old_tsec->sid, isec->sid,
+				  old_tsec->sid, update_sid(isec),
 				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
 		if (rc)
 			return rc;
@@ -2372,7 +2561,7 @@ static int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
 			return rc;
 
 		rc = avc_has_perm(current_selinux_state,
-				  new_tsec->sid, isec->sid,
+				  new_tsec->sid, update_sid(isec),
 				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
 		if (rc)
 			return rc;
@@ -2570,6 +2759,8 @@ static void sbsec_head_init(struct super_block *sb,
 {
 	INIT_LIST_HEAD(&sbsech->head);
 	spin_lock_init(&sbsech->lock);
+	sbsech->xattr_handler = NULL;
+	sbsech->old_s_xattr = NULL;
 }
 
 static struct superblock_security_struct *
@@ -2651,6 +2842,12 @@ static void selinux_sb_free_security(struct super_block *sb)
 		put_selinux_state(entry->state);
 		kfree(entry);
 	}
+	if (sbsech->old_s_xattr) {
+		const struct xattr_handler **s_xattr = sb->s_xattr;
+
+		sb->s_xattr = sbsech->old_s_xattr;
+		kfree(s_xattr);
+	}
 }
 
 static inline int opt_len(const char *s)
@@ -2910,6 +3107,7 @@ static int selinux_inode_alloc_security(struct inode *inode)
 	isec->sclass = SECCLASS_FILE;
 	isec->task_sid = sid;
 	isec->initialized = LABEL_INVALID;
+	isec->namespace_id = current_selinux_state->id;
 
 	return 0;
 }
@@ -2984,6 +3182,7 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
 		struct inode_security_struct *isec = selinux_inode(inode);
 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
 		isec->sid = newsid;
+		isec->namespace_id = current_selinux_state->id;
 		isec->initialized = LABEL_INITIALIZED;
 	}
 
@@ -3060,7 +3259,8 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
 	const struct cred *cred = current_cred();
 	struct common_audit_data ad;
 	struct inode_security_struct *isec;
-	u32 sid;
+	u32 sid, isid;
+	int rc;
 
 	validate_creds(cred);
 
@@ -3071,8 +3271,12 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
 	if (IS_ERR(isec))
 		return PTR_ERR(isec);
 
+	rc = update_sid_rcu(isec, &isid, rcu);
+	if (rc != 0)
+		return rc;
+
 	return avc_has_perm_flags(cred_selinux_state(cred),
-				  sid, isec->sid, isec->sclass, FILE__READ, &ad,
+				  sid, isid, isec->sclass, FILE__READ, &ad,
 				  rcu ? MAY_NOT_BLOCK : 0);
 }
 
@@ -3088,7 +3292,7 @@ static noinline int audit_inode_permission(struct inode *inode,
 	ad.u.inode = inode;
 
 	rc = slow_avc_audit(current_selinux_state,
-			    current_sid(), isec->sid, isec->sclass, perms,
+			    current_sid(), update_sid(isec), isec->sclass, perms,
 			    audited, denied, result, &ad);
 	if (rc)
 		return rc;
@@ -3102,7 +3306,7 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 	bool from_access;
 	bool no_block = mask & MAY_NOT_BLOCK;
 	struct inode_security_struct *isec;
-	u32 sid;
+	u32 sid, isid;
 	struct av_decision avd;
 	int rc, rc2;
 	u32 audited, denied;
@@ -3126,8 +3330,12 @@ static int selinux_inode_permission(struct inode *inode, int mask)
 	if (IS_ERR(isec))
 		return PTR_ERR(isec);
 
+	rc = update_sid_rcu(isec, &isid, no_block);
+	if (rc != 0)
+		return rc;
+
 	rc = avc_has_perm_noaudit(cred_selinux_state(cred),
-				  sid, isec->sid, isec->sclass, perms,
+				  sid, isid, isec->sclass, perms,
 				  no_block ? AVC_NONBLOCKING : 0,
 				  &avd);
 	audited = avc_audit_required(perms, &avd, rc,
@@ -3198,7 +3406,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	struct inode_security_struct *isec;
 	struct superblock_security_struct *sbsec;
 	struct common_audit_data ad;
-	u32 newsid, sid = current_sid();
+	u32 newsid, backsid, sid = current_sid();
 	int rc = 0;
 
 	if (strcmp(name, XATTR_NAME_SELINUX)) {
@@ -3225,8 +3433,9 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	ad.u.dentry = dentry;
 
 	isec = backing_inode_security(dentry);
+	backsid = update_sid(isec);
 	rc = avc_has_perm(current_selinux_state,
-			  sid, isec->sid, isec->sclass,
+			  sid, backsid, isec->sclass,
 			  FILE__RELABELFROM, &ad);
 	if (rc)
 		return rc;
@@ -3270,7 +3479,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
 	if (rc)
 		return rc;
 
-	rc = security_validate_transition(current_selinux_state, isec->sid, newsid,
+	rc = security_validate_transition(current_selinux_state, backsid, newsid,
 					  sid, isec->sclass);
 	if (rc)
 		return rc;
@@ -3319,6 +3528,7 @@ static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 
@@ -3432,13 +3642,14 @@ static int selinux_inode_getsecurity(struct inode *inode, const char *name, void
 	 * and lack of permission just means that we fall back to the
 	 * in-core context value, not a denial.
 	 */
+	//TODO: optimize sequence. need to read xattr only once
 	isec = inode_security(inode);
 	if (has_cap_mac_admin(false))
 		error = security_sid_to_context_force(current_selinux_state,
-						      isec->sid, &context,
+						      update_sid(isec), &context,
 						      &size);
 	else
-		error = security_sid_to_context(current_selinux_state, isec->sid,
+		error = security_sid_to_context(current_selinux_state, update_sid(isec),
 						&context, &size);
 	if (error)
 		return error;
@@ -3478,6 +3689,7 @@ static int selinux_inode_setsecurity(struct inode *inode, const char *name,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = newsid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 	return 0;
@@ -3494,7 +3706,7 @@ static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t
 static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
 {
 	struct inode_security_struct *isec = inode_security_novalidate(inode);
-	*secid = isec->sid;
+	*secid = update_sid(isec);
 }
 
 static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
@@ -3620,7 +3832,7 @@ static int selinux_file_permission(struct file *file, int mask)
 		return 0;
 
 	isec = inode_security(inode);
-	if (sid == fsec->sid && fsec->isid == isec->sid &&
+	if (sid == fsec->sid && fsec->isid == update_sid(isec) &&
 	    fsec->pseqno == avc_policy_seqno(current_selinux_state))
 		/* No change since file_open check. */
 		return 0;
@@ -3676,7 +3888,7 @@ static int ioctl_has_perm(const struct cred *cred, struct file *file,
 
 	isec = inode_security(inode);
 	rc = avc_has_extended_perms(current_selinux_state,
-				    ssid, isec->sid, isec->sclass,
+				    ssid, update_sid(isec), isec->sclass,
 				    requested, driver, xperm, &ad);
 out:
 	return rc;
@@ -3947,6 +4159,7 @@ static int selinux_file_open(struct file *file)
 	 * Task label is already saved in the file security
 	 * struct as its SID.
 	 */
+	//TODO: namespace?
 	fsec->isid = isec->sid;
 	fsec->pseqno = avc_policy_seqno(current_selinux_state);
 	/*
@@ -4046,21 +4259,23 @@ static int selinux_kernel_act_as(struct cred *new, u32 secid)
  * set the file creation context in a security record to the same as the
  * objective context of the specified inode
  */
+//TODO: namespace?
 static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
 {
 	struct inode_security_struct *isec = inode_security(inode);
 	struct task_security_struct *tsec = selinux_cred(new);
 	u32 sid = current_sid();
+	u32 isid = update_sid(isec);
 	int ret;
 
 	ret = avc_has_perm(tsec->state,
-			   sid, isec->sid,
+			   sid, isid,
 			   SECCLASS_KERNEL_SERVICE,
 			   KERNEL_SERVICE__CREATE_FILES_AS,
 			   NULL);
 
 	if (ret == 0)
-		tsec->create_sid = isec->sid;
+		tsec->create_sid = isid;
 	return ret;
 }
 
@@ -4105,7 +4320,7 @@ static int selinux_kernel_module_from_file(struct file *file)
 
 	isec = inode_security(file_inode(file));
 	return avc_has_perm(current_selinux_state,
-			    sid, isec->sid, SECCLASS_SYSTEM,
+			    sid, update_sid(isec), SECCLASS_SYSTEM,
 				SYSTEM__MODULE_LOAD, &ad);
 }
 
@@ -4267,6 +4482,7 @@ static void selinux_task_to_inode(struct task_struct *p,
 	spin_lock(&isec->lock);
 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 	spin_unlock(&isec->lock);
 }
@@ -4633,6 +4849,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
 
 	isec->sclass = sclass;
 	isec->sid = sid;
+	isec->namespace_id = current_selinux_state->id;
 	isec->initialized = LABEL_INITIALIZED;
 
 	if (sock->sk) {
@@ -4921,7 +5138,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 		return err;
 
 	isec = inode_security_novalidate(SOCK_INODE(sock));
-	spin_lock(&isec->lock);
+	update_sid_and_lock(isec);
 	sclass = isec->sclass;
 	sid = isec->sid;
 	spin_unlock(&isec->lock);
@@ -4929,6 +5146,7 @@ static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
 	newisec = inode_security_novalidate(SOCK_INODE(newsock));
 	newisec->sclass = sclass;
 	newisec->sid = sid;
+	newisec->namespace_id = current_selinux_state->id;
 	newisec->initialized = LABEL_INITIALIZED;
 
 	return 0;
@@ -5213,7 +5431,7 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
 
 	if (sock && family == PF_UNIX) {
 		isec = inode_security_novalidate(SOCK_INODE(sock));
-		peer_secid = isec->sid;
+		peer_secid = update_sid(isec);
 	} else if (skb)
 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
 
@@ -5280,8 +5498,11 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
 	struct sk_security_struct *sksec = sk->sk_security;
 
 	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
-	    sk->sk_family == PF_UNIX)
+	    sk->sk_family == PF_UNIX) {
 		isec->sid = sksec->sid;
+		//TODO: namespace?
+		//isec->namespace_id = ?
+	}
 	sksec->sclass = isec->sclass;
 }
 
@@ -7331,7 +7552,13 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
 
 static void selinux_state_free(struct work_struct *work);
 
-int selinux_state_create(struct selinux_state *parent, struct selinux_state **state)
+u64 selinux_new_state_id(void)
+{
+	return atomic64_fetch_add(1, &selinux_namespace_id);
+}
+
+int selinux_state_create(struct selinux_state *parent, struct selinux_state **state,
+						const char *suffix)
 {
 	struct selinux_state *newstate;
 	int rc;
@@ -7340,6 +7567,7 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 	if (!newstate)
 		return -ENOMEM;
 
+	newstate->id = selinux_new_state_id();
 	refcount_set(&newstate->count, 1);
 	INIT_WORK(&newstate->work, selinux_state_free);
 
@@ -7352,7 +7580,12 @@ int selinux_state_create(struct selinux_state *parent, struct selinux_state **st
 
 	if (parent)
 		newstate->parent = get_selinux_state(parent);
-
+	strcpy(newstate->xattr_name, XATTR_SELINUX_SUFFIX);
+	rc = strlen(suffix);
+	if (rc) {
+		strcat(newstate->xattr_name, ".");
+		strncat(newstate->xattr_name, suffix, rc);
+	}
 	*state = newstate;
 	return 0;
 err:
@@ -7385,7 +7618,7 @@ static __init int selinux_init(void)
 {
 	pr_info("SELinux:  Initializing.\n");
 
-	if (selinux_state_create(NULL, &init_selinux_state))
+	if (selinux_state_create(NULL, &init_selinux_state, ""))
 		panic("SELinux: Could not create initial namespace\n");
 	enforcing_set(init_selinux_state, selinux_enforcing_boot);
 	init_selinux_state->checkreqprot = selinux_checkreqprot_boot;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 6ad1db45b0d9..21566a1541f4 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -42,8 +42,10 @@ struct inode_security_struct {
 	u16 sclass;		/* security class of this object */
 	unsigned char initialized;	/* initialization flag */
 	spinlock_t lock;
+	u64 namespace_id;	/* pointer to selinux_state */
 };
 
+//TODO: namespace?
 struct file_security_struct {
 	u32 sid;		/* SID of open file description */
 	u32 fown_sid;		/* SID of file owner (for SIGIO) */
@@ -54,6 +56,9 @@ struct file_security_struct {
 struct superblock_security_head {
 	struct list_head head;		/* list head of superblock_security_struct */
 	spinlock_t lock;
+
+	const struct xattr_handler **old_s_xattr;
+	const struct xattr_handler *xattr_handler;
 };
 
 struct superblock_security_struct {
@@ -178,7 +183,7 @@ static inline struct ipc_security_struct *selinux_ipc(
  */
 static inline u32 current_sid(void)
 {
-	const struct task_security_struct *tsec = selinux_cred(current_cred());
+	const struct task_security_struct *tsec = selinux_cred(current_real_cred());
 
 	return tsec->sid;
 }
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index a5b698aae38c..0ab6b433dc9c 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -111,9 +111,13 @@ struct selinux_state {
 	struct selinux_policy __rcu *policy;
 	struct mutex policy_mutex;
 	struct selinux_state *parent;
+	u64 id;
+	char xattr_name[XATTR_NAME_MAX];
 } __randomize_layout;
 
-int selinux_state_create(struct selinux_state *parent, struct selinux_state **state);
+u64 selinux_new_state_id(void);
+int selinux_state_create(struct selinux_state *parent, struct selinux_state **state,
+						const char *suffix);
 void __put_selinux_state(struct selinux_state *state);
 
 void selinux_policy_free(struct selinux_policy *policy);
@@ -151,7 +155,7 @@ static inline struct task_security_struct *selinux_cred(const struct cred *cred)
 	return cred->security + selinux_blob_sizes.lbs_cred;
 }
 
-#define current_selinux_state (selinux_cred(current_cred())->state)
+#define current_selinux_state (selinux_cred(current_real_cred())->state)
 
 #define cred_selinux_state(cred) (selinux_cred(cred)->state)
 
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 9892527f2269..2da27f2fc2e3 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -31,6 +31,7 @@
 #include <linux/uaccess.h>
 #include <linux/kobject.h>
 #include <linux/ctype.h>
+#include <linux/xattr.h>
 
 /* selinuxfs pseudo filesystem for exporting the security policy API.
    Based on the proc code and the fs/nfsd/nfsctl.c code. */
@@ -347,10 +348,10 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 {
 	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
 	struct selinux_state *state = fsi->state;
-	char *page;
-	ssize_t length;
-	bool set;
-	int rc;
+	struct cred *cred;
+	struct task_security_struct *tsec;
+	char *suffix, *p;
+	ssize_t len;
 
 	if (state != current_selinux_state)
 		return -EPERM;
@@ -362,49 +363,76 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
 	if (*ppos != 0)
 		return -EINVAL;
 
-	rc = avc_has_perm(current_selinux_state, current_sid(),
+	len = avc_has_perm(current_selinux_state, current_sid(),
 			  SECINITSID_SECURITY, SECCLASS_SECURITY,
 			  SECURITY__UNSHARE, NULL);
-	if (rc)
-		return rc;
+	if (len)
+		return len;
 
-	page = memdup_user_nul(buf, count);
-	if (IS_ERR(page))
-		return PTR_ERR(page);
+	if (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2)
+		return -EINVAL;
 
-	length = -EINVAL;
-	if (kstrtobool(page, &set))
-		goto out;
+	suffix = memdup_user_nul(buf, count);
+	if (IS_ERR(suffix))
+		return PTR_ERR(suffix);
 
-	if (set) {
-		struct cred *cred = prepare_creds();
-		struct task_security_struct *tsec;
+	len = strnlen(suffix, count);
 
-		if (!cred) {
-			length = -ENOMEM;
-			goto out;
-		}
-		tsec = selinux_cred(cred);
-		if (selinux_state_create(state, &tsec->state)) {
-			abort_creds(cred);
-			length = -ENOMEM;
-			goto out;
-		}
-		tsec->osid = tsec->sid = SECINITSID_KERNEL;
-		tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
-			tsec->sockcreate_sid = SECSID_NULL;
-		tsec->parent_cred = get_current_cred();
-		commit_creds(cred);
+	/* cleanup some trash at the end of string */
+	for (p = suffix + len - 1; p >= suffix && isspace(*p); p--)
+		*p = 0;
+
+	len = p - suffix + 1;
+
+
+	/* TODO: check for uniqueness! */
+/*
+	if (!strcmp("", suffix)) {
+		len = -EINVAL;
+		goto out;
 	}
+*/
+
+	cred = prepare_creds();
+	if (!cred) {
+		len = -ENOMEM;
+		goto out;
+	}
+	tsec = cred->security;
+	if (selinux_state_create(state, &tsec->state, suffix)) {
+		abort_creds(cred);
+		len = -ENOMEM;
+		goto out;
+	}
+
+	tsec->osid = tsec->sid = SECINITSID_KERNEL;
+	tsec->exec_sid = tsec->create_sid = tsec->keycreate_sid =
+		tsec->sockcreate_sid = SECSID_NULL;
+	tsec->parent_cred = get_current_cred();
+	commit_creds(cred);
 
-	length = count;
 out:
-	kfree(page);
-	return length;
+	kfree(suffix);
+	return len < 0 ? len : count;
+}
+
+static ssize_t sel_read_unshare(struct file *file, char __user *buf,
+				size_t count, loff_t *ppos)
+{
+	struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
+	struct selinux_state *state = fsi->state;
+	size_t slen = sizeof(XATTR_SELINUX_SUFFIX);
+
+	if (state->id != current_selinux_state->id)
+		return -EPERM;
+
+	return simple_read_from_buffer(buf, count, ppos, state->xattr_name + slen,
+									strlen(state->xattr_name + slen));
 }
 
 static const struct file_operations sel_unshare_ops = {
 	.write		= sel_write_unshare,
+	.read		= sel_read_unshare,
 	.llseek		= generic_file_llseek,
 };
 
@@ -2174,7 +2202,7 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
 		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
 		[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
 					S_IWUGO},
-		[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0200},
+		[SEL_UNSHARE] = {"unshare", &sel_unshare_ops, 0600},
 		/* last one */ {""}
 	};
 
