diff --git a/Documentation/security/LSM.txt b/Documentation/security/LSM.txt
index 3db7e67..125c489 100644
--- a/Documentation/security/LSM.txt
+++ b/Documentation/security/LSM.txt
@@ -16,11 +16,25 @@ MAC extensions, other extensions can be built using the LSM to provide
 specific changes to system operation when these tweaks are not available
 in the core functionality of Linux itself.
 
-Without a specific LSM built into the kernel, the default LSM will be the
-Linux capabilities system. Most LSMs choose to extend the capabilities
-system, building their checks on top of the defined capability hooks.
-For more details on capabilities, see capabilities(7) in the Linux
-man-pages project.
+The Linux capabilities modules will always be included. For more details
+on capabilities, see capabilities(7) in the Linux man-pages project.
+This may be followed by any number of "minor" modules and at most one
+"major" module.
+
+A list of the active security modules can be found by reading
+/sys/kernel/security/lsm. This is a comma separated list, and
+will always include the capability module. The list reflects the
+order in which checks are made. The capability module will always
+be first, followed by any "minor" modules (e.g. Yama) and then
+the one "major" module (e.g. SELinux) if there is one configured.
+
+Process attributes associated with "major" security modules should
+be accessed and maintained using the special files in the module
+specific subdirectories in /proc/.../attr. The attributes related
+to Smack would be found in /proc/.../attr/smack while the attributes
+for SELinux would be in /proc/.../attr/selinux. Using the files
+found directly in /proc/.../attr (e.g. current) should be avoided.
+These files remain as legacy interfaces.
 
 Based on https://lkml.org/lkml/2007/10/26/215,
 a new LSM is accepted into the kernel when its intent (a description of
@@ -31,4 +45,4 @@ that end users and distros can make a more informed decision about which
 LSMs suit their requirements.
 
 For extensive documentation on the available LSM hook interfaces, please
-see include/linux/security.h.
+see include/linux/lsm_hooks.h.
diff --git a/fs/proc/base.c b/fs/proc/base.c
index a11eb71..df94f26 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -131,9 +131,13 @@ struct pid_entry {
 #define REG(NAME, MODE, fops)				\
 	NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
 #define ONE(NAME, MODE, show)				\
-	NOD(NAME, (S_IFREG|(MODE)), 			\
+	NOD(NAME, (S_IFREG|(MODE)),			\
 		NULL, &proc_single_file_operations,	\
 		{ .proc_show = show } )
+#define ATTR(LSM, NAME, MODE)				\
+	NOD(NAME, (S_IFREG|(MODE)),			\
+		NULL, &proc_pid_attr_operations,	\
+		{ .lsm = LSM })
 
 /*
  * Count the number of hardlinks for the pid_entry table, excluding the .
@@ -2433,7 +2437,7 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
 	if (!task)
 		return -ESRCH;
 
-	length = security_getprocattr(task,
+	length = security_getprocattr(task, PROC_I(inode)->op.lsm,
 				      (char*)file->f_path.dentry->d_name.name,
 				      &p);
 	put_task_struct(task);
@@ -2473,7 +2477,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 	if (length < 0)
 		goto out_free;
 
-	length = security_setprocattr(task,
+	length = security_setprocattr(task, PROC_I(inode)->op.lsm,
 				      (char*)file->f_path.dentry->d_name.name,
 				      page, count);
 	mutex_unlock(&task->signal->cred_guard_mutex);
@@ -2491,13 +2495,86 @@ static const struct file_operations proc_pid_attr_operations = {
 	.llseek		= generic_file_llseek,
 };
 
+#define LSM_DIR_OPS(LSM) \
+static int proc_##LSM##_attr_dir_iterate(struct file *filp, \
+			     struct dir_context *ctx) \
+{ \
+	return proc_pident_readdir(filp, ctx, \
+				   LSM##_attr_dir_stuff, \
+				   ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct file_operations proc_##LSM##_attr_dir_ops = { \
+	.read		= generic_read_dir, \
+	.iterate	= proc_##LSM##_attr_dir_iterate, \
+	.llseek		= default_llseek, \
+}; \
+\
+static struct dentry *proc_##LSM##_attr_dir_lookup(struct inode *dir, \
+				struct dentry *dentry, unsigned int flags) \
+{ \
+	return proc_pident_lookup(dir, dentry, \
+				  LSM##_attr_dir_stuff, \
+				  ARRAY_SIZE(LSM##_attr_dir_stuff)); \
+} \
+\
+static const struct inode_operations proc_##LSM##_attr_dir_inode_ops = { \
+	.lookup		= proc_##LSM##_attr_dir_lookup, \
+	.getattr	= pid_getattr, \
+	.setattr	= proc_setattr, \
+}
+
+#ifdef CONFIG_SECURITY_SELINUX
+static const struct pid_entry selinux_attr_dir_stuff[] = {
+	ATTR("selinux", "current",	S_IRUGO|S_IWUGO),
+	ATTR("selinux", "prev",		S_IRUGO),
+	ATTR("selinux", "exec",		S_IRUGO|S_IWUGO),
+	ATTR("selinux", "fscreate",	S_IRUGO|S_IWUGO),
+	ATTR("selinux", "keycreate",	S_IRUGO|S_IWUGO),
+	ATTR("selinux", "sockcreate",	S_IRUGO|S_IWUGO),
+	ATTR("selinux", "context",	S_IRUGO|S_IWUGO),
+};
+LSM_DIR_OPS(selinux);
+#endif
+
+#ifdef CONFIG_SECURITY_SMACK
+static const struct pid_entry smack_attr_dir_stuff[] = {
+	ATTR("smack", "current",	S_IRUGO|S_IWUGO),
+	ATTR("smack", "context",	S_IRUGO|S_IWUGO),
+};
+LSM_DIR_OPS(smack);
+#endif
+
+#ifdef CONFIG_SECURITY_APPARMOR
+static const struct pid_entry apparmor_attr_dir_stuff[] = {
+	ATTR("apparmor", "current",	S_IRUGO|S_IWUGO),
+	ATTR("apparmor", "prev",	S_IRUGO),
+	ATTR("apparmor", "exec",	S_IRUGO|S_IWUGO),
+	ATTR("apparmor", "context",	S_IRUGO|S_IWUGO),
+};
+LSM_DIR_OPS(apparmor);
+#endif
+
 static const struct pid_entry attr_dir_stuff[] = {
-	REG("current",    S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-	REG("prev",       S_IRUGO,	   proc_pid_attr_operations),
-	REG("exec",       S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-	REG("fscreate",   S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-	REG("keycreate",  S_IRUGO|S_IWUGO, proc_pid_attr_operations),
-	REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
+	ATTR(NULL, "current",		S_IRUGO|S_IWUGO),
+	ATTR(NULL, "prev",		S_IRUGO),
+	ATTR(NULL, "exec",		S_IRUGO|S_IWUGO),
+	ATTR(NULL, "fscreate",		S_IRUGO|S_IWUGO),
+	ATTR(NULL, "keycreate",		S_IRUGO|S_IWUGO),
+	ATTR(NULL, "sockcreate",	S_IRUGO|S_IWUGO),
+	ATTR(NULL, "context",		S_IRUGO|S_IWUGO),
+#ifdef CONFIG_SECURITY_SELINUX
+	DIR("selinux",			S_IRUGO|S_IXUGO,
+	    proc_selinux_attr_dir_inode_ops, proc_selinux_attr_dir_ops),
+#endif
+#ifdef CONFIG_SECURITY_SMACK
+	DIR("smack",			S_IRUGO|S_IXUGO,
+	    proc_smack_attr_dir_inode_ops, proc_smack_attr_dir_ops),
+#endif
+#ifdef CONFIG_SECURITY_APPARMOR
+	DIR("apparmor",			S_IRUGO|S_IXUGO,
+	    proc_apparmor_attr_dir_inode_ops, proc_apparmor_attr_dir_ops),
+#endif
 };
 
 static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index aa27810..b607cd5 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -56,6 +56,7 @@ union proc_op {
 	int (*proc_show)(struct seq_file *m,
 		struct pid_namespace *ns, struct pid *pid,
 		struct task_struct *task);
+	const char *lsm;
 };
 
 struct proc_inode {
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 7ae3976..5b796db 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1514,9 +1514,10 @@ union security_list_options {
 
 	void (*d_instantiate)(struct dentry *dentry, struct inode *inode);
 
-	int (*getprocattr)(struct task_struct *p, char *name, char **value);
-	int (*setprocattr)(struct task_struct *p, char *name, void *value,
-				size_t size);
+	int (*getprocattr)(struct task_struct *p, const char *lsm, char *name,
+				char **value);
+	int (*setprocattr)(struct task_struct *p, const char *lsm, char *name,
+				void *value, size_t size);
 	int (*ismaclabel)(const char *name);
 	int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen);
 	int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid);
@@ -1841,6 +1842,7 @@ struct security_hook_list {
 	struct list_head		list;
 	struct list_head		*head;
 	union security_list_options	hook;
+	char				*lsm;
 };
 
 /*
@@ -1853,15 +1855,10 @@ struct security_hook_list {
 	{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
 
 extern struct security_hook_heads security_hook_heads;
+extern char *lsm_names;
 
-static inline void security_add_hooks(struct security_hook_list *hooks,
-				      int count)
-{
-	int i;
-
-	for (i = 0; i < count; i++)
-		list_add_tail_rcu(&hooks[i].list, hooks[i].head);
-}
+extern void security_add_hooks(struct security_hook_list *hooks, int count,
+				char *lsm);
 
 #ifdef CONFIG_SECURITY_SELINUX_DISABLE
 /*
diff --git a/include/linux/security.h b/include/linux/security.h
index 14df373..383fcb0 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -355,8 +355,10 @@ int security_sem_semctl(struct sem_array *sma, int cmd);
 int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
 			unsigned nsops, int alter);
 void security_d_instantiate(struct dentry *dentry, struct inode *inode);
-int security_getprocattr(struct task_struct *p, char *name, char **value);
-int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+				char **value);
+int security_setprocattr(struct task_struct *p, const char *lsm, char *name,
+				void *value, size_t size);
 int security_netlink_send(struct sock *sk, struct sk_buff *skb);
 int security_ismaclabel(const char *name);
 int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
@@ -1075,15 +1077,18 @@ static inline int security_sem_semop(struct sem_array *sma,
 	return 0;
 }
 
-static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
+static inline void security_d_instantiate(struct dentry *dentry,
+						struct inode *inode)
 { }
 
-static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
+static inline int security_getprocattr(struct task_struct *p, const char *lsm,
+					char *name, char **value)
 {
 	return -EINVAL;
 }
 
-static inline int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+static inline int security_setprocattr(struct task_struct *p, const char *lsm,
+					char *name, void *value, size_t size)
 {
 	return -EINVAL;
 }
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 2660fbc..7e54292 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -468,8 +468,8 @@ static int apparmor_file_mprotect(struct vm_area_struct *vma,
 			   !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
 }
 
-static int apparmor_getprocattr(struct task_struct *task, char *name,
-				char **value)
+static int apparmor_getprocattr(struct task_struct *task, const char *lsm,
+				char *name, char **value)
 {
 	int error = -ENOENT;
 	/* released below */
@@ -479,6 +479,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
 
 	if (strcmp(name, "current") == 0)
 		profile = aa_get_newest_profile(cxt->profile);
+	else if (strcmp(name, "context") == 0)
+		profile = aa_get_newest_profile(cxt->profile);
 	else if (strcmp(name, "prev") == 0  && cxt->previous)
 		profile = aa_get_newest_profile(cxt->previous);
 	else if (strcmp(name, "exec") == 0 && cxt->onexec)
@@ -486,8 +488,29 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
 	else
 		error = -EINVAL;
 
-	if (profile)
-		error = aa_getprocattr(profile, value);
+	if (profile) {
+		if (strcmp(name, "context") == 0) {
+			char *vp;
+			char *np;
+
+			error = aa_getprocattr(profile, &vp);
+			if (error > 0) {
+				error += 12;
+				*value = kzalloc(error, GFP_KERNEL);
+				if (*value == NULL)
+					error = -ENOMEM;
+				else {
+					sprintf(*value, "apparmor='%s'", vp);
+					np = strchr(*value, '\n');
+					if (np != NULL) {
+						np[0] = '\'';
+						np[1] = '\0';
+					}
+				}
+			}
+		} else
+			error = aa_getprocattr(profile, value);
+	}
 
 	aa_put_profile(profile);
 	put_cred(cred);
@@ -495,8 +518,8 @@ static int apparmor_getprocattr(struct task_struct *task, char *name,
 	return error;
 }
 
-static int apparmor_setprocattr(struct task_struct *task, char *name,
-				void *value, size_t size)
+static int apparmor_setprocattr(struct task_struct *task, const char *lsm,
+				char *name, void *value, size_t size)
 {
 	struct common_audit_data sa;
 	struct apparmor_audit_data aad = {0,};
@@ -530,7 +553,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 		return -EINVAL;
 
 	arg_size = size - (args - (char *) value);
-	if (strcmp(name, "current") == 0) {
+	if (strcmp(name, "current") == 0 || strcmp(name, "context") == 0) {
 		if (strcmp(command, "changehat") == 0) {
 			error = aa_setprocattr_changehat(args, arg_size,
 							 !AA_DO_TEST);
@@ -552,7 +575,10 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 		else
 			goto fail;
 	} else
-		/* only support the "current" and "exec" process attributes */
+		/*
+		 * only support the "context", "current" and
+		 * "exec" process attributes
+		 */
 		return -EINVAL;
 
 	if (!error)
@@ -880,7 +906,8 @@ static int __init apparmor_init(void)
 		aa_free_root_ns();
 		goto alloc_out;
 	}
-	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks));
+	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
+				"apparmor");
 
 	/* Report that AppArmor successfully initialized */
 	apparmor_initialized = 1;
diff --git a/security/commoncap.c b/security/commoncap.c
index e7fadde..d101734 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -1090,7 +1090,8 @@ struct security_hook_list capability_hooks[] = {
 
 void __init capability_add_hooks(void)
 {
-	security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks));
+	security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks),
+				"capability");
 }
 
 #endif /* CONFIG_SECURITY */
