--- zzzz-none-000/linux-3.10.107/security/apparmor/policy_unpack.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/security/apparmor/policy_unpack.c 2021-02-04 17:41:59.000000000 +0000 @@ -24,10 +24,10 @@ #include "include/apparmor.h" #include "include/audit.h" #include "include/context.h" +#include "include/crypto.h" #include "include/match.h" #include "include/policy.h" #include "include/policy_unpack.h" -#include "include/sid.h" /* * The AppArmor interface treats data as a type byte followed by the @@ -290,6 +290,9 @@ return res; } +#define DFA_VALID_PERM_MASK 0xffffffff +#define DFA_VALID_PERM2_MASK 0xffffffff + /** * verify_accept - verify the accept tables of a dfa * @dfa: dfa to verify accept tables of (NOT NULL) @@ -331,8 +334,10 @@ /* * The dfa is aligned with in the blob to 8 bytes * from the beginning of the stream. + * alignment adjust needed by dfa unpack */ - size_t sz = blob - (char *)e->start; + size_t sz = blob - (char *) e->start - + ((e->pos - e->start) & 7); size_t pad = ALIGN(sz, 8) - sz; int flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | TO_ACCEPT2_FLAG(YYTD_DATA32); @@ -488,6 +493,9 @@ /* profile renaming is optional */ (void) unpack_str(e, &profile->rename, "rename"); + /* attachment string is optional */ + (void) unpack_str(e, &profile->attach, "attach"); + /* xmatch is optional and may be NULL */ profile->xmatch = unpack_dfa(e); if (IS_ERR(profile->xmatch)) { @@ -507,12 +515,16 @@ goto fail; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp) + if (tmp & PACKED_FLAG_HAT) profile->flags |= PFLAG_HAT; if (!unpack_u32(e, &tmp, NULL)) goto fail; - if (tmp) + if (tmp == PACKED_MODE_COMPLAIN) profile->mode = APPARMOR_COMPLAIN; + else if (tmp == PACKED_MODE_KILL) + profile->mode = APPARMOR_KILL; + else if (tmp == PACKED_MODE_UNCONFINED) + profile->mode = APPARMOR_UNCONFINED; if (!unpack_u32(e, &tmp, NULL)) goto fail; if (tmp) @@ -571,9 +583,6 @@ error = PTR_ERR(profile->policy.dfa); profile->policy.dfa = NULL; goto fail; - } else if (!profile->policy.dfa) { - error = -EPROTO; - goto fail; } if (!unpack_u32(e, &profile->policy.start[0], "start")) /* default start state */ @@ -615,7 +624,7 @@ else if (!name) name = "unknown"; audit_iface(profile, name, "failed to unpack profile", e, error); - aa_put_profile(profile); + aa_free_profile(profile); return ERR_PTR(error); } @@ -623,29 +632,41 @@ /** * verify_head - unpack serialized stream header * @e: serialized data read head (NOT NULL) + * @required: whether the header is required or optional * @ns: Returns - namespace if one is specified else NULL (NOT NULL) * * Returns: error or 0 if header is good */ -static int verify_header(struct aa_ext *e, const char **ns) +static int verify_header(struct aa_ext *e, int required, const char **ns) { int error = -EPROTONOSUPPORT; + const char *name = NULL; + *ns = NULL; + /* get the interface version */ if (!unpack_u32(e, &e->version, "version")) { - audit_iface(NULL, NULL, "invalid profile format", e, error); - return error; - } + if (required) { + audit_iface(NULL, NULL, "invalid profile format", e, + error); + return error; + } - /* check that the interface version is currently supported */ - if (e->version != 5) { - audit_iface(NULL, NULL, "unsupported interface version", e, - error); - return error; + /* check that the interface version is currently supported */ + if (e->version != 5) { + audit_iface(NULL, NULL, "unsupported interface version", + e, error); + return error; + } } + /* read the namespace if present */ - if (!unpack_str(e, ns, "namespace")) - *ns = NULL; + if (unpack_str(e, &name, "namespace")) { + if (*ns && strcmp(*ns, name)) + audit_iface(NULL, NULL, "invalid ns change", e, error); + else if (!*ns) + *ns = name; + } return 0; } @@ -655,7 +676,7 @@ int index, xtype; xtype = xindex & AA_X_TYPE_MASK; index = xindex & AA_X_INDEX_MASK; - if (xtype == AA_X_TABLE && index >= table_size) + if (xtype == AA_X_TABLE && index > table_size) return 0; return 1; } @@ -694,18 +715,40 @@ return 0; } +void aa_load_ent_free(struct aa_load_ent *ent) +{ + if (ent) { + aa_put_profile(ent->rename); + aa_put_profile(ent->old); + aa_put_profile(ent->new); + kzfree(ent); + } +} + +struct aa_load_ent *aa_load_ent_alloc(void) +{ + struct aa_load_ent *ent = kzalloc(sizeof(*ent), GFP_KERNEL); + if (ent) + INIT_LIST_HEAD(&ent->list); + return ent; +} + /** - * aa_unpack - unpack packed binary profile data loaded from user space + * aa_unpack - unpack packed binary profile(s) data loaded from user space * @udata: user data copied to kmem (NOT NULL) * @size: the size of the user data + * @lh: list to place unpacked profiles in a aa_repl_ws * @ns: Returns namespace profile is in if specified else NULL (NOT NULL) * - * Unpack user data and return refcounted allocated profile or ERR_PTR + * Unpack user data and return refcounted allocated profile(s) stored in + * @lh in order of discovery, with the list chain stored in base.list + * or error * - * Returns: profile else error pointer if fails to unpack + * Returns: profile(s) on @lh else error pointer if fails to unpack */ -struct aa_profile *aa_unpack(void *udata, size_t size, const char **ns) +int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) { + struct aa_load_ent *tmp, *ent; struct aa_profile *profile = NULL; int error; struct aa_ext e = { @@ -714,20 +757,49 @@ .pos = udata, }; - error = verify_header(&e, ns); - if (error) - return ERR_PTR(error); + *ns = NULL; + while (e.pos < e.end) { + void *start; + error = verify_header(&e, e.pos == e.start, ns); + if (error) + goto fail; + + start = e.pos; + profile = unpack_profile(&e); + if (IS_ERR(profile)) { + error = PTR_ERR(profile); + goto fail; + } + + error = verify_profile(profile); + if (error) + goto fail_profile; + + error = aa_calc_profile_hash(profile, e.version, start, + e.pos - start); + if (error) + goto fail_profile; + + ent = aa_load_ent_alloc(); + if (!ent) { + error = -ENOMEM; + goto fail_profile; + } + + ent->new = profile; + list_add_tail(&ent->list, lh); + } + + return 0; - profile = unpack_profile(&e); - if (IS_ERR(profile)) - return profile; +fail_profile: + aa_put_profile(profile); - error = verify_profile(profile); - if (error) { - aa_put_profile(profile); - profile = ERR_PTR(error); +fail: + list_for_each_entry_safe(ent, tmp, lh, list) { + list_del_init(&ent->list); + aa_load_ent_free(ent); } - /* return refcount */ - return profile; + return error; }