From 3664268f19ea07bec55df92fe53ff9ed28968bcc Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 2 Jun 2017 17:44:27 -0700 Subject: [PATCH] apparmor: add namespace lookup fns() Currently lookups are restricted to a single ns component in the path. However when namespaces are allowed to have separate views, and scopes this will not be sufficient, as it will be possible to have a multiple component ns path in scope. Add some ns lookup fns() to allow this and use them. Signed-off-by: John Johansen --- security/apparmor/include/policy_ns.h | 13 +++++++ security/apparmor/policy.c | 10 +++-- security/apparmor/policy_ns.c | 54 +++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 23e7cb770226..2f7e480a34e0 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -89,6 +89,8 @@ void aa_free_ns_kref(struct kref *kref); struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name); struct aa_ns *aa_findn_ns(struct aa_ns *root, const char *name, size_t n); +struct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n); +struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n); struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name, struct dentry *dir); struct aa_ns *aa_prepare_ns(struct aa_ns *root, const char *name); @@ -148,4 +150,15 @@ static inline struct aa_ns *__aa_find_ns(struct list_head *head, return __aa_findn_ns(head, name, strlen(name)); } +static inline struct aa_ns *__aa_lookup_ns(struct aa_ns *base, + const char *hname) +{ + return __aa_lookupn_ns(base, hname, strlen(hname)); +} + +static inline struct aa_ns *aa_lookup_ns(struct aa_ns *view, const char *name) +{ + return aa_lookupn_ns(view, name, strlen(name)); +} + #endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 0a99e5324da0..d95aae6bf710 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -566,7 +566,7 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len); if (ns_name) { - ns = aa_findn_ns(base->ns, ns_name, ns_len); + ns = aa_lookupn_ns(base->ns, ns_name, ns_len); if (!ns) return NULL; } else @@ -1108,7 +1108,7 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj, struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; - char *ns_name = NULL; + const char *ns_name = NULL; ssize_t error = 0; if (*fqname == 0) { @@ -1120,9 +1120,11 @@ ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj, root = view; if (fqname[0] == ':') { - name = aa_split_fqname(fqname, &ns_name); + size_t ns_len; + + name = aa_splitn_fqname(fqname, size, &ns_name, &ns_len); /* released below */ - ns = aa_find_ns(root, ns_name); + ns = aa_lookupn_ns(root, ns_name, ns_len); if (!ns) { info = "namespace does not exist"; error = -ENOENT; diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index f3418a9e59b1..c05316809a5e 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -183,6 +183,60 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) return aa_findn_ns(root, name, strlen(name)); } +/** + * __aa_lookupn_ns - lookup the namespace matching @hname + * @base: base list to start looking up profile name from (NOT NULL) + * @hname: hierarchical ns name (NOT NULL) + * @n: length of @hname + * + * Requires: rcu_read_lock be held + * + * Returns: unrefcounted ns pointer or NULL if not found + * + * Do a relative name lookup, recursing through profile tree. + */ +struct aa_ns *__aa_lookupn_ns(struct aa_ns *view, const char *hname, size_t n) +{ + struct aa_ns *ns = view; + const char *split; + + for (split = strnstr(hname, "//", n); split; + split = strnstr(hname, "//", n)) { + ns = __aa_findn_ns(&ns->sub_ns, hname, split - hname); + if (!ns) + return NULL; + + n -= split + 2 - hname; + hname = split + 2; + } + + if (n) + return __aa_findn_ns(&ns->sub_ns, hname, n); + return NULL; +} + +/** + * aa_lookupn_ns - look up a policy namespace relative to @view + * @view: namespace to search in (NOT NULL) + * @name: name of namespace to find (NOT NULL) + * @n: length of @name + * + * Returns: a refcounted namespace on the list, or NULL if no namespace + * called @name exists. + * + * refcount released by caller + */ +struct aa_ns *aa_lookupn_ns(struct aa_ns *view, const char *name, size_t n) +{ + struct aa_ns *ns = NULL; + + rcu_read_lock(); + ns = aa_get_ns(__aa_lookupn_ns(view, name, n)); + rcu_read_unlock(); + + return ns; +} + static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, struct dentry *dir) {