diff --git a/fs/proc/base.c b/fs/proc/base.c
index b25eee4..9ec88b8 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2327,20 +2327,77 @@ out:
 }
 
 #ifdef CONFIG_SECURITY
+static int proc_pid_attr_open(struct inode *inode, struct file *file)
+{
+	const char *name = file->f_path.dentry->d_name.name;
+	const struct seq_operations *ops;
+	struct task_struct *task;
+	struct seq_file *seq;
+	int ret;
+
+	file->private_data = NULL;
+
+	task = get_proc_task(inode);
+	if (!task)
+		return -ESRCH;
+
+	/* don't use seq_ops if they are not provided by LSM */
+	ret = security_getprocattr_seq(task, name, &ops);
+	if (ret == -EOPNOTSUPP) {
+		ret = 0;
+		goto put_task;
+	}
+	if (ret)
+		goto put_task;
+
+	ret = seq_open(file, ops);
+	if (ret)
+		goto put_task;
+
+	seq = file->private_data;
+	seq->private = task;
+
+	return 0;
+
+put_task:
+	put_task_struct(task);
+	return ret;
+}
+
+static int proc_pid_attr_release(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	struct task_struct *task;
+
+	/* don't use seq_ops if they were not provided by LSM */
+	if (file->private_data == NULL)
+		return 0;
+
+	seq = file->private_data;
+	task = seq->private;
+	put_task_struct(task);
+
+	return seq_release(inode, file);
+}
+
 static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
 				  size_t count, loff_t *ppos)
 {
-	struct inode * inode = file_inode(file);
+	struct inode *inode = file_inode(file);
+	const char *name = file->f_path.dentry->d_name.name;
 	char *p = NULL;
 	ssize_t length;
-	struct task_struct *task = get_proc_task(inode);
+	struct task_struct *task;
 
+	/* use seq_ops if they were provided by LSM */
+	if (file->private_data)
+		return seq_read(file, buf, count, ppos);
+
+	task = get_proc_task(inode);
 	if (!task)
 		return -ESRCH;
 
-	length = security_getprocattr(task,
-				      (char*)file->f_path.dentry->d_name.name,
-				      &p);
+	length = security_getprocattr(task, (char *)name, &p);
 	put_task_struct(task);
 	if (length > 0)
 		length = simple_read_from_buffer(buf, count, ppos, p, length);
@@ -2348,6 +2405,15 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
 	return length;
 }
 
+static loff_t proc_pid_attr_lseek(struct file *file, loff_t offset, int whence)
+{
+	/* use seq_ops if they were provided by LSM */
+	if (file->private_data)
+		return seq_lseek(file, offset, whence);
+
+	return generic_file_llseek(file, offset, whence);
+}
+
 static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
 				   size_t count, loff_t *ppos)
 {
@@ -2394,9 +2460,11 @@ out_no_task:
 }
 
 static const struct file_operations proc_pid_attr_operations = {
+	.open		= proc_pid_attr_open,
+	.release	= proc_pid_attr_release,
 	.read		= proc_pid_attr_read,
+	.llseek		= proc_pid_attr_lseek,
 	.write		= proc_pid_attr_write,
-	.llseek		= generic_file_llseek,
 };
 
 static const struct pid_entry attr_dir_stuff[] = {
@@ -2406,6 +2474,7 @@ static const struct pid_entry attr_dir_stuff[] = {
 	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),
+	REG("label_map",  S_IRUGO|S_IWUGO, proc_pid_attr_operations),
 };
 
 static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
index 18c9160..7049db0 100644
--- a/include/linux/lsm_hooks.h
+++ b/include/linux/lsm_hooks.h
@@ -1208,6 +1208,18 @@
  *	@name full extended attribute name to check against
  *	LSM as a MAC label.
  *
+ * @getprocattr_seq:
+ *	An alternative to the getprocattr, that makes it possible for an attr
+ *	file to be handled by seq operations. If this function returns valid
+ *	@ops for a specific @name, those operations will be used and
+ *	getprocattr will not be called.
+ *	A proper task for the file is then passed in seq_file->private.
+ *	@p a task associated with the proc file.
+ *	@name name of the attr file under /proc/$PID/attr/ to be handled.
+ *	@ops (out) seq_operations to be used for @name.
+ *	Return 0 if @name is to be handled by seq, EOPNOTSUPP if getprocattr()
+ *	should be used. Other errors will be passed to user-space.
+ *
  * @secid_to_secctx:
  *	Convert secid to security context.  If secdata is NULL the length of
  *	the result will be returned in seclen, but no secdata will be returned.
@@ -1525,6 +1537,8 @@ union security_list_options {
 
 	void (*d_instantiate)(struct dentry *dentry, struct inode *inode);
 
+	int (*getprocattr_seq)(struct task_struct *p, const char *name,
+			       const struct seq_operations **ops);
 	int (*getprocattr)(struct task_struct *p, char *name, char **value);
 	int (*setprocattr)(struct task_struct *p, char *name, void *value,
 				size_t size);
@@ -1774,6 +1788,7 @@ struct security_hook_heads {
 	struct list_head sem_semop;
 	struct list_head netlink_send;
 	struct list_head d_instantiate;
+	struct list_head getprocattr_seq;
 	struct list_head getprocattr;
 	struct list_head setprocattr;
 	struct list_head ismaclabel;
diff --git a/include/linux/security.h b/include/linux/security.h
index 91ffba2..dddea2f 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -345,6 +345,8 @@ 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_seq(struct task_struct *p, const char *name,
+			     const struct seq_operations **ops);
 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_netlink_send(struct sock *sk, struct sk_buff *skb);
@@ -1057,6 +1059,13 @@ static inline int security_sem_semop(struct sem_array *sma,
 static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 { }
 
+static inline int security_getprocattr_seq(struct task_struct *p,
+					   const char *name,
+					   const struct seq_operations **ops)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int security_getprocattr(struct task_struct *p, char *name, char **value)
 {
 	return -EINVAL;
diff --git a/security/security.c b/security/security.c
index e571127..da2bcd4 100644
--- a/security/security.c
+++ b/security/security.c
@@ -1121,6 +1121,12 @@ void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 }
 EXPORT_SYMBOL(security_d_instantiate);
 
+int security_getprocattr_seq(struct task_struct *p, const char *name,
+			     const struct seq_operations **ops)
+{
+	return call_int_hook(getprocattr_seq, -EOPNOTSUPP, p, name, ops);
+}
+
 int security_getprocattr(struct task_struct *p, char *name, char **value)
 {
 	return call_int_hook(getprocattr, -EINVAL, p, name, value);
@@ -1774,6 +1780,8 @@ struct security_hook_heads security_hook_heads = {
 	.netlink_send =	LIST_HEAD_INIT(security_hook_heads.netlink_send),
 	.d_instantiate =
 		LIST_HEAD_INIT(security_hook_heads.d_instantiate),
+	.getprocattr_seq =
+		LIST_HEAD_INIT(security_hook_heads.getprocattr_seq),
 	.getprocattr =	LIST_HEAD_INIT(security_hook_heads.getprocattr),
 	.setprocattr =	LIST_HEAD_INIT(security_hook_heads.setprocattr),
 	.ismaclabel =	LIST_HEAD_INIT(security_hook_heads.ismaclabel),
