From bd5bc987e93221b83b7b416737eb4af35827ff58 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 31 Mar 2017 05:05:04 -0700 Subject: [PATCH] UBUNTU: SAUCE: apparmor: fix label parse for stacked labels Stacked labels with two ns profile components specified and the ns only specified on one of them are not being correctly parsed. That is P//&:ns://A//&unconfined is being parsed as if P and unconfined are in the same ns while A is in :ns: ie. it is being parsed as the equiv of P//&unconfined//&:ns://A The apparmor label spec requires that profiles are ordered by ns so :ns://A//&unconfined should be parsed as if it is P//&:ns://A//&:ns://unconfined Note: the above with a ns spec for each profile component is currently parsed correctly and the ns spec is always relative to the label view. BugLink: http://bugs.launchpad.net/bugs/1677959 Signed-off-by: John Johansen Signed-off-by: Tim Gardner --- security/apparmor/include/lib.h | 1 + security/apparmor/label.c | 29 ++++++++++++++++++++++++++--- security/apparmor/lib.c | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 954e22ae8342..f44561b6075b 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -59,6 +59,7 @@ extern int apparmor_initialized __initdata; /* fn's in lib */ +const char *skipn_spaces(const char *str, size_t n); char *aa_split_fqname(char *args, char **ns_name); const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, size_t *ns_len); diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 69a600b4c1a1..db0eaba829cb 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -1850,6 +1850,23 @@ static int label_count_str_entries(const char *str) return count; } +/* + * ensure stacks with components like + * :ns://A//&B + * have :ns: applied to both 'A' and 'B' by making the lookup relative + * to the base if the lookup specifies an ns, else making the stacked lookup + * relative to the last embedded ns in the string. + */ +static struct aa_profile *fqlookupn_profile(struct aa_label *base, + struct aa_label *currentbase, + const char *str, size_t n) +{ + const char *first = skipn_spaces(str, n); + if (first && *first == ':') + return aa_fqlookupn_profile(base, str, n); + return aa_fqlookupn_profile(currentbase, str, n); +} + /** * aa_label_parse - parse, validate and convert a text string to a label * @base: base label to use for lookups (NOT NULL) @@ -1865,7 +1882,7 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str, gfp_t gfp, bool create, bool force_stack) { DEFINE_VEC(profile, vec); - struct aa_label *label; + struct aa_label *label, *currbase = base; int i, len, stack = 0, error; char *split; @@ -1889,15 +1906,21 @@ struct aa_label *aa_label_parse(struct aa_label *base, const char *str, vec[i] = aa_get_profile(base->vec[i]); for (split = strstr(str, "//&"), i = stack; split && i < len; i++) { - vec[i] = aa_fqlookupn_profile(base, str, split - str); + vec[i] = fqlookupn_profile(base, currbase, str, split - str); if (!vec[i]) goto fail; + /* + * if component specified a new ns it becomes the new base + * so that subsequent lookups are relative to it + */ + if (vec[i]->ns != labels_ns(currbase)) + currbase = &vec[i]->label; str = split + 3; split = strstr(str, "//&"); } /* last element doesn't have a split so this should be the case but just to be safe */ if (i < len) { - vec[i] = aa_fqlookupn_profile(base, str, strlen(str)); + vec[i] = fqlookupn_profile(base, currbase, str, strlen(str)); if (!vec[i]) goto fail; } diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 52d4efcad237..783d49859bca 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -76,7 +76,7 @@ char *aa_split_fqname(char *fqname, char **ns_name) * if all whitespace will return NULL */ -static const char *skipn_spaces(const char *str, size_t n) +const char *skipn_spaces(const char *str, size_t n) { for (;n && isspace(*str); --n) ++str; -- 2.39.2