diff --git a/security/inode.c b/security/inode.c
index 28414b0..235ad82 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/namei.h>
 #include <linux/security.h>
+#include <linux/lsm_hooks.h>
 #include <linux/magic.h>
 
 static struct vfsmount *mount;
@@ -208,6 +209,21 @@ void securityfs_remove(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(securityfs_remove);
 
+#ifdef CONFIG_SECURITY
+static struct dentry *lsm_dentry;
+static ssize_t lsm_read(struct file *filp, char __user *buf, size_t count,
+			loff_t *ppos)
+{
+	return simple_read_from_buffer(buf, count, ppos, lsm_names,
+		strlen(lsm_names));
+}
+
+static const struct file_operations lsm_ops = {
+	.read = lsm_read,
+	.llseek = generic_file_llseek,
+};
+#endif
+
 static int __init securityfs_init(void)
 {
 	int retval;
@@ -217,9 +233,15 @@ static int __init securityfs_init(void)
 		return retval;
 
 	retval = register_filesystem(&fs_type);
-	if (retval)
+	if (retval) {
 		sysfs_remove_mount_point(kernel_kobj, "security");
-	return retval;
+		return retval;
+	}
+#ifdef CONFIG_SECURITY
+	lsm_dentry = securityfs_create_file("lsm", S_IRUGO, NULL, NULL,
+						&lsm_ops);
+#endif
+	return 0;
 }
 
 core_initcall(securityfs_init);
diff --git a/security/security.c b/security/security.c
index 7095693..6ed098e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -32,6 +32,7 @@
 /* Maximum number of letters for an LSM name string */
 #define SECURITY_NAME_MAX	10
 
+char *lsm_names;
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
 	CONFIG_DEFAULT_SECURITY;
@@ -78,6 +79,23 @@ static int __init choose_lsm(char *str)
 }
 __setup("security=", choose_lsm);
 
