Subject: Re: linux-next: manual merge of the kunit-next tree with the apparmor tree

From: Stephen Rothwell <[email-masked]>
Date: Wed, 14 Dec 2022 11:00:05 +1100

Hi all,

On Thu, 8 Dec 2022 13:53:27 +1100 Stephen Rothwell <[email-masked]> wrote:
>
> Today's linux-next merge of the kunit-next tree got a conflict in:
> 
>   security/apparmor/policy_unpack.c
> 
> between commits:
> 
>   371e50a0b19f ("apparmor: make unpack_array return a trianary value")
>   73c7e91c8bc9 ("apparmor: Remove unnecessary size check when unpacking trans_table")
>   217af7e2f4de ("apparmor: refactor profile rules and attachments")
> (and probably others)
> 
> from the apparmor tree and commit:
> 
>   2c92044683f5 ("apparmor: test: make static symbols visible during kunit testing")
> 
> from the kunit-next tree.
> 
> This is somewhat of a mess ... pity there is not a shared branch (or
> better routing if the patches).
> 
> I fixed it up (hopefully - see below) and can carry the fix as
> necessary. This is now fixed as far as linux-next is concerned, but any
> non trivial conflicts should be mentioned to your upstream maintainer
> when your tree is submitted for merging.  You may also want to consider
> cooperating with the maintainer of the conflicting tree to minimise any
> particularly complex conflicts.
> 
> I also had to add this patch:
> 
> From: Stephen Rothwell <[email-masked]>
> Date: Thu, 8 Dec 2022 13:47:43 +1100
> Subject: [PATCH] fixup for "apparmor: make unpack_array return a trianary value"
> 
> Signed-off-by: Stephen Rothwell <[email-masked]>
> ---
>  security/apparmor/include/policy_unpack.h | 8 +++++++-
>  security/apparmor/policy_unpack.c         | 5 -----
>  2 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h
> index 940da8a33e0c..8fdf8f703bd0 100644
> --- a/security/apparmor/include/policy_unpack.h
> +++ b/security/apparmor/include/policy_unpack.h
> @@ -172,7 +172,13 @@ bool aa_unpack_X(struct aa_ext *e, enum aa_code code);
>  bool aa_unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name);
>  bool aa_unpack_u32(struct aa_ext *e, u32 *data, const char *name);
>  bool aa_unpack_u64(struct aa_ext *e, u64 *data, const char *name);
> -size_t aa_unpack_array(struct aa_ext *e, const char *name);
> +
> +#define tri int
> +#define TRI_TRUE 1
> +#define TRI_NONE 0
> +#define TRI_FALSE -1
> +
> +tri aa_unpack_array(struct aa_ext *e, const char *name, u16 *size);
>  size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name);
>  int aa_unpack_str(struct aa_ext *e, const char **string, const char *name);
>  int aa_unpack_strdup(struct aa_ext *e, char **string, const char *name);
> diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c
> index 6513545dad5e..173d832fc4ee 100644
> --- a/security/apparmor/policy_unpack.c
> +++ b/security/apparmor/policy_unpack.c
> @@ -30,11 +30,6 @@
>  #include "include/policy_unpack.h"
>  #include "include/policy_compat.h"
>  
> -#define tri int
> -#define TRI_TRUE 1
> -#define TRI_NONE 0
> -#define TRI_FALSE -1
> -
>  /* audit callback for unpack fields */
>  static void audit_cb(struct audit_buffer *ab, void *va)
>  {
> -- 
> 2.35.1
> 
> -- 
> Cheers,
> Stephen Rothwell
> 
> diff --cc security/apparmor/policy_unpack.c
> index 1bf8cfb8700a,12e535fdfa8b..000000000000
> --- a/security/apparmor/policy_unpack.c
> +++ b/security/apparmor/policy_unpack.c
> @@@ -14,9 -14,10 +14,10 @@@
>    */
>   
>   #include <asm/unaligned.h>
> + #include <kunit/visibility.h>
>   #include <linux/ctype.h>
>   #include <linux/errno.h>
>  -#include <linux/zlib.h>
>  +#include <linux/zstd.h>
>   
>   #include "include/apparmor.h"
>   #include "include/audit.h"
> @@@ -27,50 -27,16 +28,12 @@@
>   #include "include/path.h"
>   #include "include/policy.h"
>   #include "include/policy_unpack.h"
>  +#include "include/policy_compat.h"
>   
> - 
> - /*
> -  * The AppArmor interface treats data as a type byte followed by the
> -  * actual data.  The interface has the notion of a named entry
> -  * which has a name (AA_NAME typecode followed by name string) followed by
> -  * the entries typecode and data.  Named types allow for optional
> -  * elements and extensions to be added and tested for without breaking
> -  * backwards compatibility.
> -  */
> - 
> - enum aa_code {
> - 	AA_U8,
> - 	AA_U16,
> - 	AA_U32,
> - 	AA_U64,
> - 	AA_NAME,		/* same as string except it is items name */
> - 	AA_STRING,
> - 	AA_BLOB,
> - 	AA_STRUCT,
> - 	AA_STRUCTEND,
> - 	AA_LIST,
> - 	AA_LISTEND,
> - 	AA_ARRAY,
> - 	AA_ARRAYEND,
> - };
> - 
> - /*
> -  * aa_ext is the read of the buffer containing the serialized profile.  The
> -  * data is copied into a kernel buffer in apparmorfs and then handed off to
> -  * the unpack routines.
> -  */
> - struct aa_ext {
> - 	void *start;
> - 	void *end;
> - 	void *pos;		/* pointer to current position in the buffer */
> - 	u32 version;
> - };
>  -#define K_ABI_MASK 0x3ff
>  -#define FORCE_COMPLAIN_FLAG 0x800
>  -#define VERSION_LT(X, Y) (((X) & K_ABI_MASK) < ((Y) & K_ABI_MASK))
>  -#define VERSION_GT(X, Y) (((X) & K_ABI_MASK) > ((Y) & K_ABI_MASK))
> --
>  -#define v5	5	/* base version */
>  -#define v6	6	/* per entry policydb mediation check */
>  -#define v7	7
>  -#define v8	8	/* full network masking */
>  +#define tri int
>  +#define TRI_TRUE 1
>  +#define TRI_NONE 0
>  +#define TRI_FALSE -1
>   
>   /* audit callback for unpack fields */
>   static void audit_cb(struct audit_buffer *ab, void *va)
> @@@ -348,26 -319,28 +316,28 @@@ fail
>   	e->pos = pos;
>   	return false;
>   }
> + EXPORT_SYMBOL_IF_KUNIT(aa_unpack_u64);
>   
> - static tri unpack_array(struct aa_ext *e, const char *name, u16 *size)
>  -VISIBLE_IF_KUNIT size_t aa_unpack_array(struct aa_ext *e, const char *name)
> ++VISIBLE_IF_KUNIT tri aa_unpack_array(struct aa_ext *e, const char *name, u16 *size)
>   {
>   	void *pos = e->pos;
>   
> - 	if (unpack_nameX(e, AA_ARRAY, name)) {
> - 		if (!inbounds(e, sizeof(u16)))
> + 	if (aa_unpack_nameX(e, AA_ARRAY, name)) {
>  -		int size;
> + 		if (!aa_inbounds(e, sizeof(u16)))
>   			goto fail;
>  -		size = (int)le16_to_cpu(get_unaligned((__le16 *) e->pos));
>  +		*size = le16_to_cpu(get_unaligned((__le16 *) e->pos));
>   		e->pos += sizeof(u16);
>  -		return size;
>  +		return TRI_TRUE;
>   	}
>   
>  +	return TRI_NONE;
>   fail:
>   	e->pos = pos;
>  -	return 0;
>  +	return TRI_FALSE;
>   }
> + EXPORT_SYMBOL_IF_KUNIT(aa_unpack_array);
>   
> - static size_t unpack_blob(struct aa_ext *e, char **blob, const char *name)
> + VISIBLE_IF_KUNIT size_t aa_unpack_blob(struct aa_ext *e, char **blob, const char *name)
>   {
>   	void *pos = e->pos;
>   
> @@@ -470,36 -447,32 +443,36 @@@ static struct aa_dfa *unpack_dfa(struc
>   /**
>    * unpack_trans_table - unpack a profile transition table
>    * @e: serialized data extent information  (NOT NULL)
>  - * @profile: profile to add the accept table to (NOT NULL)
>  + * @table: str table to unpack to (NOT NULL)
>    *
>  - * Returns: true if table successfully unpacked
>  + * Returns: true if table successfully unpacked or not present
>    */
>  -static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile)
>  +static bool unpack_trans_table(struct aa_ext *e, struct aa_str_table *strs)
>   {
>   	void *saved_pos = e->pos;
>  +	char **table = NULL;
>   
>   	/* exec table is optional */
> - 	if (unpack_nameX(e, AA_STRUCT, "xtable")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "xtable")) {
>  -		int i, size;
>  -
>  -		size = aa_unpack_array(e, NULL);
>  -		/* currently 4 exec bits and entries 0-3 are reserved iupcx */
>  -		if (size > 16 - 4)
>  +		u16 size;
>  +		int i;
>  +
> - 		if (unpack_array(e, NULL, &size) != TRI_TRUE)
> ++		if (aa_unpack_array(e, NULL, &size) != TRI_TRUE)
>  +			/*
>  +			 * Note: index into trans table array is a max
>  +			 * of 2^24, but unpack array can only unpack
>  +			 * an array of 2^16 in size atm so no need
>  +			 * for size check here
>  +			 */
>   			goto fail;
>  -		profile->file.trans.table = kcalloc(size, sizeof(char *),
>  -						    GFP_KERNEL);
>  -		if (!profile->file.trans.table)
>  +		table = kcalloc(size, sizeof(char *), GFP_KERNEL);
>  +		if (!table)
>   			goto fail;
>   
>  -		profile->file.trans.size = size;
>   		for (i = 0; i < size; i++) {
>   			char *str;
> - 			int c, j, pos, size2 = unpack_strdup(e, &str, NULL);
> - 			/* unpack_strdup verifies that the last character is
> + 			int c, j, pos, size2 = aa_unpack_strdup(e, &str, NULL);
> + 			/* aa_unpack_strdup verifies that the last character is
>   			 * null termination byte.
>   			 */
>   			if (!size2)
> @@@ -534,13 -507,10 +507,13 @@@
>   				/* fail - all other cases with embedded \0 */
>   				goto fail;
>   		}
> - 		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>  +
>  +		strs->table = table;
>  +		strs->size = size;
>   	}
>   	return true;
>   
> @@@ -554,23 -524,21 +527,23 @@@ static bool unpack_xattrs(struct aa_ex
>   {
>   	void *pos = e->pos;
>   
> - 	if (unpack_nameX(e, AA_STRUCT, "xattrs")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "xattrs")) {
>  -		int i, size;
>  +		u16 size;
>  +		int i;
>   
> - 		if (unpack_array(e, NULL, &size) != TRI_TRUE)
>  -		size = aa_unpack_array(e, NULL);
>  -		profile->xattr_count = size;
>  -		profile->xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
>  -		if (!profile->xattrs)
> ++		if (aa_unpack_array(e, NULL, &size) != TRI_TRUE)
>  +			goto fail;
>  +		profile->attach.xattr_count = size;
>  +		profile->attach.xattrs = kcalloc(size, sizeof(char *), GFP_KERNEL);
>  +		if (!profile->attach.xattrs)
>   			goto fail;
>   		for (i = 0; i < size; i++) {
> - 			if (!unpack_strdup(e, &profile->attach.xattrs[i], NULL))
>  -			if (!aa_unpack_strdup(e, &profile->xattrs[i], NULL))
> ++			if (!aa_unpack_strdup(e, &profile->attach.xattrs[i], NULL))
>   				goto fail;
>   		}
> - 		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>   	}
>   
> @@@ -581,34 -549,32 +554,34 @@@ fail
>   	return false;
>   }
>   
>  -static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile)
>  +static bool unpack_secmark(struct aa_ext *e, struct aa_ruleset *rules)
>   {
>   	void *pos = e->pos;
>  -	int i, size;
>  +	u16 size;
>  +	int i;
>   
> - 	if (unpack_nameX(e, AA_STRUCT, "secmark")) {
> - 		if (unpack_array(e, NULL, &size) != TRI_TRUE)
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "secmark")) {
>  -		size = aa_unpack_array(e, NULL);
> ++		if (aa_unpack_array(e, NULL, &size) != TRI_TRUE)
>  +			goto fail;
>   
>  -		profile->secmark = kcalloc(size, sizeof(struct aa_secmark),
>  +		rules->secmark = kcalloc(size, sizeof(struct aa_secmark),
>   					   GFP_KERNEL);
>  -		if (!profile->secmark)
>  +		if (!rules->secmark)
>   			goto fail;
>   
>  -		profile->secmark_count = size;
>  +		rules->secmark_count = size;
>   
>   		for (i = 0; i < size; i++) {
>  -			if (!unpack_u8(e, &profile->secmark[i].audit, NULL))
>  +			if (!unpack_u8(e, &rules->secmark[i].audit, NULL))
>   				goto fail;
>  -			if (!unpack_u8(e, &profile->secmark[i].deny, NULL))
>  +			if (!unpack_u8(e, &rules->secmark[i].deny, NULL))
>   				goto fail;
> - 			if (!unpack_strdup(e, &rules->secmark[i].label, NULL))
>  -			if (!aa_unpack_strdup(e, &profile->secmark[i].label, NULL))
> ++			if (!aa_unpack_strdup(e, &rules->secmark[i].label, NULL))
>   				goto fail;
>   		}
> - 		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>   	}
>   
> @@@ -632,27 -598,26 +605,27 @@@ static bool unpack_rlimits(struct aa_ex
>   	void *pos = e->pos;
>   
>   	/* rlimits are optional */
> - 	if (unpack_nameX(e, AA_STRUCT, "rlimits")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "rlimits")) {
>  -		int i, size;
>  +		u16 size;
>  +		int i;
>   		u32 tmp = 0;
> - 		if (!unpack_u32(e, &tmp, NULL))
> + 		if (!aa_unpack_u32(e, &tmp, NULL))
>   			goto fail;
>  -		profile->rlimits.mask = tmp;
>  +		rules->rlimits.mask = tmp;
>   
> - 		if (unpack_array(e, NULL, &size) != TRI_TRUE ||
>  -		size = aa_unpack_array(e, NULL);
>  -		if (size > RLIM_NLIMITS)
> ++		if (aa_unpack_array(e, NULL, &size) != TRI_TRUE ||
>  +		    size > RLIM_NLIMITS)
>   			goto fail;
>   		for (i = 0; i < size; i++) {
>   			u64 tmp2 = 0;
>   			int a = aa_map_resource(i);
> - 			if (!unpack_u64(e, &tmp2, NULL))
> + 			if (!aa_unpack_u64(e, &tmp2, NULL))
>   				goto fail;
>  -			profile->rlimits.limits[a].rlim_max = tmp2;
>  +			rules->rlimits.limits[a].rlim_max = tmp2;
>   		}
> - 		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>   	}
>   	return true;
> @@@ -662,144 -627,6 +635,144 @@@ fail
>   	return false;
>   }
>   
>  +static bool unpack_perm(struct aa_ext *e, u32 version, struct aa_perms *perm)
>  +{
>  +	bool res;
>  +
>  +	if (version != 1)
>  +		return false;
>  +
> - 	res = unpack_u32(e, &perm->allow, NULL);
> - 	res = res && unpack_u32(e, &perm->allow, NULL);
> - 	res = res && unpack_u32(e, &perm->deny, NULL);
> - 	res = res && unpack_u32(e, &perm->subtree, NULL);
> - 	res = res && unpack_u32(e, &perm->cond, NULL);
> - 	res = res && unpack_u32(e, &perm->kill, NULL);
> - 	res = res && unpack_u32(e, &perm->complain, NULL);
> - 	res = res && unpack_u32(e, &perm->prompt, NULL);
> - 	res = res && unpack_u32(e, &perm->audit, NULL);
> - 	res = res && unpack_u32(e, &perm->quiet, NULL);
> - 	res = res && unpack_u32(e, &perm->hide, NULL);
> - 	res = res && unpack_u32(e, &perm->xindex, NULL);
> - 	res = res && unpack_u32(e, &perm->tag, NULL);
> - 	res = res && unpack_u32(e, &perm->label, NULL);
> ++	res = aa_unpack_u32(e, &perm->allow, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->allow, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->deny, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->subtree, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->cond, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->kill, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->complain, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->prompt, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->audit, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->quiet, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->hide, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->xindex, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->tag, NULL);
> ++	res = res && aa_unpack_u32(e, &perm->label, NULL);
>  +
>  +	return res;
>  +}
>  +
>  +static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
>  +{
>  +	void *pos = e->pos;
>  +	u16 size = 0;
>  +
>  +	AA_BUG(!perms);
>  +	/*
>  +	 * policy perms are optional, in which case perms are embedded
>  +	 * in the dfa accept table
>  +	 */
> - 	if (unpack_nameX(e, AA_STRUCT, "perms")) {
> ++	if (aa_unpack_nameX(e, AA_STRUCT, "perms")) {
>  +		int i;
>  +		u32 version;
>  +
> - 		if (!unpack_u32(e, &version, "version"))
> ++		if (!aa_unpack_u32(e, &version, "version"))
>  +			goto fail_reset;
> - 		if (unpack_array(e, NULL, &size) != TRI_TRUE)
> ++		if (aa_unpack_array(e, NULL, &size) != TRI_TRUE)
>  +			goto fail_reset;
>  +		*perms = kcalloc(size, sizeof(struct aa_perms), GFP_KERNEL);
>  +		if (!*perms)
>  +			goto fail_reset;
>  +		for (i = 0; i < size; i++) {
>  +			if (!unpack_perm(e, version, &(*perms)[i]))
>  +				goto fail;
>  +		}
> - 		if (!unpack_nameX(e, AA_ARRAYEND, NULL))
> ++		if (!aa_unpack_nameX(e, AA_ARRAYEND, NULL))
>  +			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> ++		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>  +			goto fail;
>  +	} else
>  +		*perms = NULL;
>  +
>  +	return size;
>  +
>  +fail:
>  +	kfree(*perms);
>  +fail_reset:
>  +	e->pos = pos;
>  +	return -EPROTO;
>  +}
>  +
>  +static int unpack_pdb(struct aa_ext *e, struct aa_policydb *policy,
>  +		      bool required_dfa, bool required_trans,
>  +		      const char **info)
>  +{
>  +	void *pos = e->pos;
>  +	int i, flags, error = -EPROTO;
>  +	ssize_t size;
>  +
>  +	size = unpack_perms_table(e, &policy->perms);
>  +	if (size < 0) {
>  +		error = size;
>  +		policy->perms = NULL;
>  +		*info = "failed to unpack - perms";
>  +		goto fail;
>  +	}
>  +	policy->size = size;
>  +
>  +	if (policy->perms) {
>  +		/* perms table present accept is index */
>  +		flags = TO_ACCEPT1_FLAG(YYTD_DATA32);
>  +	} else {
>  +		/* packed perms in accept1 and accept2 */
>  +		flags = TO_ACCEPT1_FLAG(YYTD_DATA32) |
>  +			TO_ACCEPT2_FLAG(YYTD_DATA32);
>  +	}
>  +
>  +	policy->dfa = unpack_dfa(e, flags);
>  +	if (IS_ERR(policy->dfa)) {
>  +		error = PTR_ERR(policy->dfa);
>  +		policy->dfa = NULL;
>  +		*info = "failed to unpack - dfa";
>  +		goto fail;
>  +	} else if (!policy->dfa) {
>  +		if (required_dfa) {
>  +			*info = "missing required dfa";
>  +			goto fail;
>  +		}
>  +		goto out;
>  +	}
>  +
>  +	/*
>  +	 * only unpack the following if a dfa is present
>  +	 *
>  +	 * sadly start was given different names for file and policydb
>  +	 * but since it is optional we can try both
>  +	 */
> - 	if (!unpack_u32(e, &policy->start[0], "start"))
> ++	if (!aa_unpack_u32(e, &policy->start[0], "start"))
>  +		/* default start state */
>  +		policy->start[0] = DFA_START;
> - 	if (!unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
> ++	if (!aa_unpack_u32(e, &policy->start[AA_CLASS_FILE], "dfa_start")) {
>  +		/* default start state for xmatch and file dfa */
>  +		policy->start[AA_CLASS_FILE] = DFA_START;
>  +	}	/* setup class index */
>  +	for (i = AA_CLASS_FILE + 1; i <= AA_CLASS_LAST; i++) {
>  +		policy->start[i] = aa_dfa_next(policy->dfa, policy->start[0],
>  +					       i);
>  +	}
>  +	if (!unpack_trans_table(e, &policy->trans) && required_trans) {
>  +		*info = "failed to unpack profile transition table";
>  +		goto fail;
>  +	}
>  +
>  +	/* TODO: move compat mapping here, requires dfa merging first */
>  +	/* TODO: move verify here, it has to be done after compat mappings */
>  +out:
>  +	return 0;
>  +
>  +fail:
>  +	e->pos = pos;
>  +	return error;
>  +}
>  +
>   static u32 strhash(const void *data, u32 len, u32 seed)
>   {
>   	const char * const *key = data;
> @@@ -858,29 -683,26 +831,29 @@@ static struct aa_profile *unpack_profil
>   	}
>   
>   	profile = aa_alloc_profile(name, NULL, GFP_KERNEL);
>  -	if (!profile)
>  -		return ERR_PTR(-ENOMEM);
>  +	if (!profile) {
>  +		info = "out of memory";
>  +		error = -ENOMEM;
>  +		goto fail;
>  +	}
>  +	rules = list_first_entry(&profile->rules, typeof(*rules), list);
>   
>   	/* profile renaming is optional */
> - 	(void) unpack_str(e, &profile->rename, "rename");
> + 	(void) aa_unpack_str(e, &profile->rename, "rename");
>   
>   	/* attachment string is optional */
> - 	(void) unpack_str(e, &profile->attach.xmatch_str, "attach");
>  -	(void) aa_unpack_str(e, &profile->attach, "attach");
> ++	(void) aa_unpack_str(e, &profile->attach.xmatch_str, "attach");
>   
>   	/* xmatch is optional and may be NULL */
>  -	profile->xmatch = unpack_dfa(e);
>  -	if (IS_ERR(profile->xmatch)) {
>  -		error = PTR_ERR(profile->xmatch);
>  -		profile->xmatch = NULL;
>  +	error = unpack_pdb(e, &profile->attach.xmatch, false, false, &info);
>  +	if (error) {
>   		info = "bad xmatch";
>   		goto fail;
>   	}
>  -	/* xmatch_len is not optional if xmatch is set */
>  -	if (profile->xmatch) {
>  +
>  +	/* neither xmatch_len not xmatch_perms are optional if xmatch is set */
>  +	if (profile->attach.xmatch.dfa) {
> - 		if (!unpack_u32(e, &tmp, NULL)) {
> + 		if (!aa_unpack_u32(e, &tmp, NULL)) {
>   			info = "missing xmatch len";
>   			goto fail;
>   		}
> @@@ -943,38 -757,38 +916,38 @@@
>   		profile->path_flags = PATH_MEDIATE_DELETED;
>   
>   	info = "failed to unpack profile capabilities";
> - 	if (!unpack_u32(e, &(rules->caps.allow.cap[0]), NULL))
>  -	if (!aa_unpack_u32(e, &(profile->caps.allow.cap[0]), NULL))
> ++	if (!aa_unpack_u32(e, &(rules->caps.allow.cap[0]), NULL))
>   		goto fail;
> - 	if (!unpack_u32(e, &(rules->caps.audit.cap[0]), NULL))
>  -	if (!aa_unpack_u32(e, &(profile->caps.audit.cap[0]), NULL))
> ++	if (!aa_unpack_u32(e, &(rules->caps.audit.cap[0]), NULL))
>   		goto fail;
> - 	if (!unpack_u32(e, &(rules->caps.quiet.cap[0]), NULL))
>  -	if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[0]), NULL))
> ++	if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[0]), NULL))
>   		goto fail;
> - 	if (!unpack_u32(e, &tmpcap.cap[0], NULL))
> + 	if (!aa_unpack_u32(e, &tmpcap.cap[0], NULL))
>   		goto fail;
>   
>   	info = "failed to unpack upper profile capabilities";
> - 	if (unpack_nameX(e, AA_STRUCT, "caps64")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "caps64")) {
>   		/* optional upper half of 64 bit caps */
> - 		if (!unpack_u32(e, &(rules->caps.allow.cap[1]), NULL))
>  -		if (!aa_unpack_u32(e, &(profile->caps.allow.cap[1]), NULL))
> ++		if (!aa_unpack_u32(e, &(rules->caps.allow.cap[1]), NULL))
>   			goto fail;
> - 		if (!unpack_u32(e, &(rules->caps.audit.cap[1]), NULL))
>  -		if (!aa_unpack_u32(e, &(profile->caps.audit.cap[1]), NULL))
> ++		if (!aa_unpack_u32(e, &(rules->caps.audit.cap[1]), NULL))
>   			goto fail;
> - 		if (!unpack_u32(e, &(rules->caps.quiet.cap[1]), NULL))
>  -		if (!aa_unpack_u32(e, &(profile->caps.quiet.cap[1]), NULL))
> ++		if (!aa_unpack_u32(e, &(rules->caps.quiet.cap[1]), NULL))
>   			goto fail;
> - 		if (!unpack_u32(e, &(tmpcap.cap[1]), NULL))
> + 		if (!aa_unpack_u32(e, &(tmpcap.cap[1]), NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>   	}
>   
>   	info = "failed to unpack extended profile capabilities";
> - 	if (unpack_nameX(e, AA_STRUCT, "capsx")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "capsx")) {
>   		/* optional extended caps mediation mask */
> - 		if (!unpack_u32(e, &(rules->caps.extended.cap[0]), NULL))
>  -		if (!aa_unpack_u32(e, &(profile->caps.extended.cap[0]), NULL))
> ++		if (!aa_unpack_u32(e, &(rules->caps.extended.cap[0]), NULL))
>   			goto fail;
> - 		if (!unpack_u32(e, &(rules->caps.extended.cap[1]), NULL))
>  -		if (!aa_unpack_u32(e, &(profile->caps.extended.cap[1]), NULL))
> ++		if (!aa_unpack_u32(e, &(rules->caps.extended.cap[1]), NULL))
>   			goto fail;
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>   	}
>   
> @@@ -993,55 -807,62 +966,55 @@@
>   		goto fail;
>   	}
>   
> - 	if (unpack_nameX(e, AA_STRUCT, "policydb")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "policydb")) {
>   		/* generic policy dfa - optional and may be NULL */
>   		info = "failed to unpack policydb";
>  -		profile->policy.dfa = unpack_dfa(e);
>  -		if (IS_ERR(profile->policy.dfa)) {
>  -			error = PTR_ERR(profile->policy.dfa);
>  -			profile->policy.dfa = NULL;
>  -			goto fail;
>  -		} else if (!profile->policy.dfa) {
>  -			error = -EPROTO;
>  +		error = unpack_pdb(e, &rules->policy, true, false,
>  +				   &info);
>  +		if (error)
>   			goto fail;
>  -		}
>  -		if (!aa_unpack_u32(e, &profile->policy.start[0], "start"))
>  -			/* default start state */
>  -			profile->policy.start[0] = DFA_START;
>  -		/* setup class index */
>  -		for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) {
>  -			profile->policy.start[i] =
>  -				aa_dfa_next(profile->policy.dfa,
>  -					    profile->policy.start[0],
>  -					    i);
>  -		}
>  +		/* Fixup: drop when we get rid of start array */
>  +		if (aa_dfa_next(rules->policy.dfa, rules->policy.start[0],
>  +				AA_CLASS_FILE))
>  +			rules->policy.start[AA_CLASS_FILE] =
>  +			  aa_dfa_next(rules->policy.dfa,
>  +				      rules->policy.start[0],
>  +				      AA_CLASS_FILE);
> - 		if (!unpack_nameX(e, AA_STRUCTEND, NULL))
> + 		if (!aa_unpack_nameX(e, AA_STRUCTEND, NULL))
>   			goto fail;
>  +		error = aa_compat_map_policy(&rules->policy, e->version);
>  +		if (error) {
>  +			info = "failed to remap policydb permission table";
>  +			goto fail;
>  +		}
>   	} else
>  -		profile->policy.dfa = aa_get_dfa(nulldfa);
>  +		rules->policy.dfa = aa_get_dfa(nulldfa);
>   
>   	/* get file rules */
>  -	profile->file.dfa = unpack_dfa(e);
>  -	if (IS_ERR(profile->file.dfa)) {
>  -		error = PTR_ERR(profile->file.dfa);
>  -		profile->file.dfa = NULL;
>  -		info = "failed to unpack profile file rules";
>  +	error = unpack_pdb(e, &rules->file, false, true, &info);
>  +	if (error) {
>   		goto fail;
>  -	} else if (profile->file.dfa) {
>  -		if (!aa_unpack_u32(e, &profile->file.start, "dfa_start"))
>  -			/* default start state */
>  -			profile->file.start = DFA_START;
>  -	} else if (profile->policy.dfa &&
>  -		   profile->policy.start[AA_CLASS_FILE]) {
>  -		profile->file.dfa = aa_get_dfa(profile->policy.dfa);
>  -		profile->file.start = profile->policy.start[AA_CLASS_FILE];
>  +	} else if (rules->file.dfa) {
>  +		error = aa_compat_map_file(&rules->file);
>  +		if (error) {
>  +			info = "failed to remap file permission table";
>  +			goto fail;
>  +		}
>  +	} else if (rules->policy.dfa &&
>  +		   rules->policy.start[AA_CLASS_FILE]) {
>  +		rules->file.dfa = aa_get_dfa(rules->policy.dfa);
>  +		rules->file.start[AA_CLASS_FILE] = rules->policy.start[AA_CLASS_FILE];
>   	} else
>  -		profile->file.dfa = aa_get_dfa(nulldfa);
>  -
>  -	if (!unpack_trans_table(e, profile)) {
>  -		info = "failed to unpack profile transition table";
>  -		goto fail;
>  -	}
>  +		rules->file.dfa = aa_get_dfa(nulldfa);
>   
>  +	error = -EPROTO;
> - 	if (unpack_nameX(e, AA_STRUCT, "data")) {
> + 	if (aa_unpack_nameX(e, AA_STRUCT, "data")) {
>   		info = "out of memory";
>   		profile->data = kzalloc(sizeof(*profile->data), GFP_KERNEL);
>  -		if (!profile->data)
>  +		if (!profile->data) {
>  +			error = -ENOMEM;
>   			goto fail;
>  -
>  +		}
>   		params.nelem_hint = 3;
>   		params.key_len = sizeof(void *);
>   		params.key_offset = offsetof(struct aa_data, key);

This is now a conflict between the apparmor tree and Linus' tree
(including the updated fix patch).

-- 
Cheers,
Stephen Rothwell