diff --git a/security/apparmor/file.c b/security/apparmor/file.c
index 7312db7..2692333 100644
--- a/security/apparmor/file.c
+++ b/security/apparmor/file.c
@@ -155,7 +155,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
  *
  * Returns: new permission mapping
  */
-static u32 map_old_perms(u32 old)
+u32 map_old_perms(u32 old)
 {
 	u32 new = old & 0xf;
 	if (old & MAY_READ)
diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h
index ab8c6d8..632fdfb 100644
--- a/security/apparmor/include/file.h
+++ b/security/apparmor/include/file.h
@@ -186,6 +186,8 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
 	aa_free_domain_entries(&rules->trans);
 }
 
+u32 map_old_perms(u32 old);
+
 #define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
 
 /* from namei.c */
diff --git a/security/apparmor/include/procattr.h b/security/apparmor/include/procattr.h
index 544aa6b..4221037 100644
--- a/security/apparmor/include/procattr.h
+++ b/security/apparmor/include/procattr.h
@@ -22,5 +22,6 @@ int aa_getprocattr(struct aa_profile *profile, char **string);
 int aa_setprocattr_changehat(char *args, size_t size, int test);
 int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
 int aa_setprocattr_permipc(char *fqname);
+int aa_setprocattr_perm(char *fqname, size_t size);
 
 #endif /* __AA_PROCATTR_H */
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
index 7459547..bca1667 100644
--- a/security/apparmor/lsm.c
+++ b/security/apparmor/lsm.c
@@ -559,10 +559,6 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 		args[size] = '\0';
 	}
 
-	/* task can only write its own attributes */
-	if (current != task)
-		return -EACCES;
-
 	args = value;
 	args = strim(args);
 	command = strsep(&args, " ");
@@ -575,12 +571,18 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 	arg_size = size - (args - (char *) value);
 	if (strcmp(name, "current") == 0) {
 		if (strcmp(command, "changehat") == 0) {
+			/* task can only write its own attributes */
+			if (current != task)
+				return -EACCES;
 			error = aa_setprocattr_changehat(args, arg_size,
 							 !AA_DO_TEST);
 		} else if (strcmp(command, "permhat") == 0) {
 			error = aa_setprocattr_changehat(args, arg_size,
 							 AA_DO_TEST);
 		} else if (strcmp(command, "changeprofile") == 0) {
+			/* task can only write its own attributes */
+			if (current != task)
+				return -EACCES;
 			error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
 							     !AA_DO_TEST);
 		} else if (strcmp(command, "permprofile") == 0) {
@@ -588,6 +590,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
 							     AA_DO_TEST);
 		} else if (strcmp(command, "permipc") == 0) {
 			error = aa_setprocattr_permipc(args);
+		} else if (strcmp(command, "perm") == 0) {
+			error = aa_setprocattr_perm(args, arg_size);
 		} else {
 			struct common_audit_data sa;
 			COMMON_AUDIT_DATA_INIT(&sa, NONE);
diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c
index 04a2cf8..222e56a 100644
--- a/security/apparmor/procattr.c
+++ b/security/apparmor/procattr.c
@@ -168,3 +168,37 @@ int aa_setprocattr_permipc(char *fqname)
 	/* TODO: add ipc permission querying */
 	return -ENOTSUPP;
 }
+
+/**
+ * aa_setprocattr_perm - generic perm test can be used to determine transition
+ * @args: args from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ */
+int aa_setprocattr_perm(char *args, size_t size)
+{
+	struct aa_profile *profile;
+	char *permstr, *val = args;
+	u32 mask, perms;
+	unsigned int state;
+
+	if (!args)
+		return -EINVAL;
+	permstr = strsep(&val, " ");
+	if (!val)
+		return -EINVAL;
+	mask = simple_strtoul(permstr, NULL, 0);
+	size -= val - args;
+
+	profile = aa_current_profile();
+	if (profile->policy) {
+		state = aa_dfa_match_len(profile->policy, profile->policy_start,
+					 args, size);
+		perms = map_old_perms(dfa_user_allow(profile->policy, state));
+	} else
+		perms = 0;
+
+	if (mask & ~perms)
+		return -EACCES;
+
+	return 0;
+}