+static int lsm_append(char *new, char **result)
+{
+	char *cp;
+
+	if (*result == NULL) {
+		*result = kstrdup(new, GFP_KERNEL);
+	} else {
+		cp = kzalloc(strlen(*result) + strlen(new) + 2, GFP_KERNEL);
+		if (cp == NULL)
+			return -ENOMEM;
+		sprintf(cp, "%s,%s", *result, new);
+		kfree(*result);
+		*result = cp;
+	}
+	return 0;
+}
+
 /**
  * security_module_enable - Load given security module on boot ?
  * @module: the name of the module
@@ -97,6 +115,26 @@ int __init security_module_enable(const char *module)
 	return !strcmp(module, chosen_lsm);
 }
 
+/**
+ * security_add_hooks - Add a modules hooks to the hook lists.
+ * @hooks - the hooks to add
+ * @count - the number of hooks to add
+ *
+ * Each LSM has to register its hooks with the infrastructure.
+ */
+void __init security_add_hooks(struct security_hook_list *hooks, int count,
+				char *lsm)
+{
+	int i;
+
+	for (i = 0; i < count; i++) {
+		hooks[i].lsm = lsm;
+		list_add_tail_rcu(&hooks[i].list, hooks[i].head);
+	}
+	if (lsm_append(lsm, &lsm_names) < 0)
+		panic("%s - Cannot get early memory.\n", __func__);
+}
+
 /*
  * Hook list operation macros.
  *
@@ -1123,14 +1161,134 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
-int security_getprocattr(struct task_struct *p, char *name, char **value)
+int security_getprocattr(struct task_struct *p, const char *lsm, char *name,
+				char **value)
 {
-	return call_int_hook(getprocattr, -EINVAL, p, name, value);
+	struct security_hook_list *hp;
+	char *vp;
+	char *cp = NULL;
+	int rc = -EINVAL;
+	int trc;
+
+	/*
+	 * "context" requires work here in addition to what
+	 * the modules provide.
+	 */
+	if (strcmp(name, "context") == 0) {
+		*value = NULL;
+		list_for_each_entry(hp,
+				&security_hook_heads.getprocattr, list) {
+			if (lsm != NULL && strcmp(lsm, hp->lsm))
+				continue;
+			trc = hp->hook.getprocattr(p, lsm, "context", &vp);
+			if (trc == -ENOENT)
+				continue;
+			if (trc <= 0) {
+				kfree(*value);
+				return trc;
+			}
+			rc = trc;
+			if (*value == NULL) {
+				*value = vp;
+			} else {
+				cp = kzalloc(strlen(*value) + strlen(vp) + 1,
+					GFP_KERNEL);
+				if (cp == NULL) {
+					kfree(*value);
+					kfree(vp);
+					return -ENOMEM;
+				}
+				sprintf(cp, "%s%s", *value, vp);
+				kfree(*value);
+				kfree(vp);
+				*value = cp;
+			}
+		}
+		if (rc > 0)
+			return strlen(*value);
+		return rc;
+	}
+
+	list_for_each_entry(hp, &security_hook_heads.getprocattr, list) {
+		if (lsm != NULL && strcmp(lsm, hp->lsm))
+			continue;
+		rc = hp->hook.getprocattr(p, lsm, name, value);
+		if (rc != -ENOENT)
+			return rc;
+	}
+	return -EINVAL;
 }
 
