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

From: John Johansen <[email-masked]>
Date: Wed, 14 Dec 2022 10:38:35 -0800

On 12/13/22 16:00, Stephen Rothwell wrote:
> 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).
> 

sorry for the delay on this, build and regression testing took way
longer than they should have.

apparmor merge request is now sent