-int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+int security_setprocattr(struct task_struct *p, const char *lsm, char *name,
+				void *value, size_t size)
 {
-	return call_int_hook(setprocattr, -EINVAL, p, name, value, size);
+	struct security_hook_list *hp;
+	int rc = -EINVAL;
+	char *local;
+	char *cp;
+	int slen;
+	int failed = 0;
+
+	/*
+	 * "context" is handled directly here.
+	 */
+	if (strcmp(name, "context") == 0) {
+		/*
+		 * First verify that the input is acceptable.
+		 * lsm1='v1'lsm2='v2'lsm3='v3'
+		 *
+		 * A note on the use of strncmp() below.
+		 * The check is for the substring at the beginning of cp.
+		 */
+		local = kzalloc(size + 1, GFP_KERNEL);
+		memcpy(local, value, size);
+		cp = local;
+		list_for_each_entry(hp, &security_hook_heads.setprocattr,
+					list) {
+			if (lsm != NULL && strcmp(lsm, hp->lsm))
+				continue;
+			slen = strlen(hp->lsm);
+			if (strncmp(cp, hp->lsm, slen))
+				goto free_out;
+			cp += slen;
+			if (cp[0] != '=' || cp[1] != '\'' || cp[2] == '\'')
+				goto free_out;
+			for (cp += 2; cp[0] != '\''; cp++)
+				if (cp[0] == '\0')
+					goto free_out;
+			cp++;
+		}
+		cp = local;
+		list_for_each_entry(hp, &security_hook_heads.setprocattr,
+					list) {
+			if (lsm != NULL && strcmp(lsm, hp->lsm))
+				continue;
+			cp += strlen(hp->lsm) + 2;
+			for (slen = 0; cp[slen] != '\''; slen++)
+				;
+			cp[slen] = '\0';
+
+			rc = hp->hook.setprocattr(p, NULL, "context", cp, slen);
+			if (rc < 0)
+				failed = rc;
+			cp += slen + 1;
+		}
+		if (failed != 0)
+			rc = failed;
+		else
+			rc = size;
+free_out:
+		kfree(local);
+		return rc;
+	}
+	list_for_each_entry(hp, &security_hook_heads.setprocattr, list) {
+		if (lsm != NULL && strcmp(lsm, hp->lsm))
+			continue;
+		rc = hp->hook.setprocattr(p, lsm, name, value, size);
+		if (rc != -ENOENT)
+			break;
+	}
+	return rc;
 }
 
 int security_netlink_send(struct sock *sk, struct sk_buff *skb)
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index a86d537..bb5a809 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -5692,7 +5692,7 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 		inode_doinit_with_dentry(inode, dentry);
 }
 
-static int selinux_getprocattr(struct task_struct *p,
+static int selinux_getprocattr(struct task_struct *p, const char *lsm,
 			       char *name, char **value)
 {
 	const struct task_security_struct *__tsec;
@@ -5711,6 +5711,8 @@ static int selinux_getprocattr(struct task_struct *p,
 
 	if (!strcmp(name, "current"))
 		sid = __tsec->sid;
+	else if (!strcmp(name, "context"))
+		sid = __tsec->sid;
 	else if (!strcmp(name, "prev"))
 		sid = __tsec->osid;
 	else if (!strcmp(name, "exec"))
@@ -5728,7 +5730,21 @@ static int selinux_getprocattr(struct task_struct *p,
 	if (!sid)
 		return 0;
 
-	error = security_sid_to_context(sid, value, &len);
+	if (strcmp(name, "context")) {
+		error = security_sid_to_context(sid, value, &len);
+	} else {
+		char *vp;
+
+		error = security_sid_to_context(sid, &vp, &len);
+		if (!error) {
+			*value = kzalloc(len + 10, GFP_KERNEL);
+			if (*value == NULL)
+				error = -ENOMEM;
+			else
+				sprintf(*value, "selinux='%s'", vp);
+		}
+	}
+
 	if (error)
 		return error;
 	return len;
@@ -5738,7 +5754,7 @@ invalid:
 	return -EINVAL;
 }
 
-static int selinux_setprocattr(struct task_struct *p,
+static int selinux_setprocattr(struct task_struct *p, const char *lsm,
 			       char *name, void *value, size_t size)
 {
 	struct task_security_struct *tsec;
@@ -5768,6 +5784,8 @@ static int selinux_setprocattr(struct task_struct *p,
 		error = current_has_perm(p, PROCESS__SETSOCKCREATE);
 	else if (!strcmp(name, "current"))
 		error = current_has_perm(p, PROCESS__SETCURRENT);
+	else if (!strcmp(name, "context"))
+		error = current_has_perm(p, PROCESS__SETCURRENT);
 	else
 		error = -EINVAL;
 	if (error)
@@ -5827,7 +5845,7 @@ static int selinux_setprocattr(struct task_struct *p,
 		tsec->keycreate_sid = sid;
 	} else if (!strcmp(name, "sockcreate")) {
 		tsec->sockcreate_sid = sid;
-	} else if (!strcmp(name, "current")) {
+	} else if (!strcmp(name, "current") || !strcmp(name, "context")) {
 		error = -EINVAL;
 		if (sid == 0)
 			goto abort_change;
@@ -6233,7 +6251,7 @@ static __init int selinux_init(void)
 					    0, SLAB_PANIC, NULL);
 	avc_init();
 
-	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
+	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
 
 	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
 		panic("SELinux: Unable to register AVC netcache callback\n");
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 6777295..03a297b 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -3570,22 +3570,28 @@ unlockandout:
  *
  * Returns the length of the smack label or an error code
  */
-static int smack_getprocattr(struct task_struct *p, char *name, char **value)
+static int smack_getprocattr(struct task_struct *p, const char *lsm, char *name,
+				char **value)
 {
 	struct smack_known *skp = smk_of_task_struct(p);
 	char *cp;
 	int slen;
 
-	if (strcmp(name, "current") != 0)
+	if (strcmp(name, "current") == 0) {
+		cp = kstrdup(skp->smk_known, GFP_KERNEL);
+		if (cp == NULL)
+			return -ENOMEM;
+	} else if (strcmp(name, "context") == 0) {
+		slen = strlen(skp->smk_known) + 9;
+		cp = kzalloc(slen, GFP_KERNEL);
+		if (cp == NULL)
+			return -ENOMEM;
+		sprintf(cp, "smack='%s'", skp->smk_known);
+	} else
 		return -EINVAL;
 
-	cp = kstrdup(skp->smk_known, GFP_KERNEL);
-	if (cp == NULL)
-		return -ENOMEM;
-
-	slen = strlen(cp);
 	*value = cp;
-	return slen;
+	return strlen(cp);
 }
 
 /**
@@ -3600,7 +3606,7 @@ static int smack_getprocattr(struct task_struct *p, char *name, char **value)
  *
  * Returns the length of the smack label or an error code
  */
-static int smack_setprocattr(struct task_struct *p, char *name,
+static int smack_setprocattr(struct task_struct *p, const char *lsm, char *name,
 			     void *value, size_t size)
 {
 	struct task_smack *tsp = current_security();
@@ -3622,7 +3628,7 @@ static int smack_setprocattr(struct task_struct *p, char *name,
 	if (value == NULL || size == 0 || size >= SMK_LONGLABEL)
 		return -EINVAL;
 
-	if (strcmp(name, "current") != 0)
+	if (strcmp(name, "current") != 0 && strcmp(name, "context") != 0)
 		return -EINVAL;
 
 	skp = smk_import_entry(value, size);
@@ -4801,7 +4807,7 @@ static __init int smack_init(void)
 	/*
 	 * Register with LSM
 	 */
-	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks));
+	security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack");
 
 	return 0;
 }
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index 75c9987..edc52d6 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -542,7 +542,7 @@ static int __init tomoyo_init(void)
 	if (!security_module_enable("tomoyo"))
 		return 0;
 	/* register ourselves with the security framework */
-	security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks));
+	security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo");
 	printk(KERN_INFO "TOMOYO Linux initialized\n");
 	cred->security = &tomoyo_kernel_domain;
 	tomoyo_mm_init();
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c
index 0309f21..f8ee60e 100644
--- a/security/yama/yama_lsm.c
+++ b/security/yama/yama_lsm.c
@@ -471,6 +471,6 @@ static inline void yama_init_sysctl(void) { }
 void __init yama_add_hooks(void)
 {
 	pr_info("Yama: becoming mindful.\n");
-	security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks));
+	security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama");
 	yama_init_sysctl();
 }
