From 12557dcba21b015f470076da6947e68bc70fff64 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:13 -0800 Subject: apparmor: move lib definitions into separate lib include Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 1 + 1 file changed, 1 insertion(+) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 52275f040a5f..190fe37ecff0 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -27,6 +27,7 @@ #include "capability.h" #include "domain.h" #include "file.h" +#include "lib.h" #include "resource.h" extern const char *const aa_profile_mode_names[]; -- cgit v1.2.3 From fe6bb31f590c9cd9c8d3ddbdfd4301f72db91718 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:14 -0800 Subject: apparmor: split out shared policy_XXX fns to lib Signed-off-by: John Johansen --- security/apparmor/include/lib.h | 81 ++++++++++++++++++++++++ security/apparmor/include/policy.h | 13 ---- security/apparmor/lib.c | 52 ++++++++++++++++ security/apparmor/policy.c | 123 ++----------------------------------- 4 files changed, 137 insertions(+), 132 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 71fd6d28a651..74cc68ea4c12 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h @@ -91,4 +91,85 @@ static inline bool mediated_filesystem(struct dentry *dentry) return !(dentry->d_sb->s_flags & MS_NOUSER); } +/* struct aa_policy - common part of both namespaces and profiles + * @name: name of the object + * @hname - The hierarchical name + * @list: list policy object is on + * @profiles: head of the profiles list contained in the object + */ +struct aa_policy { + char *name; + char *hname; + struct list_head list; + struct list_head profiles; +}; + +/** + * hname_tail - find the last component of an hname + * @name: hname to find the base profile name component of (NOT NULL) + * + * Returns: the tail (base profile name) name component of an hname + */ +static inline const char *hname_tail(const char *hname) +{ + char *split; + + hname = strim((char *)hname); + for (split = strstr(hname, "//"); split; split = strstr(hname, "//")) + hname = split + 2; + + return hname; +} + +/** + * __policy_find - find a policy by @name on a policy list + * @head: list to search (NOT NULL) + * @name: name to search for (NOT NULL) + * + * Requires: rcu_read_lock be held + * + * Returns: unrefcounted policy that match @name or NULL if not found + */ +static inline struct aa_policy *__policy_find(struct list_head *head, + const char *name) +{ + struct aa_policy *policy; + + list_for_each_entry_rcu(policy, head, list) { + if (!strcmp(policy->name, name)) + return policy; + } + return NULL; +} + +/** + * __policy_strn_find - find a policy that's name matches @len chars of @str + * @head: list to search (NOT NULL) + * @str: string to search for (NOT NULL) + * @len: length of match required + * + * Requires: rcu_read_lock be held + * + * Returns: unrefcounted policy that match @str or NULL if not found + * + * if @len == strlen(@strlen) then this is equiv to __policy_find + * other wise it allows searching for policy by a partial match of name + */ +static inline struct aa_policy *__policy_strn_find(struct list_head *head, + const char *str, int len) +{ + struct aa_policy *policy; + + list_for_each_entry_rcu(policy, head, list) { + if (aa_strneq(policy->name, str, len)) + return policy; + } + + return NULL; +} + +bool aa_policy_init(struct aa_policy *policy, const char *prefix, + const char *name); +void aa_policy_destroy(struct aa_policy *policy); + #endif /* AA_LIB_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 190fe37ecff0..9b199678a11c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -77,19 +77,6 @@ enum profile_flags { struct aa_profile; -/* struct aa_policy - common part of both namespaces and profiles - * @name: name of the object - * @hname - The hierarchical name - * @list: list policy object is on - * @profiles: head of the profiles list contained in the object - */ -struct aa_policy { - char *name; - char *hname; - struct list_head list; - struct list_head profiles; -}; - /* struct aa_ns_acct - accounting of profiles in namespace * @max_size: maximum space allowed for all profiles in namespace * @max_count: maximum number of profiles that can be in this namespace diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 6028ffc008ae..e29ccdb0309a 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -20,6 +20,7 @@ #include "include/audit.h" #include "include/apparmor.h" #include "include/lib.h" +#include "include/policy.h" /** * aa_split_fqname - split a fqname into a profile and namespace name @@ -105,3 +106,54 @@ void *__aa_kvmalloc(size_t size, gfp_t flags) } return buffer; } + +/** + * aa_policy_init - initialize a policy structure + * @policy: policy to initialize (NOT NULL) + * @prefix: prefix name if any is required. (MAYBE NULL) + * @name: name of the policy, init will make a copy of it (NOT NULL) + * + * Note: this fn creates a copy of strings passed in + * + * Returns: true if policy init successful + */ +bool aa_policy_init(struct aa_policy *policy, const char *prefix, + const char *name) +{ + /* freed by policy_free */ + if (prefix) { + policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, + GFP_KERNEL); + if (policy->hname) + sprintf(policy->hname, "%s//%s", prefix, name); + } else + policy->hname = kstrdup(name, GFP_KERNEL); + if (!policy->hname) + return 0; + /* base.name is a substring of fqname */ + policy->name = (char *)hname_tail(policy->hname); + INIT_LIST_HEAD(&policy->list); + INIT_LIST_HEAD(&policy->profiles); + + return 1; +} + +/** + * aa_policy_destroy - free the elements referenced by @policy + * @policy: policy that is to have its elements freed (NOT NULL) + */ +void aa_policy_destroy(struct aa_policy *policy) +{ + /* still contains profiles -- invalid */ + if (on_list_rcu(&policy->profiles)) { + AA_ERROR("%s: internal error, policy '%s' contains profiles\n", + __func__, policy->name); + } + if (on_list_rcu(&policy->list)) { + AA_ERROR("%s: internal error, policy '%s' still on list\n", + __func__, policy->name); + } + + /* don't free name as its a subset of hname */ + kzfree(policy->hname); +} diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 179e68d7dc5f..a331149a4587 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -99,121 +99,6 @@ const char *const aa_profile_mode_names[] = { "unconfined", }; -/** - * hname_tail - find the last component of an hname - * @name: hname to find the base profile name component of (NOT NULL) - * - * Returns: the tail (base profile name) name component of an hname - */ -static const char *hname_tail(const char *hname) -{ - char *split; - hname = strim((char *)hname); - for (split = strstr(hname, "//"); split; split = strstr(hname, "//")) - hname = split + 2; - - return hname; -} - -/** - * policy_init - initialize a policy structure - * @policy: policy to initialize (NOT NULL) - * @prefix: prefix name if any is required. (MAYBE NULL) - * @name: name of the policy, init will make a copy of it (NOT NULL) - * - * Note: this fn creates a copy of strings passed in - * - * Returns: true if policy init successful - */ -static bool policy_init(struct aa_policy *policy, const char *prefix, - const char *name) -{ - /* freed by policy_free */ - if (prefix) { - policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, - GFP_KERNEL); - if (policy->hname) - sprintf(policy->hname, "%s//%s", prefix, name); - } else - policy->hname = kstrdup(name, GFP_KERNEL); - if (!policy->hname) - return 0; - /* base.name is a substring of fqname */ - policy->name = (char *)hname_tail(policy->hname); - INIT_LIST_HEAD(&policy->list); - INIT_LIST_HEAD(&policy->profiles); - - return 1; -} - -/** - * policy_destroy - free the elements referenced by @policy - * @policy: policy that is to have its elements freed (NOT NULL) - */ -static void policy_destroy(struct aa_policy *policy) -{ - /* still contains profiles -- invalid */ - if (on_list_rcu(&policy->profiles)) { - AA_ERROR("%s: internal error, " - "policy '%s' still contains profiles\n", - __func__, policy->name); - BUG(); - } - if (on_list_rcu(&policy->list)) { - AA_ERROR("%s: internal error, policy '%s' still on list\n", - __func__, policy->name); - BUG(); - } - - /* don't free name as its a subset of hname */ - kzfree(policy->hname); -} - -/** - * __policy_find - find a policy by @name on a policy list - * @head: list to search (NOT NULL) - * @name: name to search for (NOT NULL) - * - * Requires: rcu_read_lock be held - * - * Returns: unrefcounted policy that match @name or NULL if not found - */ -static struct aa_policy *__policy_find(struct list_head *head, const char *name) -{ - struct aa_policy *policy; - - list_for_each_entry_rcu(policy, head, list) { - if (!strcmp(policy->name, name)) - return policy; - } - return NULL; -} - -/** - * __policy_strn_find - find a policy that's name matches @len chars of @str - * @head: list to search (NOT NULL) - * @str: string to search for (NOT NULL) - * @len: length of match required - * - * Requires: rcu_read_lock be held - * - * Returns: unrefcounted policy that match @str or NULL if not found - * - * if @len == strlen(@strlen) then this is equiv to __policy_find - * other wise it allows searching for policy by a partial match of name - */ -static struct aa_policy *__policy_strn_find(struct list_head *head, - const char *str, int len) -{ - struct aa_policy *policy; - - list_for_each_entry_rcu(policy, head, list) { - if (aa_strneq(policy->name, str, len)) - return policy; - } - - return NULL; -} /* * Routines for AppArmor namespaces @@ -280,7 +165,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, AA_DEBUG("%s(%p)\n", __func__, ns); if (!ns) return NULL; - if (!policy_init(&ns->base, prefix, name)) + if (!aa_policy_init(&ns->base, prefix, name)) goto fail_ns; INIT_LIST_HEAD(&ns->sub_ns); @@ -321,7 +206,7 @@ static void free_namespace(struct aa_namespace *ns) if (!ns) return; - policy_destroy(&ns->base); + aa_policy_destroy(&ns->base); aa_put_namespace(ns->parent); ns->unconfined->ns = NULL; @@ -595,7 +480,7 @@ void aa_free_profile(struct aa_profile *profile) return; /* free children profiles */ - policy_destroy(&profile->base); + aa_policy_destroy(&profile->base); aa_put_profile(rcu_access_pointer(profile->parent)); aa_put_namespace(profile->ns); @@ -657,7 +542,7 @@ struct aa_profile *aa_alloc_profile(const char *hname) goto fail; kref_init(&profile->replacedby->count); - if (!policy_init(&profile->base, NULL, hname)) + if (!aa_policy_init(&profile->base, NULL, hname)) goto fail; kref_init(&profile->count); -- cgit v1.2.3 From cff281f6861e72f1416927aaa0c10a08bb7b2d3f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:15 -0800 Subject: apparmor: split apparmor policy namespaces code into its own file Policy namespaces will be diverging from profile management and expanding so put it in its own file. Signed-off-by: John Johansen --- security/apparmor/Makefile | 2 +- security/apparmor/apparmorfs.c | 1 + security/apparmor/audit.c | 1 + security/apparmor/domain.c | 1 + security/apparmor/include/policy.h | 112 +------------ security/apparmor/include/policy_ns.h | 137 ++++++++++++++++ security/apparmor/lsm.c | 1 + security/apparmor/policy.c | 298 ++-------------------------------- security/apparmor/policy_ns.c | 291 +++++++++++++++++++++++++++++++++ security/apparmor/procattr.c | 1 + 10 files changed, 454 insertions(+), 391 deletions(-) create mode 100644 security/apparmor/include/policy_ns.h create mode 100644 security/apparmor/policy_ns.c (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index d693df874818..3485f49d9de9 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o sid.o file.o + resource.o sid.o file.o policy_ns.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o clean-files := capability_names.h rlim_names.h diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 5923d5665209..efac1a9565e2 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -28,6 +28,7 @@ #include "include/context.h" #include "include/crypto.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/resource.h" /** diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 3a7f1da1425e..42101c42f446 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -18,6 +18,7 @@ #include "include/apparmor.h" #include "include/audit.h" #include "include/policy.h" +#include "include/policy_ns.h" const char *const op_table[] = { "null", diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index a4d90aa1045a..02d2f01e908d 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -29,6 +29,7 @@ #include "include/match.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" /** * aa_free_domain_entries - free entries in a domain table diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 9b199678a11c..a1b1d8ab589c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -30,6 +30,9 @@ #include "lib.h" #include "resource.h" + +struct aa_namespace; + extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -77,57 +80,6 @@ enum profile_flags { struct aa_profile; -/* struct aa_ns_acct - accounting of profiles in namespace - * @max_size: maximum space allowed for all profiles in namespace - * @max_count: maximum number of profiles that can be in this namespace - * @size: current size of profiles - * @count: current count of profiles (includes null profiles) - */ -struct aa_ns_acct { - int max_size; - int max_count; - int size; - int count; -}; - -/* struct aa_namespace - namespace for a set of profiles - * @base: common policy - * @parent: parent of namespace - * @lock: lock for modifying the object - * @acct: accounting for the namespace - * @unconfined: special unconfined profile for the namespace - * @sub_ns: list of namespaces under the current namespace. - * @uniq_null: uniq value used for null learning profiles - * @uniq_id: a unique id count for the profiles in the namespace - * @dents: dentries for the namespaces file entries in apparmorfs - * - * An aa_namespace defines the set profiles that are searched to determine - * which profile to attach to a task. Profiles can not be shared between - * aa_namespaces and profile names within a namespace are guaranteed to be - * unique. When profiles in separate namespaces have the same name they - * are NOT considered to be equivalent. - * - * Namespaces are hierarchical and only namespaces and profiles below the - * current namespace are visible. - * - * Namespace names must be unique and can not contain the characters :/\0 - * - * FIXME TODO: add vserver support of namespaces (can it all be done in - * userspace?) - */ -struct aa_namespace { - struct aa_policy base; - struct aa_namespace *parent; - struct mutex lock; - struct aa_ns_acct acct; - struct aa_profile *unconfined; - struct list_head sub_ns; - atomic_t uniq_null; - long uniq_id; - - struct dentry *dents[AAFS_NS_SIZEOF]; -}; - /* struct aa_policydb - match engine for a policy * dfa: dfa pattern match * start: set of start states for the different classes of data @@ -212,19 +164,11 @@ struct aa_profile { struct dentry *dents[AAFS_PROF_SIZEOF]; }; -extern struct aa_namespace *root_ns; extern enum profile_mode aa_g_profile_mode; -void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); - -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); -const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); -int aa_alloc_root_ns(void); -void aa_free_root_ns(void); -void aa_free_namespace_kref(struct kref *kref); +void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new); -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name); +void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_free_replacedby_kref(struct kref *kref); @@ -238,6 +182,7 @@ struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); +void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 #define PROF_REPLACE 0 @@ -245,12 +190,6 @@ ssize_t aa_remove_profiles(char *name, size_t size); #define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) -static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) -{ - return rcu_dereference_protected(p->parent, - mutex_is_locked(&p->ns->lock)); -} - /** * aa_get_profile - increment refcount on profile @p * @p: profile (MAYBE NULL) @@ -344,45 +283,6 @@ static inline void aa_put_replacedby(struct aa_replacedby *p) kref_put(&p->count, aa_free_replacedby_kref); } -/* requires profile list write lock held */ -static inline void __aa_update_replacedby(struct aa_profile *orig, - struct aa_profile *new) -{ - struct aa_profile *tmp; - tmp = rcu_dereference_protected(orig->replacedby->profile, - mutex_is_locked(&orig->ns->lock)); - rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); - orig->flags |= PFLAG_INVALID; - aa_put_profile(tmp); -} - -/** - * aa_get_namespace - increment references count on @ns - * @ns: namespace to increment reference count of (MAYBE NULL) - * - * Returns: pointer to @ns, if @ns is NULL returns NULL - * Requires: @ns must be held with valid refcount when called - */ -static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) -{ - if (ns) - aa_get_profile(ns->unconfined); - - return ns; -} - -/** - * aa_put_namespace - decrement refcount on @ns - * @ns: namespace to put reference of - * - * Decrement reference count of @ns and if no longer in use free it - */ -static inline void aa_put_namespace(struct aa_namespace *ns) -{ - if (ns) - aa_put_profile(ns->unconfined); -} - static inline int AUDIT_MODE(struct aa_profile *profile) { if (aa_g_audit != AUDIT_NORMAL) diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h new file mode 100644 index 000000000000..4b9e8c7c669a --- /dev/null +++ b/security/apparmor/include/policy_ns.h @@ -0,0 +1,137 @@ +/* + * AppArmor security module + * + * This file contains AppArmor policy definitions. + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2017 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ + +#ifndef __AA_NAMESPACE_H +#define __AA_NAMESPACE_H + +#include + +#include "apparmor.h" +#include "apparmorfs.h" +#include "policy.h" + + +/* struct aa_ns_acct - accounting of profiles in namespace + * @max_size: maximum space allowed for all profiles in namespace + * @max_count: maximum number of profiles that can be in this namespace + * @size: current size of profiles + * @count: current count of profiles (includes null profiles) + */ +struct aa_ns_acct { + int max_size; + int max_count; + int size; + int count; +}; + +/* struct aa_namespace - namespace for a set of profiles + * @base: common policy + * @parent: parent of namespace + * @lock: lock for modifying the object + * @acct: accounting for the namespace + * @unconfined: special unconfined profile for the namespace + * @sub_ns: list of namespaces under the current namespace. + * @uniq_null: uniq value used for null learning profiles + * @uniq_id: a unique id count for the profiles in the namespace + * @dents: dentries for the namespaces file entries in apparmorfs + * + * An aa_namespace defines the set profiles that are searched to determine + * which profile to attach to a task. Profiles can not be shared between + * aa_namespaces and profile names within a namespace are guaranteed to be + * unique. When profiles in separate namespaces have the same name they + * are NOT considered to be equivalent. + * + * Namespaces are hierarchical and only namespaces and profiles below the + * current namespace are visible. + * + * Namespace names must be unique and can not contain the characters :/\0 + */ +struct aa_namespace { + struct aa_policy base; + struct aa_namespace *parent; + struct mutex lock; + struct aa_ns_acct acct; + struct aa_profile *unconfined; + struct list_head sub_ns; + atomic_t uniq_null; + long uniq_id; + + struct dentry *dents[AAFS_NS_SIZEOF]; +}; + +extern struct aa_namespace *root_ns; + +extern const char *aa_hidden_ns_name; + +bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); +const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); +void aa_free_namespace(struct aa_namespace *ns); +int aa_alloc_root_ns(void); +void aa_free_root_ns(void); +void aa_free_namespace_kref(struct kref *kref); + +struct aa_namespace *aa_find_namespace(struct aa_namespace *root, + const char *name); +struct aa_namespace *aa_prepare_namespace(const char *name); +void __aa_remove_namespace(struct aa_namespace *ns); + +static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) +{ + return rcu_dereference_protected(p->parent, + mutex_is_locked(&p->ns->lock)); +} + +/** + * aa_get_namespace - increment references count on @ns + * @ns: namespace to increment reference count of (MAYBE NULL) + * + * Returns: pointer to @ns, if @ns is NULL returns NULL + * Requires: @ns must be held with valid refcount when called + */ +static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) +{ + if (ns) + aa_get_profile(ns->unconfined); + + return ns; +} + +/** + * aa_put_namespace - decrement refcount on @ns + * @ns: namespace to put reference of + * + * Decrement reference count of @ns and if no longer in use free it + */ +static inline void aa_put_namespace(struct aa_namespace *ns) +{ + if (ns) + aa_put_profile(ns->unconfined); +} + +/** + * __aa_find_namespace - find a namespace on a list by @name + * @head: list to search for namespace on (NOT NULL) + * @name: name of namespace to look for (NOT NULL) + * + * Returns: unrefcounted namespace + * + * Requires: rcu_read_lock be held + */ +static inline struct aa_namespace *__aa_find_namespace(struct list_head *head, + const char *name) +{ + return (struct aa_namespace *)__policy_find(head, name); +} + +#endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f76738b1eb15..1dae66ba757b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -34,6 +34,7 @@ #include "include/ipc.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/procattr.h" /* Flag indicating whether initialization completed */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a331149a4587..2a861824319e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -85,13 +85,11 @@ #include "include/match.h" #include "include/path.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/policy_unpack.h" #include "include/resource.h" -/* root profile namespace */ -struct aa_namespace *root_ns; - const char *const aa_profile_mode_names[] = { "enforce", "complain", @@ -100,202 +98,16 @@ const char *const aa_profile_mode_names[] = { }; -/* - * Routines for AppArmor namespaces - */ - -static const char *hidden_ns_name = "---"; -/** - * aa_ns_visible - test if @view is visible from @curr - * @curr: namespace to treat as the parent (NOT NULL) - * @view: namespace to test if visible from @curr (NOT NULL) - * - * Returns: true if @view is visible from @curr else false - */ -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) -{ - if (curr == view) - return true; - - for ( ; view; view = view->parent) { - if (view->parent == curr) - return true; - } - return false; -} - -/** - * aa_na_name - Find the ns name to display for @view from @curr - * @curr - current namespace (NOT NULL) - * @view - namespace attempting to view (NOT NULL) - * - * Returns: name of @view visible from @curr - */ -const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) -{ - /* if view == curr then the namespace name isn't displayed */ - if (curr == view) - return ""; - - if (aa_ns_visible(curr, view)) { - /* at this point if a ns is visible it is in a view ns - * thus the curr ns.hname is a prefix of its name. - * Only output the virtualized portion of the name - * Add + 2 to skip over // separating curr hname prefix - * from the visible tail of the views hname - */ - return view->base.hname + strlen(curr->base.hname) + 2; - } else - return hidden_ns_name; -} - -/** - * alloc_namespace - allocate, initialize and return a new namespace - * @prefix: parent namespace name (MAYBE NULL) - * @name: a preallocated name (NOT NULL) - * - * Returns: refcounted namespace or NULL on failure. - */ -static struct aa_namespace *alloc_namespace(const char *prefix, - const char *name) -{ - struct aa_namespace *ns; - - ns = kzalloc(sizeof(*ns), GFP_KERNEL); - AA_DEBUG("%s(%p)\n", __func__, ns); - if (!ns) - return NULL; - if (!aa_policy_init(&ns->base, prefix, name)) - goto fail_ns; - - INIT_LIST_HEAD(&ns->sub_ns); - mutex_init(&ns->lock); - - /* released by free_namespace */ - ns->unconfined = aa_alloc_profile("unconfined"); - if (!ns->unconfined) - goto fail_unconfined; - - ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | - PFLAG_IMMUTABLE | PFLAG_NS_COUNT; - ns->unconfined->mode = APPARMOR_UNCONFINED; - - /* ns and ns->unconfined share ns->unconfined refcount */ - ns->unconfined->ns = ns; - - atomic_set(&ns->uniq_null, 0); - - return ns; - -fail_unconfined: - kzfree(ns->base.hname); -fail_ns: - kzfree(ns); - return NULL; -} - -/** - * free_namespace - free a profile namespace - * @ns: the namespace to free (MAYBE NULL) - * - * Requires: All references to the namespace must have been put, if the - * namespace was referenced by a profile confining a task, - */ -static void free_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - aa_policy_destroy(&ns->base); - aa_put_namespace(ns->parent); - - ns->unconfined->ns = NULL; - aa_free_profile(ns->unconfined); - kzfree(ns); -} - -/** - * __aa_find_namespace - find a namespace on a list by @name - * @head: list to search for namespace on (NOT NULL) - * @name: name of namespace to look for (NOT NULL) - * - * Returns: unrefcounted namespace - * - * Requires: rcu_read_lock be held - */ -static struct aa_namespace *__aa_find_namespace(struct list_head *head, - const char *name) -{ - return (struct aa_namespace *)__policy_find(head, name); -} - -/** - * aa_find_namespace - look up a profile namespace on the namespace list - * @root: namespace to search in (NOT NULL) - * @name: name of namespace to find (NOT NULL) - * - * Returns: a refcounted namespace on the list, or NULL if no namespace - * called @name exists. - * - * refcount released by caller - */ -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name) -{ - struct aa_namespace *ns = NULL; - - rcu_read_lock(); - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - rcu_read_unlock(); - - return ns; -} - -/** - * aa_prepare_namespace - find an existing or create a new namespace of @name - * @name: the namespace to find or add (MAYBE NULL) - * - * Returns: refcounted namespace or NULL if failed to create one - */ -static struct aa_namespace *aa_prepare_namespace(const char *name) +/* requires profile list write lock held */ +void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) { - struct aa_namespace *ns, *root; - - root = aa_current_profile()->ns; - - mutex_lock(&root->lock); - - /* if name isn't specified the profile is loaded to the current ns */ - if (!name) { - /* released by caller */ - ns = aa_get_namespace(root); - goto out; - } + struct aa_profile *tmp; - /* try and find the specified ns and if it doesn't exist create it */ - /* released by caller */ - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); - if (!ns) { - ns = alloc_namespace(root->base.hname, name); - if (!ns) - goto out; - if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { - AA_ERROR("Failed to create interface for ns %s\n", - ns->base.name); - free_namespace(ns); - ns = NULL; - goto out; - } - ns->parent = aa_get_namespace(root); - list_add_rcu(&ns->base.list, &root->sub_ns); - /* add list ref */ - aa_get_namespace(ns); - } -out: - mutex_unlock(&root->lock); - - /* return ref */ - return ns; + tmp = rcu_dereference_protected(orig->replacedby->profile, + mutex_is_locked(&orig->ns->lock)); + rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); + orig->flags |= PFLAG_INVALID; + aa_put_profile(tmp); } /** @@ -333,8 +145,6 @@ static void __list_remove_profile(struct aa_profile *profile) aa_put_profile(profile); } -static void __profile_list_release(struct list_head *head); - /** * __remove_profile - remove old profile, and children * @profile: profile to be replaced (NOT NULL) @@ -344,7 +154,7 @@ static void __profile_list_release(struct list_head *head); static void __remove_profile(struct aa_profile *profile) { /* release any children lists first */ - __profile_list_release(&profile->base.profiles); + __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ __aa_update_replacedby(profile, profile->ns->unconfined); __aa_fs_profile_rmdir(profile); @@ -352,98 +162,18 @@ static void __remove_profile(struct aa_profile *profile) } /** - * __profile_list_release - remove all profiles on the list and put refs + * __aa_profile_list_release - remove all profiles on the list and put refs * @head: list of profiles (NOT NULL) * * Requires: namespace lock be held */ -static void __profile_list_release(struct list_head *head) +void __aa_profile_list_release(struct list_head *head) { struct aa_profile *profile, *tmp; list_for_each_entry_safe(profile, tmp, head, base.list) __remove_profile(profile); } -static void __ns_list_release(struct list_head *head); - -/** - * destroy_namespace - remove everything contained by @ns - * @ns: namespace to have it contents removed (NOT NULL) - */ -static void destroy_namespace(struct aa_namespace *ns) -{ - if (!ns) - return; - - mutex_lock(&ns->lock); - /* release all profiles in this namespace */ - __profile_list_release(&ns->base.profiles); - - /* release all sub namespaces */ - __ns_list_release(&ns->sub_ns); - - if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); - __aa_fs_namespace_rmdir(ns); - mutex_unlock(&ns->lock); -} - -/** - * __remove_namespace - remove a namespace and all its children - * @ns: namespace to be removed (NOT NULL) - * - * Requires: ns->parent->lock be held and ns removed from parent. - */ -static void __remove_namespace(struct aa_namespace *ns) -{ - /* remove ns from namespace list */ - list_del_rcu(&ns->base.list); - destroy_namespace(ns); - aa_put_namespace(ns); -} - -/** - * __ns_list_release - remove all profile namespaces on the list put refs - * @head: list of profile namespaces (NOT NULL) - * - * Requires: namespace lock be held - */ -static void __ns_list_release(struct list_head *head) -{ - struct aa_namespace *ns, *tmp; - list_for_each_entry_safe(ns, tmp, head, base.list) - __remove_namespace(ns); - -} - -/** - * aa_alloc_root_ns - allocate the root profile namespace - * - * Returns: %0 on success else error - * - */ -int __init aa_alloc_root_ns(void) -{ - /* released by aa_free_root_ns - used as list ref*/ - root_ns = alloc_namespace(NULL, "root"); - if (!root_ns) - return -ENOMEM; - - return 0; -} - - /** - * aa_free_root_ns - free the root profile namespace - */ -void __init aa_free_root_ns(void) - { - struct aa_namespace *ns = root_ns; - root_ns = NULL; - - destroy_namespace(ns); - aa_put_namespace(ns); -} - static void free_replacedby(struct aa_replacedby *r) { @@ -507,7 +237,7 @@ static void aa_free_profile_rcu(struct rcu_head *head) { struct aa_profile *p = container_of(head, struct aa_profile, rcu); if (p->flags & PFLAG_NS_COUNT) - free_namespace(p->ns); + aa_free_namespace(p->ns); else aa_free_profile(p); } @@ -1181,7 +911,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ mutex_lock(&ns->parent->lock); - __remove_namespace(ns); + __aa_remove_namespace(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c new file mode 100644 index 000000000000..d4e9924a276e --- /dev/null +++ b/security/apparmor/policy_ns.c @@ -0,0 +1,291 @@ +/* + * AppArmor security module + * + * This file contains AppArmor policy manipulation functions + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2017 Canonical Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + * + * AppArmor policy namespaces, allow for different sets of policies + * to be loaded for tasks within the namespace. + */ + +#include +#include +#include +#include + +#include "include/apparmor.h" +#include "include/context.h" +#include "include/policy_ns.h" +#include "include/policy.h" + +/* root profile namespace */ +struct aa_namespace *root_ns; +const char *aa_hidden_ns_name = "---"; + +/** + * aa_ns_visible - test if @view is visible from @curr + * @curr: namespace to treat as the parent (NOT NULL) + * @view: namespace to test if visible from @curr (NOT NULL) + * + * Returns: true if @view is visible from @curr else false + */ +bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) +{ + if (curr == view) + return true; + + for ( ; view; view = view->parent) { + if (view->parent == curr) + return true; + } + return false; +} + +/** + * aa_na_name - Find the ns name to display for @view from @curr + * @curr - current namespace (NOT NULL) + * @view - namespace attempting to view (NOT NULL) + * + * Returns: name of @view visible from @curr + */ +const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) +{ + /* if view == curr then the namespace name isn't displayed */ + if (curr == view) + return ""; + + if (aa_ns_visible(curr, view)) { + /* at this point if a ns is visible it is in a view ns + * thus the curr ns.hname is a prefix of its name. + * Only output the virtualized portion of the name + * Add + 2 to skip over // separating curr hname prefix + * from the visible tail of the views hname + */ + return view->base.hname + strlen(curr->base.hname) + 2; + } + + return aa_hidden_ns_name; +} + +/** + * alloc_namespace - allocate, initialize and return a new namespace + * @prefix: parent namespace name (MAYBE NULL) + * @name: a preallocated name (NOT NULL) + * + * Returns: refcounted namespace or NULL on failure. + */ +static struct aa_namespace *alloc_namespace(const char *prefix, + const char *name) +{ + struct aa_namespace *ns; + + ns = kzalloc(sizeof(*ns), GFP_KERNEL); + AA_DEBUG("%s(%p)\n", __func__, ns); + if (!ns) + return NULL; + if (!aa_policy_init(&ns->base, prefix, name)) + goto fail_ns; + + INIT_LIST_HEAD(&ns->sub_ns); + mutex_init(&ns->lock); + + /* released by free_namespace */ + ns->unconfined = aa_alloc_profile("unconfined"); + if (!ns->unconfined) + goto fail_unconfined; + + ns->unconfined->flags = PFLAG_IX_ON_NAME_ERROR | + PFLAG_IMMUTABLE | PFLAG_NS_COUNT; + ns->unconfined->mode = APPARMOR_UNCONFINED; + + /* ns and ns->unconfined share ns->unconfined refcount */ + ns->unconfined->ns = ns; + + atomic_set(&ns->uniq_null, 0); + + return ns; + +fail_unconfined: + kzfree(ns->base.hname); +fail_ns: + kzfree(ns); + return NULL; +} + +/** + * aa_free_namespace - free a profile namespace + * @ns: the namespace to free (MAYBE NULL) + * + * Requires: All references to the namespace must have been put, if the + * namespace was referenced by a profile confining a task, + */ +void aa_free_namespace(struct aa_namespace *ns) +{ + if (!ns) + return; + + aa_policy_destroy(&ns->base); + aa_put_namespace(ns->parent); + + ns->unconfined->ns = NULL; + aa_free_profile(ns->unconfined); + kzfree(ns); +} + +/** + * aa_find_namespace - look up a profile namespace on the namespace list + * @root: namespace to search in (NOT NULL) + * @name: name of namespace to find (NOT NULL) + * + * Returns: a refcounted namespace on the list, or NULL if no namespace + * called @name exists. + * + * refcount released by caller + */ +struct aa_namespace *aa_find_namespace(struct aa_namespace *root, + const char *name) +{ + struct aa_namespace *ns = NULL; + + rcu_read_lock(); + ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + rcu_read_unlock(); + + return ns; +} + +/** + * aa_prepare_namespace - find an existing or create a new namespace of @name + * @name: the namespace to find or add (MAYBE NULL) + * + * Returns: refcounted namespace or NULL if failed to create one + */ +struct aa_namespace *aa_prepare_namespace(const char *name) +{ + struct aa_namespace *ns, *root; + + root = aa_current_profile()->ns; + + mutex_lock(&root->lock); + + /* if name isn't specified the profile is loaded to the current ns */ + if (!name) { + /* released by caller */ + ns = aa_get_namespace(root); + goto out; + } + + /* try and find the specified ns and if it doesn't exist create it */ + /* released by caller */ + ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + if (!ns) { + ns = alloc_namespace(root->base.hname, name); + if (!ns) + goto out; + if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { + AA_ERROR("Failed to create interface for ns %s\n", + ns->base.name); + aa_free_namespace(ns); + ns = NULL; + goto out; + } + ns->parent = aa_get_namespace(root); + list_add_rcu(&ns->base.list, &root->sub_ns); + /* add list ref */ + aa_get_namespace(ns); + } +out: + mutex_unlock(&root->lock); + + /* return ref */ + return ns; +} + +static void __ns_list_release(struct list_head *head); + +/** + * destroy_namespace - remove everything contained by @ns + * @ns: namespace to have it contents removed (NOT NULL) + */ +static void destroy_namespace(struct aa_namespace *ns) +{ + if (!ns) + return; + + mutex_lock(&ns->lock); + /* release all profiles in this namespace */ + __aa_profile_list_release(&ns->base.profiles); + + /* release all sub namespaces */ + __ns_list_release(&ns->sub_ns); + + if (ns->parent) + __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); + __aa_fs_namespace_rmdir(ns); + mutex_unlock(&ns->lock); +} + +/** + * __aa_remove_namespace - remove a namespace and all its children + * @ns: namespace to be removed (NOT NULL) + * + * Requires: ns->parent->lock be held and ns removed from parent. + */ +void __aa_remove_namespace(struct aa_namespace *ns) +{ + /* remove ns from namespace list */ + list_del_rcu(&ns->base.list); + destroy_namespace(ns); + aa_put_namespace(ns); +} + +/** + * __ns_list_release - remove all profile namespaces on the list put refs + * @head: list of profile namespaces (NOT NULL) + * + * Requires: namespace lock be held + */ +static void __ns_list_release(struct list_head *head) +{ + struct aa_namespace *ns, *tmp; + + list_for_each_entry_safe(ns, tmp, head, base.list) + __aa_remove_namespace(ns); + +} + +/** + * aa_alloc_root_ns - allocate the root profile namespace + * + * Returns: %0 on success else error + * + */ +int __init aa_alloc_root_ns(void) +{ + /* released by aa_free_root_ns - used as list ref*/ + root_ns = alloc_namespace(NULL, "root"); + if (!root_ns) + return -ENOMEM; + + return 0; +} + + /** + * aa_free_root_ns - free the root profile namespace + */ +void __init aa_free_root_ns(void) +{ + struct aa_namespace *ns = root_ns; + + root_ns = NULL; + + destroy_namespace(ns); + aa_put_namespace(ns); +} diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index b125acc9aa26..bb2600d9d826 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -15,6 +15,7 @@ #include "include/apparmor.h" #include "include/context.h" #include "include/policy.h" +#include "include/policy_ns.h" #include "include/domain.h" #include "include/procattr.h" -- cgit v1.2.3 From 98849dff90e270af3b34889b9e08252544f40b5b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:16 -0800 Subject: apparmor: rename namespace to ns to improve code line lengths Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 49 ++++++++++---------- security/apparmor/domain.c | 24 +++++----- security/apparmor/include/apparmorfs.h | 8 ++-- security/apparmor/include/policy.h | 8 ++-- security/apparmor/include/policy_ns.h | 43 +++++++++--------- security/apparmor/policy.c | 32 ++++++------- security/apparmor/policy_ns.c | 82 +++++++++++++++++----------------- security/apparmor/procattr.c | 4 +- 8 files changed, 122 insertions(+), 128 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index efac1a9565e2..4409b63f0dd7 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -478,9 +478,9 @@ fail2: return error; } -void __aa_fs_namespace_rmdir(struct aa_namespace *ns) +void __aa_fs_ns_rmdir(struct aa_ns *ns) { - struct aa_namespace *sub; + struct aa_ns *sub; struct aa_profile *child; int i; @@ -492,7 +492,7 @@ void __aa_fs_namespace_rmdir(struct aa_namespace *ns) list_for_each_entry(sub, &ns->sub_ns, base.list) { mutex_lock(&sub->lock); - __aa_fs_namespace_rmdir(sub); + __aa_fs_ns_rmdir(sub); mutex_unlock(&sub->lock); } @@ -502,10 +502,9 @@ void __aa_fs_namespace_rmdir(struct aa_namespace *ns) } } -int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, - const char *name) +int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name) { - struct aa_namespace *sub; + struct aa_ns *sub; struct aa_profile *child; struct dentry *dent, *dir; int error; @@ -536,7 +535,7 @@ int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, list_for_each_entry(sub, &ns->sub_ns, base.list) { mutex_lock(&sub->lock); - error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL); + error = __aa_fs_ns_mkdir(sub, ns_subns_dir(ns), NULL); mutex_unlock(&sub->lock); if (error) goto fail2; @@ -548,7 +547,7 @@ fail: error = PTR_ERR(dent); fail2: - __aa_fs_namespace_rmdir(ns); + __aa_fs_ns_rmdir(ns); return error; } @@ -557,7 +556,7 @@ fail2: #define list_entry_is_head(pos, head, member) (&pos->member == (head)) /** - * __next_namespace - find the next namespace to list + * __next_ns - find the next namespace to list * @root: root namespace to stop search at (NOT NULL) * @ns: current ns position (NOT NULL) * @@ -568,10 +567,9 @@ fail2: * Requires: ns->parent->lock to be held * NOTE: will not unlock root->lock */ -static struct aa_namespace *__next_namespace(struct aa_namespace *root, - struct aa_namespace *ns) +static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) { - struct aa_namespace *parent, *next; + struct aa_ns *parent, *next; /* is next namespace a child */ if (!list_empty(&ns->sub_ns)) { @@ -604,10 +602,10 @@ static struct aa_namespace *__next_namespace(struct aa_namespace *root, * Returns: unrefcounted profile or NULL if no profile * Requires: profile->ns.lock to be held */ -static struct aa_profile *__first_profile(struct aa_namespace *root, - struct aa_namespace *ns) +static struct aa_profile *__first_profile(struct aa_ns *root, + struct aa_ns *ns) { - for (; ns; ns = __next_namespace(root, ns)) { + for (; ns; ns = __next_ns(root, ns)) { if (!list_empty(&ns->base.profiles)) return list_first_entry(&ns->base.profiles, struct aa_profile, base.list); @@ -627,7 +625,7 @@ static struct aa_profile *__first_profile(struct aa_namespace *root, static struct aa_profile *__next_profile(struct aa_profile *p) { struct aa_profile *parent; - struct aa_namespace *ns = p->ns; + struct aa_ns *ns = p->ns; /* is next profile a child */ if (!list_empty(&p->base.profiles)) @@ -661,7 +659,7 @@ static struct aa_profile *__next_profile(struct aa_profile *p) * * Returns: next profile or NULL if there isn't one */ -static struct aa_profile *next_profile(struct aa_namespace *root, +static struct aa_profile *next_profile(struct aa_ns *root, struct aa_profile *profile) { struct aa_profile *next = __next_profile(profile); @@ -669,7 +667,7 @@ static struct aa_profile *next_profile(struct aa_namespace *root, return next; /* finished all profiles in namespace move to next namespace */ - return __first_profile(root, __next_namespace(root, profile->ns)); + return __first_profile(root, __next_ns(root, profile->ns)); } /** @@ -684,9 +682,9 @@ static struct aa_profile *next_profile(struct aa_namespace *root, static void *p_start(struct seq_file *f, loff_t *pos) { struct aa_profile *profile = NULL; - struct aa_namespace *root = aa_current_profile()->ns; + struct aa_ns *root = aa_current_profile()->ns; loff_t l = *pos; - f->private = aa_get_namespace(root); + f->private = aa_get_ns(root); /* find the first profile */ @@ -713,7 +711,7 @@ static void *p_start(struct seq_file *f, loff_t *pos) static void *p_next(struct seq_file *f, void *p, loff_t *pos) { struct aa_profile *profile = p; - struct aa_namespace *ns = f->private; + struct aa_ns *ns = f->private; (*pos)++; return next_profile(ns, profile); @@ -729,14 +727,14 @@ static void *p_next(struct seq_file *f, void *p, loff_t *pos) static void p_stop(struct seq_file *f, void *p) { struct aa_profile *profile = p; - struct aa_namespace *root = f->private, *ns; + struct aa_ns *root = f->private, *ns; if (profile) { for (ns = profile->ns; ns && ns != root; ns = ns->parent) mutex_unlock(&ns->lock); } mutex_unlock(&root->lock); - aa_put_namespace(root); + aa_put_ns(root); } /** @@ -749,7 +747,7 @@ static void p_stop(struct seq_file *f, void *p) static int seq_show_profile(struct seq_file *f, void *p) { struct aa_profile *profile = (struct aa_profile *)p; - struct aa_namespace *root = f->private; + struct aa_ns *root = f->private; if (profile->ns != root) seq_printf(f, ":%s://", aa_ns_name(root, profile->ns)); @@ -951,8 +949,7 @@ static int __init aa_create_aafs(void) if (error) goto error; - error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry, - "policy"); + error = __aa_fs_ns_mkdir(root_ns, aa_fs_entry.dentry, "policy"); if (error) goto error; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 02d2f01e908d..503cb2c54447 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -94,7 +94,7 @@ out: * Returns: permission set */ static struct file_perms change_profile_perms(struct aa_profile *profile, - struct aa_namespace *ns, + struct aa_ns *ns, const char *name, u32 request, unsigned int start) { @@ -171,7 +171,7 @@ static struct aa_profile *__attach_match(const char *name, * * Returns: profile or NULL if no match found */ -static struct aa_profile *find_attach(struct aa_namespace *ns, +static struct aa_profile *find_attach(struct aa_ns *ns, struct list_head *list, const char *name) { struct aa_profile *profile; @@ -240,7 +240,7 @@ static const char *next_name(int xtype, const char *name) static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) { struct aa_profile *new_profile = NULL; - struct aa_namespace *ns = profile->ns; + struct aa_ns *ns = profile->ns; u32 xtype = xindex & AA_X_TYPE_MASK; int index = xindex & AA_X_INDEX_MASK; const char *name; @@ -248,7 +248,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) /* index is guaranteed to be in range, validated at load time */ for (name = profile->file.trans.table[index]; !new_profile && name; name = next_name(xtype, name)) { - struct aa_namespace *new_ns; + struct aa_ns *new_ns; const char *xname = NULL; new_ns = NULL; @@ -268,7 +268,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) ; } /* released below */ - new_ns = aa_find_namespace(ns, ns_name); + new_ns = aa_find_ns(ns, ns_name); if (!new_ns) continue; } else if (*name == '@') { @@ -281,7 +281,7 @@ static struct aa_profile *x_table_lookup(struct aa_profile *profile, u32 xindex) /* released by caller */ new_profile = aa_lookup_profile(new_ns ? new_ns : ns, xname); - aa_put_namespace(new_ns); + aa_put_ns(new_ns); } /* released by caller */ @@ -302,7 +302,7 @@ static struct aa_profile *x_to_profile(struct aa_profile *profile, const char *name, u32 xindex) { struct aa_profile *new_profile = NULL; - struct aa_namespace *ns = profile->ns; + struct aa_ns *ns = profile->ns; u32 xtype = xindex & AA_X_TYPE_MASK; switch (xtype) { @@ -339,7 +339,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { struct aa_task_cxt *cxt; struct aa_profile *profile, *new_profile = NULL; - struct aa_namespace *ns; + struct aa_ns *ns; char *buffer = NULL; unsigned int state; struct file_perms perms = {}; @@ -746,7 +746,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, { const struct cred *cred; struct aa_profile *profile, *target = NULL; - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; struct file_perms perms = {}; const char *name = NULL, *info = NULL; int op, error = 0; @@ -780,7 +780,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, if (ns_name) { /* released below */ - ns = aa_find_namespace(profile->ns, ns_name); + ns = aa_find_ns(profile->ns, ns_name); if (!ns) { /* we don't create new namespace in complain mode */ name = ns_name; @@ -790,7 +790,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } } else /* released below */ - ns = aa_get_namespace(profile->ns); + ns = aa_get_ns(profile->ns); /* if the name was not specified, use the name of the current profile */ if (!hname) { @@ -843,7 +843,7 @@ audit: error = aa_audit_file(profile, &perms, GFP_KERNEL, op, request, name, hname, GLOBAL_ROOT_UID, info, error); - aa_put_namespace(ns); + aa_put_ns(ns); aa_put_profile(target); put_cred(cred); diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index 414e56878dd0..5626bd48d7cb 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -62,7 +62,7 @@ extern const struct file_operations aa_fs_seq_file_ops; extern void __init aa_destroy_aafs(void); struct aa_profile; -struct aa_namespace; +struct aa_ns; enum aafs_ns_type { AAFS_NS_DIR, @@ -97,8 +97,8 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile); void __aa_fs_profile_migrate_dents(struct aa_profile *old, struct aa_profile *new); int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent); -void __aa_fs_namespace_rmdir(struct aa_namespace *ns); -int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent, - const char *name); +void __aa_fs_ns_rmdir(struct aa_ns *ns); +int __aa_fs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, + const char *name); #endif /* __AA_APPARMORFS_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index a1b1d8ab589c..415f8ab0b11e 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -31,7 +31,7 @@ #include "resource.h" -struct aa_namespace; +struct aa_ns; extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -141,7 +141,7 @@ struct aa_profile { struct rcu_head rcu; struct aa_profile __rcu *parent; - struct aa_namespace *ns; + struct aa_ns *ns; struct aa_replacedby *replacedby; const char *rename; @@ -177,8 +177,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); -struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *name); -struct aa_profile *aa_match_profile(struct aa_namespace *ns, const char *name); +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); +struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 4b9e8c7c669a..323752cc0c87 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -35,7 +35,7 @@ struct aa_ns_acct { int count; }; -/* struct aa_namespace - namespace for a set of profiles +/* struct aa_ns - namespace for a set of profiles * @base: common policy * @parent: parent of namespace * @lock: lock for modifying the object @@ -46,9 +46,9 @@ struct aa_ns_acct { * @uniq_id: a unique id count for the profiles in the namespace * @dents: dentries for the namespaces file entries in apparmorfs * - * An aa_namespace defines the set profiles that are searched to determine + * An aa_ns defines the set profiles that are searched to determine * which profile to attach to a task. Profiles can not be shared between - * aa_namespaces and profile names within a namespace are guaranteed to be + * aa_nss and profile names within a namespace are guaranteed to be * unique. When profiles in separate namespaces have the same name they * are NOT considered to be equivalent. * @@ -57,9 +57,9 @@ struct aa_ns_acct { * * Namespace names must be unique and can not contain the characters :/\0 */ -struct aa_namespace { +struct aa_ns { struct aa_policy base; - struct aa_namespace *parent; + struct aa_ns *parent; struct mutex lock; struct aa_ns_acct acct; struct aa_profile *unconfined; @@ -70,21 +70,20 @@ struct aa_namespace { struct dentry *dents[AAFS_NS_SIZEOF]; }; -extern struct aa_namespace *root_ns; +extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view); -const char *aa_ns_name(struct aa_namespace *parent, struct aa_namespace *child); -void aa_free_namespace(struct aa_namespace *ns); +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view); +const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child); +void aa_free_ns(struct aa_ns *ns); int aa_alloc_root_ns(void); void aa_free_root_ns(void); -void aa_free_namespace_kref(struct kref *kref); +void aa_free_ns_kref(struct kref *kref); -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name); -struct aa_namespace *aa_prepare_namespace(const char *name); -void __aa_remove_namespace(struct aa_namespace *ns); +struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name); +struct aa_ns *aa_prepare_ns(const char *name); +void __aa_remove_ns(struct aa_ns *ns); static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) { @@ -93,13 +92,13 @@ static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) } /** - * aa_get_namespace - increment references count on @ns + * aa_get_ns - increment references count on @ns * @ns: namespace to increment reference count of (MAYBE NULL) * * Returns: pointer to @ns, if @ns is NULL returns NULL * Requires: @ns must be held with valid refcount when called */ -static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) +static inline struct aa_ns *aa_get_ns(struct aa_ns *ns) { if (ns) aa_get_profile(ns->unconfined); @@ -108,19 +107,19 @@ static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns) } /** - * aa_put_namespace - decrement refcount on @ns + * aa_put_ns - decrement refcount on @ns * @ns: namespace to put reference of * * Decrement reference count of @ns and if no longer in use free it */ -static inline void aa_put_namespace(struct aa_namespace *ns) +static inline void aa_put_ns(struct aa_ns *ns) { if (ns) aa_put_profile(ns->unconfined); } /** - * __aa_find_namespace - find a namespace on a list by @name + * __aa_find_ns - find a namespace on a list by @name * @head: list to search for namespace on (NOT NULL) * @name: name of namespace to look for (NOT NULL) * @@ -128,10 +127,10 @@ static inline void aa_put_namespace(struct aa_namespace *ns) * * Requires: rcu_read_lock be held */ -static inline struct aa_namespace *__aa_find_namespace(struct list_head *head, - const char *name) +static inline struct aa_ns *__aa_find_ns(struct list_head *head, + const char *name) { - return (struct aa_namespace *)__policy_find(head, name); + return (struct aa_ns *)__policy_find(head, name); } #endif /* AA_NAMESPACE_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 2a861824319e..2dd8717a5a89 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -213,7 +213,7 @@ void aa_free_profile(struct aa_profile *profile) aa_policy_destroy(&profile->base); aa_put_profile(rcu_access_pointer(profile->parent)); - aa_put_namespace(profile->ns); + aa_put_ns(profile->ns); kzfree(profile->rename); aa_free_file_rules(&profile->file); @@ -237,7 +237,7 @@ static void aa_free_profile_rcu(struct rcu_head *head) { struct aa_profile *p = container_of(head, struct aa_profile, rcu); if (p->flags & PFLAG_NS_COUNT) - aa_free_namespace(p->ns); + aa_free_ns(p->ns); else aa_free_profile(p); } @@ -324,7 +324,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); - profile->ns = aa_get_namespace(parent->ns); + profile->ns = aa_get_ns(parent->ns); mutex_lock(&profile->ns->lock); __list_add_profile(&parent->base.profiles, profile); @@ -403,7 +403,7 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name) * * Returns: unrefcounted policy or NULL if not found */ -static struct aa_policy *__lookup_parent(struct aa_namespace *ns, +static struct aa_policy *__lookup_parent(struct aa_ns *ns, const char *hname) { struct aa_policy *policy; @@ -466,7 +466,7 @@ static struct aa_profile *__lookup_profile(struct aa_policy *base, * * Returns: refcounted profile or NULL if not found */ -struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) { struct aa_profile *profile; @@ -670,7 +670,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, * * Returns: profile to replace (no ref) on success else ptr error */ -static int __lookup_replace(struct aa_namespace *ns, const char *hname, +static int __lookup_replace(struct aa_ns *ns, const char *hname, bool noreplace, struct aa_profile **p, const char **info) { @@ -701,7 +701,7 @@ static int __lookup_replace(struct aa_namespace *ns, const char *hname, ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) { const char *ns_name, *info = NULL; - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; int op = OP_PROF_REPL; ssize_t error; @@ -713,7 +713,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) goto out; /* released below */ - ns = aa_prepare_namespace(ns_name); + ns = aa_prepare_ns(ns_name); if (!ns) { error = audit_policy(op, GFP_KERNEL, ns_name, "failed to prepare namespace", -ENOMEM); @@ -738,7 +738,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) } /* released when @new is freed */ - ent->new->ns = aa_get_namespace(ns); + ent->new->ns = aa_get_ns(ns); if (ent->old || ent->rename) continue; @@ -835,7 +835,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) mutex_unlock(&ns->lock); out: - aa_put_namespace(ns); + aa_put_ns(ns); if (error) return error; @@ -881,7 +881,7 @@ free: */ ssize_t aa_remove_profiles(char *fqname, size_t size) { - struct aa_namespace *root, *ns = NULL; + struct aa_ns *root, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; ssize_t error = 0; @@ -898,7 +898,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) char *ns_name; name = aa_split_fqname(fqname, &ns_name); /* released below */ - ns = aa_find_namespace(root, ns_name); + ns = aa_find_ns(root, ns_name); if (!ns) { info = "namespace does not exist"; error = -ENOENT; @@ -906,12 +906,12 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) } } else /* released below */ - ns = aa_get_namespace(root); + ns = aa_get_ns(root); if (!name) { /* remove namespace - can only happen if fqname[0] == ':' */ mutex_lock(&ns->parent->lock); - __aa_remove_namespace(ns); + __aa_remove_ns(ns); mutex_unlock(&ns->parent->lock); } else { /* remove profile */ @@ -929,13 +929,13 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) /* don't fail removal if audit fails */ (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); - aa_put_namespace(ns); + aa_put_ns(ns); aa_put_profile(profile); return size; fail_ns_lock: mutex_unlock(&ns->lock); - aa_put_namespace(ns); + aa_put_ns(ns); fail: (void) audit_policy(OP_PROF_RM, GFP_KERNEL, name, info, error); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index d4e9924a276e..88b3b3c110e3 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -26,7 +26,7 @@ #include "include/policy.h" /* root profile namespace */ -struct aa_namespace *root_ns; +struct aa_ns *root_ns; const char *aa_hidden_ns_name = "---"; /** @@ -36,7 +36,7 @@ const char *aa_hidden_ns_name = "---"; * * Returns: true if @view is visible from @curr else false */ -bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) +bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view) { if (curr == view) return true; @@ -55,7 +55,7 @@ bool aa_ns_visible(struct aa_namespace *curr, struct aa_namespace *view) * * Returns: name of @view visible from @curr */ -const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) +const char *aa_ns_name(struct aa_ns *curr, struct aa_ns *view) { /* if view == curr then the namespace name isn't displayed */ if (curr == view) @@ -75,16 +75,15 @@ const char *aa_ns_name(struct aa_namespace *curr, struct aa_namespace *view) } /** - * alloc_namespace - allocate, initialize and return a new namespace + * alloc_ns - allocate, initialize and return a new namespace * @prefix: parent namespace name (MAYBE NULL) * @name: a preallocated name (NOT NULL) * * Returns: refcounted namespace or NULL on failure. */ -static struct aa_namespace *alloc_namespace(const char *prefix, - const char *name) +static struct aa_ns *alloc_ns(const char *prefix, const char *name) { - struct aa_namespace *ns; + struct aa_ns *ns; ns = kzalloc(sizeof(*ns), GFP_KERNEL); AA_DEBUG("%s(%p)\n", __func__, ns); @@ -96,7 +95,7 @@ static struct aa_namespace *alloc_namespace(const char *prefix, INIT_LIST_HEAD(&ns->sub_ns); mutex_init(&ns->lock); - /* released by free_namespace */ + /* released by aa_free_ns() */ ns->unconfined = aa_alloc_profile("unconfined"); if (!ns->unconfined) goto fail_unconfined; @@ -120,19 +119,19 @@ fail_ns: } /** - * aa_free_namespace - free a profile namespace + * aa_free_ns - free a profile namespace * @ns: the namespace to free (MAYBE NULL) * * Requires: All references to the namespace must have been put, if the * namespace was referenced by a profile confining a task, */ -void aa_free_namespace(struct aa_namespace *ns) +void aa_free_ns(struct aa_ns *ns) { if (!ns) return; aa_policy_destroy(&ns->base); - aa_put_namespace(ns->parent); + aa_put_ns(ns->parent); ns->unconfined->ns = NULL; aa_free_profile(ns->unconfined); @@ -140,7 +139,7 @@ void aa_free_namespace(struct aa_namespace *ns) } /** - * aa_find_namespace - look up a profile namespace on the namespace list + * aa_find_ns - look up a profile namespace on the namespace list * @root: namespace to search in (NOT NULL) * @name: name of namespace to find (NOT NULL) * @@ -149,27 +148,26 @@ void aa_free_namespace(struct aa_namespace *ns) * * refcount released by caller */ -struct aa_namespace *aa_find_namespace(struct aa_namespace *root, - const char *name) +struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) { - struct aa_namespace *ns = NULL; + struct aa_ns *ns = NULL; rcu_read_lock(); - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); rcu_read_unlock(); return ns; } /** - * aa_prepare_namespace - find an existing or create a new namespace of @name + * aa_prepare_ns - find an existing or create a new namespace of @name * @name: the namespace to find or add (MAYBE NULL) * - * Returns: refcounted namespace or NULL if failed to create one + * Returns: refcounted ns or NULL if failed to create one */ -struct aa_namespace *aa_prepare_namespace(const char *name) +struct aa_ns *aa_prepare_ns(const char *name) { - struct aa_namespace *ns, *root; + struct aa_ns *ns, *root; root = aa_current_profile()->ns; @@ -178,28 +176,28 @@ struct aa_namespace *aa_prepare_namespace(const char *name) /* if name isn't specified the profile is loaded to the current ns */ if (!name) { /* released by caller */ - ns = aa_get_namespace(root); + ns = aa_get_ns(root); goto out; } /* try and find the specified ns and if it doesn't exist create it */ /* released by caller */ - ns = aa_get_namespace(__aa_find_namespace(&root->sub_ns, name)); + ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); if (!ns) { - ns = alloc_namespace(root->base.hname, name); + ns = alloc_ns(root->base.hname, name); if (!ns) goto out; - if (__aa_fs_namespace_mkdir(ns, ns_subns_dir(root), name)) { + if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) { AA_ERROR("Failed to create interface for ns %s\n", ns->base.name); - aa_free_namespace(ns); + aa_free_ns(ns); ns = NULL; goto out; } - ns->parent = aa_get_namespace(root); + ns->parent = aa_get_ns(root); list_add_rcu(&ns->base.list, &root->sub_ns); /* add list ref */ - aa_get_namespace(ns); + aa_get_ns(ns); } out: mutex_unlock(&root->lock); @@ -211,10 +209,10 @@ out: static void __ns_list_release(struct list_head *head); /** - * destroy_namespace - remove everything contained by @ns - * @ns: namespace to have it contents removed (NOT NULL) + * destroy_ns - remove everything contained by @ns + * @ns: ns to have it contents removed (NOT NULL) */ -static void destroy_namespace(struct aa_namespace *ns) +static void destroy_ns(struct aa_ns *ns) { if (!ns) return; @@ -228,22 +226,22 @@ static void destroy_namespace(struct aa_namespace *ns) if (ns->parent) __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); - __aa_fs_namespace_rmdir(ns); + __aa_fs_ns_rmdir(ns); mutex_unlock(&ns->lock); } /** - * __aa_remove_namespace - remove a namespace and all its children + * __aa_remove_ns - remove a namespace and all its children * @ns: namespace to be removed (NOT NULL) * * Requires: ns->parent->lock be held and ns removed from parent. */ -void __aa_remove_namespace(struct aa_namespace *ns) +void __aa_remove_ns(struct aa_ns *ns) { /* remove ns from namespace list */ list_del_rcu(&ns->base.list); - destroy_namespace(ns); - aa_put_namespace(ns); + destroy_ns(ns); + aa_put_ns(ns); } /** @@ -254,15 +252,15 @@ void __aa_remove_namespace(struct aa_namespace *ns) */ static void __ns_list_release(struct list_head *head) { - struct aa_namespace *ns, *tmp; + struct aa_ns *ns, *tmp; list_for_each_entry_safe(ns, tmp, head, base.list) - __aa_remove_namespace(ns); + __aa_remove_ns(ns); } /** - * aa_alloc_root_ns - allocate the root profile namespace + * aa_alloc_root_ns - allocate the root profile namespcae * * Returns: %0 on success else error * @@ -270,7 +268,7 @@ static void __ns_list_release(struct list_head *head) int __init aa_alloc_root_ns(void) { /* released by aa_free_root_ns - used as list ref*/ - root_ns = alloc_namespace(NULL, "root"); + root_ns = alloc_ns(NULL, "root"); if (!root_ns) return -ENOMEM; @@ -282,10 +280,10 @@ int __init aa_alloc_root_ns(void) */ void __init aa_free_root_ns(void) { - struct aa_namespace *ns = root_ns; + struct aa_ns *ns = root_ns; root_ns = NULL; - destroy_namespace(ns); - aa_put_namespace(ns); + destroy_ns(ns); + aa_put_ns(ns); } diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index bb2600d9d826..15ddf74ac269 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -40,8 +40,8 @@ int aa_getprocattr(struct aa_profile *profile, char **string) int len = 0, mode_len = 0, ns_len = 0, name_len; const char *mode_str = aa_profile_mode_names[profile->mode]; const char *ns_name = NULL; - struct aa_namespace *ns = profile->ns; - struct aa_namespace *current_ns = __aa_current_profile()->ns; + struct aa_ns *ns = profile->ns; + struct aa_ns *current_ns = __aa_current_profile()->ns; char *s; if (!aa_ns_visible(current_ns, ns)) -- cgit v1.2.3 From d97d51d253e08e059bba40002407ec3d188feafb Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:18 -0800 Subject: apparmor: rename PFLAG_INVALID to PFLAG_STALE Invalid does not convey the meaning of the flag anymore so rename it. Signed-off-by: John Johansen --- security/apparmor/include/context.h | 2 +- security/apparmor/include/policy.h | 6 +++--- security/apparmor/policy.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 6bf65798e5d1..a0acc2390fae 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -152,7 +152,7 @@ static inline struct aa_profile *aa_current_profile(void) struct aa_profile *profile; BUG_ON(!cxt || !cxt->profile); - if (PROFILE_INVALID(cxt->profile)) { + if (profile_is_stale(cxt->profile)) { profile = aa_get_newest_profile(cxt->profile); aa_replace_current_profile(profile); aa_put_profile(profile); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 415f8ab0b11e..56bef768c7eb 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -46,7 +46,7 @@ extern const char *const aa_profile_mode_names[]; #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) -#define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID) +#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) @@ -71,7 +71,7 @@ enum profile_flags { PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ - PFLAG_INVALID = 0x200, /* profile replaced/removed */ + PFLAG_STALE = 0x200, /* profile replaced/removed */ PFLAG_NS_COUNT = 0x400, /* carries NS ref count */ /* These flags must correspond with PATH_flags */ @@ -253,7 +253,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) if (!p) return NULL; - if (PROFILE_INVALID(p)) + if (profile_is_stale(p)) return aa_get_profile_rcu(&p->replacedby->profile); return aa_get_profile(p); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 2dd8717a5a89..edc81a0d0cb4 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -106,7 +106,7 @@ void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) tmp = rcu_dereference_protected(orig->replacedby->profile, mutex_is_locked(&orig->ns->lock)); rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); - orig->flags |= PFLAG_INVALID; + orig->flags |= PFLAG_STALE; aa_put_profile(tmp); } -- cgit v1.2.3 From 8399588a7f9def9195e577f988ad06f2a0ffb1af Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:19 -0800 Subject: apparmor: rename replacedby to proxy Proxy is shorter and a better fit than replaceby, so rename it. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 36 ++++++++++---------- security/apparmor/context.c | 2 +- security/apparmor/include/policy.h | 20 +++++------ security/apparmor/policy.c | 70 +++++++++++++++++++------------------- security/apparmor/policy_ns.c | 2 +- 5 files changed, 65 insertions(+), 65 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 4409b63f0dd7..0f1a4a28e025 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -228,12 +228,12 @@ const struct file_operations aa_fs_seq_file_ops = { static int aa_fs_seq_profile_open(struct inode *inode, struct file *file, int (*show)(struct seq_file *, void *)) { - struct aa_replacedby *r = aa_get_replacedby(inode->i_private); - int error = single_open(file, show, r); + struct aa_proxy *proxy = aa_get_proxy(inode->i_private); + int error = single_open(file, show, proxy); if (error) { file->private_data = NULL; - aa_put_replacedby(r); + aa_put_proxy(proxy); } return error; @@ -243,14 +243,14 @@ static int aa_fs_seq_profile_release(struct inode *inode, struct file *file) { struct seq_file *seq = (struct seq_file *) file->private_data; if (seq) - aa_put_replacedby(seq->private); + aa_put_proxy(seq->private); return single_release(inode, file); } static int aa_fs_seq_profname_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); seq_printf(seq, "%s\n", profile->base.name); aa_put_profile(profile); @@ -272,8 +272,8 @@ static const struct file_operations aa_fs_profname_fops = { static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]); aa_put_profile(profile); @@ -295,8 +295,8 @@ static const struct file_operations aa_fs_profmode_fops = { static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); if (profile->attach) seq_printf(seq, "%s\n", profile->attach); else if (profile->xmatch) @@ -323,8 +323,8 @@ static const struct file_operations aa_fs_profattach_fops = { static int aa_fs_seq_hash_show(struct seq_file *seq, void *v) { - struct aa_replacedby *r = seq->private; - struct aa_profile *profile = aa_get_profile_rcu(&r->profile); + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); unsigned int i, size = aa_hash_size(); if (profile->hash) { @@ -363,13 +363,13 @@ void __aa_fs_profile_rmdir(struct aa_profile *profile) __aa_fs_profile_rmdir(child); for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) { - struct aa_replacedby *r; + struct aa_proxy *proxy; if (!profile->dents[i]) continue; - r = d_inode(profile->dents[i])->i_private; + proxy = d_inode(profile->dents[i])->i_private; securityfs_remove(profile->dents[i]); - aa_put_replacedby(r); + aa_put_proxy(proxy); profile->dents[i] = NULL; } } @@ -391,12 +391,12 @@ static struct dentry *create_profile_file(struct dentry *dir, const char *name, struct aa_profile *profile, const struct file_operations *fops) { - struct aa_replacedby *r = aa_get_replacedby(profile->replacedby); + struct aa_proxy *proxy = aa_get_proxy(profile->proxy); struct dentry *dent; - dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops); + dent = securityfs_create_file(name, S_IFREG | 0444, dir, proxy, fops); if (IS_ERR(dent)) - aa_put_replacedby(r); + aa_put_proxy(proxy); return dent; } diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 3064c6ced87c..3c4f534ef88c 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -112,7 +112,7 @@ int aa_replace_current_profile(struct aa_profile *profile) aa_clear_task_cxt_trans(cxt); /* be careful switching cxt->profile, when racing replacement it - * is possible that cxt->profile->replacedby->profile is the reference + * is possible that cxt->profile->proxy->profile is the reference * keeping @profile valid, so make sure to get its reference before * dropping the reference on cxt->profile */ aa_get_profile(profile); diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 56bef768c7eb..f55ecb8b3777 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -91,7 +91,7 @@ struct aa_policydb { }; -struct aa_replacedby { +struct aa_proxy { struct kref count; struct aa_profile __rcu *profile; }; @@ -103,7 +103,7 @@ struct aa_replacedby { * @rcu: rcu head used when removing from @list * @parent: parent of profile * @ns: namespace the profile is in - * @replacedby: is set to the profile that replaced this profile + * @proxy: is set to the profile that replaced this profile * @rename: optional profile name that this profile renamed * @attach: human readable attachment string * @xmatch: optional extended matching for unconfined executables names @@ -126,7 +126,7 @@ struct aa_replacedby { * used to determine profile attachment against unconfined tasks. All other * attachments are determined by profile X transition rules. * - * The @replacedby struct is write protected by the profile lock. + * The @proxy struct is write protected by the profile lock. * * Profiles have a hierarchy where hats and children profiles keep * a reference to their parent. @@ -142,7 +142,7 @@ struct aa_profile { struct aa_profile __rcu *parent; struct aa_ns *ns; - struct aa_replacedby *replacedby; + struct aa_proxy *proxy; const char *rename; const char *attach; @@ -166,12 +166,12 @@ struct aa_profile { extern enum profile_mode aa_g_profile_mode; -void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new); +void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); -void aa_free_replacedby_kref(struct kref *kref); +void aa_free_proxy_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name); struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); @@ -254,7 +254,7 @@ static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) return NULL; if (profile_is_stale(p)) - return aa_get_profile_rcu(&p->replacedby->profile); + return aa_get_profile_rcu(&p->proxy->profile); return aa_get_profile(p); } @@ -269,7 +269,7 @@ static inline void aa_put_profile(struct aa_profile *p) kref_put(&p->count, aa_free_profile_kref); } -static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) +static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p) { if (p) kref_get(&(p->count)); @@ -277,10 +277,10 @@ static inline struct aa_replacedby *aa_get_replacedby(struct aa_replacedby *p) return p; } -static inline void aa_put_replacedby(struct aa_replacedby *p) +static inline void aa_put_proxy(struct aa_proxy *p) { if (p) - kref_put(&p->count, aa_free_replacedby_kref); + kref_put(&p->count, aa_free_proxy_kref); } static inline int AUDIT_MODE(struct aa_profile *profile) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index edc81a0d0cb4..a4bf6756bc1c 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -99,13 +99,13 @@ const char *const aa_profile_mode_names[] = { /* requires profile list write lock held */ -void __aa_update_replacedby(struct aa_profile *orig, struct aa_profile *new) +void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new) { struct aa_profile *tmp; - tmp = rcu_dereference_protected(orig->replacedby->profile, + tmp = rcu_dereference_protected(orig->proxy->profile, mutex_is_locked(&orig->ns->lock)); - rcu_assign_pointer(orig->replacedby->profile, aa_get_profile(new)); + rcu_assign_pointer(orig->proxy->profile, aa_get_profile(new)); orig->flags |= PFLAG_STALE; aa_put_profile(tmp); } @@ -156,7 +156,7 @@ static void __remove_profile(struct aa_profile *profile) /* release any children lists first */ __aa_profile_list_release(&profile->base.profiles); /* released by free_profile */ - __aa_update_replacedby(profile, profile->ns->unconfined); + __aa_update_proxy(profile, profile->ns->unconfined); __aa_fs_profile_rmdir(profile); __list_remove_profile(profile); } @@ -175,21 +175,21 @@ void __aa_profile_list_release(struct list_head *head) } -static void free_replacedby(struct aa_replacedby *r) +static void free_proxy(struct aa_proxy *p) { - if (r) { + if (p) { /* r->profile will not be updated any more as r is dead */ - aa_put_profile(rcu_dereference_protected(r->profile, true)); - kzfree(r); + aa_put_profile(rcu_dereference_protected(p->profile, true)); + kzfree(p); } } -void aa_free_replacedby_kref(struct kref *kref) +void aa_free_proxy_kref(struct kref *kref) { - struct aa_replacedby *r = container_of(kref, struct aa_replacedby, - count); - free_replacedby(r); + struct aa_proxy *p = container_of(kref, struct aa_proxy, count); + + free_proxy(p); } /** @@ -223,7 +223,7 @@ void aa_free_profile(struct aa_profile *profile) kzfree(profile->dirname); aa_put_dfa(profile->xmatch); aa_put_dfa(profile->policy.dfa); - aa_put_replacedby(profile->replacedby); + aa_put_proxy(profile->proxy); kzfree(profile->hash); kzfree(profile); @@ -267,10 +267,10 @@ struct aa_profile *aa_alloc_profile(const char *hname) if (!profile) return NULL; - profile->replacedby = kzalloc(sizeof(struct aa_replacedby), GFP_KERNEL); - if (!profile->replacedby) + profile->proxy = kzalloc(sizeof(struct aa_proxy), GFP_KERNEL); + if (!profile->proxy) goto fail; - kref_init(&profile->replacedby->count); + kref_init(&profile->proxy->count); if (!aa_policy_init(&profile->base, NULL, hname)) goto fail; @@ -280,7 +280,7 @@ struct aa_profile *aa_alloc_profile(const char *hname) return profile; fail: - kzfree(profile->replacedby); + kzfree(profile->proxy); kzfree(profile); return NULL; @@ -598,7 +598,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh, * __replace_profile - replace @old with @new on a list * @old: profile to be replaced (NOT NULL) * @new: profile to replace @old with (NOT NULL) - * @share_replacedby: transfer @old->replacedby to @new + * @share_proxy: transfer @old->proxy to @new * * Will duplicate and refcount elements that @new inherits from @old * and will inherit @old children. @@ -608,7 +608,7 @@ static struct aa_profile *__list_lookup_parent(struct list_head *lh, * Requires: namespace list lock be held, or list not be shared */ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, - bool share_replacedby) + bool share_proxy) { struct aa_profile *child, *tmp; @@ -623,7 +623,7 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, p = __find_child(&new->base.profiles, child->base.name); if (p) { /* @p replaces @child */ - __replace_profile(child, p, share_replacedby); + __replace_profile(child, p, share_proxy); continue; } @@ -641,13 +641,13 @@ static void __replace_profile(struct aa_profile *old, struct aa_profile *new, struct aa_profile *parent = aa_deref_parent(old); rcu_assign_pointer(new->parent, aa_get_profile(parent)); } - __aa_update_replacedby(old, new); - if (share_replacedby) { - aa_put_replacedby(new->replacedby); - new->replacedby = aa_get_replacedby(old->replacedby); - } else if (!rcu_access_pointer(new->replacedby->profile)) - /* aafs interface uses replacedby */ - rcu_assign_pointer(new->replacedby->profile, + __aa_update_proxy(old, new); + if (share_proxy) { + aa_put_proxy(new->proxy); + new->proxy = aa_get_proxy(old->proxy); + } else if (!rcu_access_pointer(new->proxy->profile)) + /* aafs interface uses proxy */ + rcu_assign_pointer(new->proxy->profile, aa_get_profile(new)); __aa_fs_profile_migrate_dents(old, new); @@ -797,15 +797,15 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) if (ent->old) { __replace_profile(ent->old, ent->new, 1); if (ent->rename) { - /* aafs interface uses replacedby */ - struct aa_replacedby *r = ent->new->replacedby; + /* aafs interface uses proxy */ + struct aa_proxy *r = ent->new->proxy; rcu_assign_pointer(r->profile, aa_get_profile(ent->new)); __replace_profile(ent->rename, ent->new, 0); } } else if (ent->rename) { - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __replace_profile(ent->rename, ent->new, 0); } else if (ent->new->parent) { @@ -819,14 +819,14 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) rcu_assign_pointer(ent->new->parent, newest); aa_put_profile(parent); } - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __list_add_profile(&newest->base.profiles, ent->new); aa_put_profile(newest); } else { - /* aafs interface uses replacedby */ - rcu_assign_pointer(ent->new->replacedby->profile, + /* aafs interface uses proxy */ + rcu_assign_pointer(ent->new->proxy->profile, aa_get_profile(ent->new)); __list_add_profile(&ns->base.profiles, ent->new); } diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 88b3b3c110e3..71fbd14e3b37 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -225,7 +225,7 @@ static void destroy_ns(struct aa_ns *ns) __ns_list_release(&ns->sub_ns); if (ns->parent) - __aa_update_replacedby(ns->unconfined, ns->parent->unconfined); + __aa_update_proxy(ns->unconfined, ns->parent->unconfined); __aa_fs_ns_rmdir(ns); mutex_unlock(&ns->lock); } -- cgit v1.2.3 From 1741e9eb8c15de0ba6598a342c51d0688cb569d2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:21 -0800 Subject: apparmor: add strn version of lookup_profile fn Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 ++ security/apparmor/policy.c | 36 +++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 11 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index f55ecb8b3777..c90f4a2ffe57 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -177,6 +177,8 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); +struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, + size_t n); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a4bf6756bc1c..291810490eaf 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -427,9 +427,10 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns, } /** - * __lookup_profile - lookup the profile matching @hname + * __lookupn_profile - lookup the profile matching @hname * @base: base list to start looking up profile name from (NOT NULL) * @hname: hierarchical profile name (NOT NULL) + * @n: length of @hname * * Requires: rcu_read_lock be held * @@ -437,53 +438,66 @@ static struct aa_policy *__lookup_parent(struct aa_ns *ns, * * Do a relative name lookup, recursing through profile tree. */ -static struct aa_profile *__lookup_profile(struct aa_policy *base, - const char *hname) +static struct aa_profile *__lookupn_profile(struct aa_policy *base, + const char *hname, size_t n) { struct aa_profile *profile = NULL; - char *split; + const char *split; - for (split = strstr(hname, "//"); split;) { + for (split = strnstr(hname, "//", n); split; + split = strnstr(hname, "//", n)) { profile = __strn_find_child(&base->profiles, hname, split - hname); if (!profile) return NULL; base = &profile->base; + n -= split + 2 - hname; hname = split + 2; - split = strstr(hname, "//"); } - profile = __find_child(&base->profiles, hname); + if (n) + return __strn_find_child(&base->profiles, hname, n); + return NULL; +} - return profile; +static struct aa_profile *__lookup_profile(struct aa_policy *base, + const char *hname) +{ + return __lookupn_profile(base, hname, strlen(hname)); } /** * aa_lookup_profile - find a profile by its full or partial name * @ns: the namespace to start from (NOT NULL) * @hname: name to do lookup on. Does not contain namespace prefix (NOT NULL) + * @n: size of @hname * * Returns: refcounted profile or NULL if not found */ -struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) +struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, + size_t n) { struct aa_profile *profile; rcu_read_lock(); do { - profile = __lookup_profile(&ns->base, hname); + profile = __lookupn_profile(&ns->base, hname, n); } while (profile && !aa_get_profile_not0(profile)); rcu_read_unlock(); /* the unconfined profile is not in the regular profile list */ - if (!profile && strcmp(hname, "unconfined") == 0) + if (!profile && strncmp(hname, "unconfined", n) == 0) profile = aa_get_newest_profile(ns->unconfined); /* refcount released by caller */ return profile; } +struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) +{ + return aa_lookupn_profile(ns, hname, strlen(hname)); +} /** * replacement_allowed - test to see if replacement is allowed * @profile: profile to test if it can be replaced (MAYBE NULL) -- cgit v1.2.3 From 31617ddfdd7764a5046f076247208aa324458069 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:24 -0800 Subject: apparmor: add fn to lookup profiles by fqname Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 ++ security/apparmor/include/policy_ns.h | 10 +++++----- security/apparmor/policy.c | 29 +++++++++++++++++++++++++++++ security/apparmor/policy_ns.c | 4 ++-- 4 files changed, 38 insertions(+), 7 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index c90f4a2ffe57..da62d29d3992 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -180,6 +180,8 @@ struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); struct aa_profile *aa_lookupn_profile(struct aa_ns *ns, const char *hname, size_t n); struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *name); +struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, + const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 381f8b078548..ebf9b40f84ed 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -46,11 +46,11 @@ struct aa_ns_acct { * @uniq_id: a unique id count for the profiles in the namespace * @dents: dentries for the namespaces file entries in apparmorfs * - * An aa_ns defines the set profiles that are searched to determine - * which profile to attach to a task. Profiles can not be shared between - * aa_nss and profile names within a namespace are guaranteed to be - * unique. When profiles in separate namespaces have the same name they - * are NOT considered to be equivalent. + * An aa_ns defines the set profiles that are searched to determine which + * profile to attach to a task. Profiles can not be shared between aa_ns + * and profile names within a namespace are guaranteed to be unique. When + * profiles in separate namespaces have the same name they are NOT considered + * to be equivalent. * * Namespaces are hierarchical and only namespaces and profiles below the * current namespace are visible. diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 291810490eaf..7fde5785005d 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -498,6 +498,35 @@ struct aa_profile *aa_lookup_profile(struct aa_ns *ns, const char *hname) { return aa_lookupn_profile(ns, hname, strlen(hname)); } + +struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, + const char *fqname, size_t n) +{ + struct aa_profile *profile; + struct aa_ns *ns; + const char *name, *ns_name; + size_t ns_len; + + name = aa_splitn_fqname(fqname, n, &ns_name, &ns_len); + if (ns_name) { + ns = aa_findn_ns(base->ns, ns_name, ns_len); + if (!ns) + return NULL; + } else + ns = aa_get_ns(base->ns); + + if (name) + profile = aa_lookupn_profile(ns, name, n - (name - fqname)); + else if (ns) + /* default profile for ns, currently unconfined */ + profile = aa_get_newest_profile(ns->unconfined); + else + profile = NULL; + aa_put_ns(ns); + + return profile; +} + /** * replacement_allowed - test to see if replacement is allowed * @profile: profile to test if it can be replaced (MAYBE NULL) diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 9746643cbab2..bab23cce197c 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -226,7 +226,7 @@ static void __ns_list_release(struct list_head *head); /** * destroy_ns - remove everything contained by @ns - * @ns: ns to have it contents removed (NOT NULL) + * @ns: namespace to have it contents removed (NOT NULL) */ static void destroy_ns(struct aa_ns *ns) { @@ -276,7 +276,7 @@ static void __ns_list_release(struct list_head *head) } /** - * aa_alloc_root_ns - allocate the root profile namespcae + * aa_alloc_root_ns - allocate the root profile namespace * * Returns: %0 on success else error * -- cgit v1.2.3 From 73688d1ed0b8f800f312f7bc9d583463858da861 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:34 -0800 Subject: apparmor: refactor prepare_ns() and make usable from different views prepare_ns() will need to be called from alternate views, and namespaces will need to be created via different interfaces. So refactor and allow specifying the view ns. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 6 ++- security/apparmor/include/policy.h | 3 +- security/apparmor/include/policy_ns.h | 4 +- security/apparmor/policy.c | 6 ++- security/apparmor/policy_ns.c | 98 +++++++++++++++++++++++------------ 5 files changed, 79 insertions(+), 38 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 96a02ee9c499..2b48be2169cb 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -125,7 +125,8 @@ static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(data, size, PROF_ADD); + error = aa_replace_profiles(__aa_current_profile()->ns, data, + size, PROF_ADD); kvfree(data); } @@ -147,7 +148,8 @@ static ssize_t profile_replace(struct file *f, const char __user *buf, data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(data, size, PROF_REPLACE); + error = aa_replace_profiles(__aa_current_profile()->ns, data, + size, PROF_REPLACE); kvfree(data); } diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index da62d29d3992..1573cade8812 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -184,7 +184,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace); +ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, + bool noreplace); ssize_t aa_remove_profiles(char *name, size_t size); void __aa_profile_list_release(struct list_head *head); diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index e4c876544adc..820d86d266fe 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -83,7 +83,9 @@ 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_prepare_ns(const char *name); +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); void __aa_remove_ns(struct aa_ns *ns); static inline struct aa_profile *aa_deref_parent(struct aa_profile *p) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 5d99fb7ac881..e02ab20b0a8d 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -731,6 +731,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list + * @view: namespace load is viewed from * @udata: serialized data stream (NOT NULL) * @size: size of the serialized data stream * @noreplace: true if only doing addition, no replacement allowed @@ -741,7 +742,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) +ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, + bool noreplace) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -756,7 +758,7 @@ ssize_t aa_replace_profiles(void *udata, size_t size, bool noreplace) goto out; /* released below */ - ns = aa_prepare_ns(ns_name); + ns = aa_prepare_ns(view, ns_name); if (!ns) { error = audit_policy(op, GFP_KERNEL, ns_name, "failed to prepare namespace", -ENOMEM); diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 8a5632f39751..f6cdc738ffcd 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -181,48 +181,82 @@ struct aa_ns *aa_find_ns(struct aa_ns *root, const char *name) return aa_findn_ns(root, name, strlen(name)); } +static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, + struct dentry *dir) +{ + struct aa_ns *ns; + int error; + + AA_BUG(!parent); + AA_BUG(!name); + AA_BUG(!mutex_is_locked(&parent->lock)); + + ns = alloc_ns(parent->base.hname, name); + if (!ns) + return NULL; + mutex_lock(&ns->lock); + error = __aa_fs_ns_mkdir(ns, ns_subns_dir(parent), name); + if (error) { + AA_ERROR("Failed to create interface for ns %s\n", + ns->base.name); + mutex_unlock(&ns->lock); + aa_free_ns(ns); + return ERR_PTR(error); + } + ns->parent = aa_get_ns(parent); + list_add_rcu(&ns->base.list, &parent->sub_ns); + /* add list ref */ + aa_get_ns(ns); + mutex_unlock(&ns->lock); + + return ns; +} + /** - * aa_prepare_ns - find an existing or create a new namespace of @name - * @name: the namespace to find or add (MAYBE NULL) + * aa_create_ns - create an ns, fail if it already exists + * @parent: the parent of the namespace being created + * @name: the name of the namespace + * @dir: if not null the dir to put the ns entries in * - * Returns: refcounted ns or NULL if failed to create one + * Returns: the a refcounted ns that has been add or an ERR_PTR */ -struct aa_ns *aa_prepare_ns(const char *name) +struct aa_ns *__aa_find_or_create_ns(struct aa_ns *parent, const char *name, + struct dentry *dir) { - struct aa_ns *ns, *root; + struct aa_ns *ns; - root = aa_current_profile()->ns; + AA_BUG(!mutex_is_locked(&parent->lock)); - mutex_lock(&root->lock); + /* try and find the specified ns */ + /* released by caller */ + ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); + if (!ns) + ns = __aa_create_ns(parent, name, dir); + else + ns = ERR_PTR(-EEXIST); - /* if name isn't specified the profile is loaded to the current ns */ - if (!name) { - /* released by caller */ - ns = aa_get_ns(root); - goto out; - } + /* return ref */ + return ns; +} +/** + * aa_prepare_ns - find an existing or create a new namespace of @name + * @parent: ns to treat as parent + * @name: the namespace to find or add (NOT NULL) + * + * Returns: refcounted namespace or PTR_ERR if failed to create one + */ +struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name) +{ + struct aa_ns *ns; + + mutex_lock(&parent->lock); /* try and find the specified ns and if it doesn't exist create it */ /* released by caller */ - ns = aa_get_ns(__aa_find_ns(&root->sub_ns, name)); - if (!ns) { - ns = alloc_ns(root->base.hname, name); - if (!ns) - goto out; - if (__aa_fs_ns_mkdir(ns, ns_subns_dir(root), name)) { - AA_ERROR("Failed to create interface for ns %s\n", - ns->base.name); - aa_free_ns(ns); - ns = NULL; - goto out; - } - ns->parent = aa_get_ns(root); - list_add_rcu(&ns->base.list, &root->sub_ns); - /* add list ref */ - aa_get_ns(ns); - } -out: - mutex_unlock(&root->lock); + ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); + if (!ns) + ns = __aa_create_ns(parent, name, NULL); + mutex_unlock(&parent->lock); /* return ref */ return ns; -- cgit v1.2.3 From 30b026a8d16bfa15bc24f4cca1604e47ac1a2f64 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:35 -0800 Subject: apparmor: pass gfp_t parameter into profile allocation Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 11 ++++++----- security/apparmor/policy_ns.c | 2 +- security/apparmor/policy_unpack.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 1573cade8812..b44eaea2bd2c 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -172,7 +172,7 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_free_proxy_kref(struct kref *kref); -struct aa_profile *aa_alloc_profile(const char *name); +struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp); struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index e02ab20b0a8d..e310f3b63fbe 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -255,24 +255,25 @@ void aa_free_profile_kref(struct kref *kref) /** * aa_alloc_profile - allocate, initialize and return a new profile * @hname: name of the profile (NOT NULL) + * @gfp: allocation type * * Returns: refcount profile or NULL on failure */ -struct aa_profile *aa_alloc_profile(const char *hname) +struct aa_profile *aa_alloc_profile(const char *hname, gfp_t gfp) { struct aa_profile *profile; /* freed by free_profile - usually through aa_put_profile */ - profile = kzalloc(sizeof(*profile), GFP_KERNEL); + profile = kzalloc(sizeof(*profile), gfp); if (!profile) return NULL; - profile->proxy = kzalloc(sizeof(struct aa_proxy), GFP_KERNEL); + profile->proxy = kzalloc(sizeof(struct aa_proxy), gfp); if (!profile->proxy) goto fail; kref_init(&profile->proxy->count); - if (!aa_policy_init(&profile->base, NULL, hname, GFP_KERNEL)) + if (!aa_policy_init(&profile->base, NULL, hname, gfp)) goto fail; kref_init(&profile->count); @@ -312,7 +313,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) goto fail; sprintf(name, "%s//null-%x", parent->base.hname, uniq); - profile = aa_alloc_profile(name); + profile = aa_alloc_profile(name, GFP_KERNEL); kfree(name); if (!profile) goto fail; diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index f6cdc738ffcd..1e19bd3c7851 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -102,7 +102,7 @@ static struct aa_ns *alloc_ns(const char *prefix, const char *name) mutex_init(&ns->lock); /* released by aa_free_ns() */ - ns->unconfined = aa_alloc_profile("unconfined"); + ns->unconfined = aa_alloc_profile("unconfined", GFP_KERNEL); if (!ns->unconfined) goto fail_unconfined; diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 138120698f83..9ddc6b2a7322 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -486,7 +486,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) if (!unpack_str(e, &name, NULL)) goto fail; - profile = aa_alloc_profile(name); + profile = aa_alloc_profile(name, GFP_KERNEL); if (!profile) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 181f7c977680dcd86eb71ad4b37239d2a385c3ad Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:36 -0800 Subject: apparmor: name null-XXX profiles after the executable When possible its better to name a learning profile after the missing profile in question. This allows for both more informative names and for profile reuse. Signed-off-by: John Johansen --- security/apparmor/domain.c | 8 +++--- security/apparmor/include/policy.h | 3 ++- security/apparmor/policy.c | 53 ++++++++++++++++++++++++++++---------- 3 files changed, 47 insertions(+), 17 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 503cb2c54447..1a8ffc577009 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -442,7 +442,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } } else if (COMPLAIN_MODE(profile)) { /* no exec permission - are we in learning mode */ - new_profile = aa_new_null_profile(profile, 0); + new_profile = aa_new_null_profile(profile, false, name, + GFP_ATOMIC); if (!new_profile) { error = -ENOMEM; info = "could not create null profile"; @@ -667,7 +668,8 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) aa_put_profile(root); target = name; /* released below */ - hat = aa_new_null_profile(profile, 1); + hat = aa_new_null_profile(profile, true, hats[0], + GFP_KERNEL); if (!hat) { info = "failed null profile create"; error = -ENOMEM; @@ -815,7 +817,7 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, if (permtest || !COMPLAIN_MODE(profile)) goto audit; /* released below */ - target = aa_new_null_profile(profile, 0); + target = aa_new_null_profile(profile, false, hname, GFP_KERNEL); if (!target) { info = "failed null profile create"; error = -ENOMEM; diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b44eaea2bd2c..3527e3f5a099 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -173,7 +173,8 @@ void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); void aa_free_proxy_kref(struct kref *kref); struct aa_profile *aa_alloc_profile(const char *name, gfp_t gfp); -struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat); +struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, + const char *base, gfp_t gfp); void aa_free_profile(struct aa_profile *profile); void aa_free_profile_kref(struct kref *kref); struct aa_profile *aa_find_child(struct aa_profile *parent, const char *name); diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index e310f3b63fbe..dd63ac92d28f 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -288,12 +288,16 @@ fail: } /** - * aa_new_null_profile - create a new null-X learning profile + * aa_new_null_profile - create or find a null-X learning profile * @parent: profile that caused this profile to be created (NOT NULL) * @hat: true if the null- learning profile is a hat + * @base: name to base the null profile off of + * @gfp: type of allocation * - * Create a null- complain mode profile used in learning mode. The name of - * the profile is unique and follows the format of parent//null-. + * Find/Create a null- complain mode profile used in learning mode. The + * name of the profile is unique and follows the format of parent//null-XXX. + * where XXX is based on the @name or if that fails or is not supplied + * a unique number * * null profiles are added to the profile list but the list does not * hold a count on them so that they are automatically released when @@ -301,27 +305,45 @@ fail: * * Returns: new refcounted profile else NULL on failure */ -struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) +struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, + const char *base, gfp_t gfp) { - struct aa_profile *profile = NULL; + struct aa_profile *profile; char *name; - int uniq = atomic_inc_return(&parent->ns->uniq_null); - /* freed below */ - name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, GFP_KERNEL); + AA_BUG(!parent); + + if (base) { + name = kmalloc(strlen(parent->base.hname) + 8 + strlen(base), + gfp); + if (name) { + sprintf(name, "%s//null-%s", parent->base.hname, base); + goto name; + } + /* fall through to try shorter uniq */ + } + + name = kmalloc(strlen(parent->base.hname) + 2 + 7 + 8, gfp); if (!name) - goto fail; - sprintf(name, "%s//null-%x", parent->base.hname, uniq); + return NULL; + sprintf(name, "%s//null-%x", parent->base.hname, + atomic_inc_return(&parent->ns->uniq_null)); - profile = aa_alloc_profile(name, GFP_KERNEL); - kfree(name); +name: + /* lookup to see if this is a dup creation */ + profile = aa_find_child(parent, basename(name)); + if (profile) + goto out; + + profile = aa_alloc_profile(name, gfp); if (!profile) goto fail; profile->mode = APPARMOR_COMPLAIN; - profile->flags = PFLAG_NULL; + profile->flags |= PFLAG_NULL; if (hat) profile->flags |= PFLAG_HAT; + profile->path_flags = parent->path_flags; /* released on free_profile */ rcu_assign_pointer(profile->parent, aa_get_profile(parent)); @@ -332,9 +354,14 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, int hat) mutex_unlock(&profile->ns->lock); /* refcount released by caller */ +out: + kfree(name); + return profile; fail: + kfree(name); + aa_free_profile(profile); return NULL; } -- cgit v1.2.3 From b79473f2de3eb3320e2a145da8a2ea03c7331784 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:47 -0800 Subject: apparmor: Make aa_remove_profile() callable from a different view This is prep work for fs operations being able to remove namespaces. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 3 ++- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 2501a65fe7d3..14b96a44a3f5 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -180,7 +180,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { data[size] = 0; - error = aa_remove_profiles(data, size); + error = aa_remove_profiles(__aa_current_profile()->ns, data, + size); kvfree(data); } diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 3527e3f5a099..8fcfb3c78d21 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -187,7 +187,7 @@ struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, bool noreplace); -ssize_t aa_remove_profiles(char *name, size_t size); +ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 046edecc4c8a..0314faeacccd 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -944,6 +944,7 @@ free: /** * aa_remove_profiles - remove profile(s) from the system + * @view: namespace the remove is being done from * @fqname: name of the profile or namespace to remove (NOT NULL) * @size: size of the name * @@ -954,9 +955,9 @@ free: * * Returns: size of data consume else error code if fails */ -ssize_t aa_remove_profiles(char *fqname, size_t size) +ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) { - struct aa_ns *root, *ns = NULL; + struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; const char *name = fqname, *info = NULL; ssize_t error = 0; @@ -967,7 +968,7 @@ ssize_t aa_remove_profiles(char *fqname, size_t size) goto fail; } - root = aa_current_profile()->ns; + root = view; if (fqname[0] == ':') { char *ns_name; -- cgit v1.2.3 From 2bd8dbbf22fe9eb2a99273436f815d49ceb23a8f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:50 -0800 Subject: apparmor: add ns being viewed as a param to policy_view_capable() Prepare for a tighter pairing of user namespaces and apparmor policy namespaces, by making the ns to be viewed available and checking that the user namespace level is the same as the policy ns level. This strict pairing will be relaxed once true support of user namespaces lands. Signed-off-by: John Johansen --- security/apparmor/include/context.h | 6 ++++++ security/apparmor/include/policy.h | 4 +++- security/apparmor/lsm.c | 8 ++++---- security/apparmor/policy.c | 25 ++++++++++++++++++++++--- 4 files changed, 35 insertions(+), 8 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index a0acc2390fae..d378bff47ccd 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -20,6 +20,7 @@ #include #include "policy.h" +#include "policy_ns.h" #define cred_cxt(X) (X)->security #define current_cxt() cred_cxt(current_cred()) @@ -162,6 +163,11 @@ static inline struct aa_profile *aa_current_profile(void) return cxt->profile; } +static inline struct aa_ns *aa_get_current_ns(void) +{ + return aa_get_ns(__aa_current_profile()->ns); +} + /** * aa_clear_task_cxt_trans - clear transition tracking info from the cxt * @cxt: task context to clear (NOT NULL) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 8fcfb3c78d21..b0b65c525bcc 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -33,6 +33,8 @@ struct aa_ns; +extern int unprivileged_userns_apparmor_policy; + extern const char *const aa_profile_mode_names[]; #define APPARMOR_MODE_NAMES_MAX_INDEX 4 @@ -297,7 +299,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) return profile->audit; } -bool policy_view_capable(void); +bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(void); bool aa_may_manage_policy(int op); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f852cd626f2e..f83ba33651a0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -745,7 +745,7 @@ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -759,7 +759,7 @@ static int param_set_aabool(const char *val, const struct kernel_param *kp) static int param_get_aabool(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_bool(buffer, kp); } @@ -773,14 +773,14 @@ static int param_set_aauint(const char *val, const struct kernel_param *kp) static int param_get_aauint(char *buffer, const struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; return param_get_uint(buffer, kp); } static int param_get_audit(char *buffer, struct kernel_param *kp) { - if (!policy_view_capable()) + if (!policy_view_capable(NULL)) return -EPERM; if (!apparmor_enabled) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 0125de6061fd..f092c04c7c4e 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -76,6 +76,7 @@ #include #include #include +#include #include "include/apparmor.h" #include "include/capability.h" @@ -89,6 +90,7 @@ #include "include/policy_unpack.h" #include "include/resource.h" +int unprivileged_userns_apparmor_policy = 1; const char *const aa_profile_mode_names[] = { "enforce", @@ -607,20 +609,37 @@ static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, &sa, NULL); } -bool policy_view_capable(void) +/** + * policy_view_capable - check if viewing policy in at @ns is allowed + * ns: namespace being viewed by current task (may be NULL) + * Returns: true if viewing policy is allowed + * + * If @ns is NULL then the namespace being viewed is assumed to be the + * tasks current namespace. + */ +bool policy_view_capable(struct aa_ns *ns) { struct user_namespace *user_ns = current_user_ns(); + struct aa_ns *view_ns = aa_get_current_ns(); + bool root_in_user_ns = uid_eq(current_euid(), make_kuid(user_ns, 0)) || + in_egroup_p(make_kgid(user_ns, 0)); bool response = false; + if (!ns) + ns = view_ns; - if (ns_capable(user_ns, CAP_MAC_ADMIN)) + if (root_in_user_ns && aa_ns_visible(view_ns, ns, true) && + (user_ns == &init_user_ns || + (unprivileged_userns_apparmor_policy != 0 && + user_ns->level == view_ns->level))) response = true; + aa_put_ns(view_ns); return response; } bool policy_admin_capable(void) { - return policy_view_capable() && !aa_g_lock_policy; + return policy_view_capable(NULL) && !aa_g_lock_policy; } /** -- cgit v1.2.3 From fd2a80438d736012129977bec779db093979057e Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:51 -0800 Subject: apparmor: add ns being viewed as a param to policy_admin_capable() Prepare for a tighter pairing of user namespaces and apparmor policy namespaces, by making the ns to be viewed available. Signed-off-by: John Johansen --- security/apparmor/include/policy.h | 2 +- security/apparmor/lsm.c | 12 ++++++------ security/apparmor/policy.c | 12 +++++++++--- 3 files changed, 16 insertions(+), 10 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b0b65c525bcc..27f9171fa31f 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -300,7 +300,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) } bool policy_view_capable(struct aa_ns *ns); -bool policy_admin_capable(void); +bool policy_admin_capable(struct aa_ns *ns); bool aa_may_manage_policy(int op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index f83ba33651a0..09f1c407c4d8 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -738,7 +738,7 @@ __setup("apparmor=", apparmor_enabled_setup); /* set global flag turning off the ability to load policy */ static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -752,7 +752,7 @@ static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) static int param_set_aabool(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_bool(val, kp); } @@ -766,7 +766,7 @@ static int param_get_aabool(char *buffer, const struct kernel_param *kp) static int param_set_aauint(const char *val, const struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; return param_set_uint(val, kp); } @@ -792,7 +792,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) static int param_set_audit(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; if (!apparmor_enabled) @@ -813,7 +813,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) static int param_get_mode(char *buffer, struct kernel_param *kp) { - if (!policy_admin_capable()) + if (!policy_view_capable(NULL)) return -EPERM; if (!apparmor_enabled) @@ -825,7 +825,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) static int param_set_mode(const char *val, struct kernel_param *kp) { int i; - if (!policy_admin_capable()) + if (!policy_admin_capable(NULL)) return -EPERM; if (!apparmor_enabled) diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index f092c04c7c4e..ef64c25b2a45 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -637,9 +637,15 @@ bool policy_view_capable(struct aa_ns *ns) return response; } -bool policy_admin_capable(void) +bool policy_admin_capable(struct aa_ns *ns) { - return policy_view_capable(NULL) && !aa_g_lock_policy; + struct user_namespace *user_ns = current_user_ns(); + bool capable = ns_capable(user_ns, CAP_MAC_ADMIN); + + AA_DEBUG("cap_mac_admin? %d\n", capable); + AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); + + return policy_view_capable(ns) && capable && !aa_g_lock_policy; } /** @@ -657,7 +663,7 @@ bool aa_may_manage_policy(int op) return 0; } - if (!policy_admin_capable()) { + if (!policy_admin_capable(NULL)) { audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, "not policy admin", -EACCES); return 0; -- cgit v1.2.3 From 078c73c63fb2878689da334f112507639c72c14f Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:52 -0800 Subject: apparmor: add profile and ns params to aa_may_manage_policy() Policy management will be expanded beyond traditional unconfined root. This will require knowning the profile of the task doing the management and the ns view. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- security/apparmor/include/policy.h | 2 +- security/apparmor/policy.c | 22 ++++++++++------------ 3 files changed, 12 insertions(+), 14 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 9fd7f73a4e86..cc6ee1ee2b42 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -100,7 +100,7 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, * Don't allow profile load/replace/remove from profiles that don't * have CAP_MAC_ADMIN */ - if (!aa_may_manage_policy(op)) + if (!aa_may_manage_policy(__aa_current_profile(), NULL, op)) return ERR_PTR(-EACCES); /* freed by caller to simple_write_to_buffer */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 27f9171fa31f..95641e235d47 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -301,6 +301,6 @@ static inline int AUDIT_MODE(struct aa_profile *profile) bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns); -bool aa_may_manage_policy(int op); +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index ef64c25b2a45..27d93aa58016 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -650,26 +650,24 @@ bool policy_admin_capable(struct aa_ns *ns) /** * aa_may_manage_policy - can the current task manage policy + * @profile: profile to check if it can manage policy * @op: the policy manipulation operation being done * - * Returns: true if the task is allowed to manipulate policy + * Returns: 0 if the task is allowed to manipulate policy else error */ -bool aa_may_manage_policy(int op) +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op) { /* check if loading policy is locked out */ - if (aa_g_lock_policy) { - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, + if (aa_g_lock_policy) + return audit_policy(profile, op, GFP_KERNEL, NULL, "policy_locked", -EACCES); - return 0; - } - if (!policy_admin_capable(NULL)) { - audit_policy(__aa_current_profile(), op, GFP_KERNEL, NULL, - "not policy admin", -EACCES); - return 0; - } + if (!policy_admin_capable(ns)) + return audit_policy(profile, op, GFP_KERNEL, NULL, + "not policy admin", -EACCES); - return 1; + /* TODO: add fine grained mediation of policy loads */ + return 0; } static struct aa_profile *__list_lookup_parent(struct list_head *lh, -- cgit v1.2.3 From 5ac8c355ae0013d82b3a07b49aebeadfce9b6e52 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:55 -0800 Subject: apparmor: allow introspecting the loaded policy pre internal transform Store loaded policy and allow introspecting it through apparmorfs. This has several uses from debugging, policy validation, and policy checkpoint and restore for containers. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 213 ++++++++++++++++++++++++------ security/apparmor/crypto.c | 39 +++++- security/apparmor/include/apparmorfs.h | 5 + security/apparmor/include/crypto.h | 5 + security/apparmor/include/policy.h | 5 +- security/apparmor/include/policy_unpack.h | 27 +++- security/apparmor/policy.c | 14 +- security/apparmor/policy_unpack.c | 28 +++- 8 files changed, 278 insertions(+), 58 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index cc6ee1ee2b42..2e6790cf54da 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -33,6 +33,7 @@ #include "include/policy.h" #include "include/policy_ns.h" #include "include/resource.h" +#include "include/policy_unpack.h" /** * aa_mangle_name - mangle a profile name to std profile layout form @@ -84,11 +85,13 @@ static int mangle_name(const char *name, char *target) * Returns: kernel buffer containing copy of user buffer data or an * ERR_PTR on failure. */ -static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, - size_t alloc_size, size_t copy_size, - loff_t *pos) +static struct aa_loaddata *aa_simple_write_to_buffer(int op, + const char __user *userbuf, + size_t alloc_size, + size_t copy_size, + loff_t *pos) { - char *data; + struct aa_loaddata *data; BUG_ON(copy_size > alloc_size); @@ -96,19 +99,16 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, /* only writes from pos 0, that is complete writes */ return ERR_PTR(-ESPIPE); - /* - * Don't allow profile load/replace/remove from profiles that don't - * have CAP_MAC_ADMIN - */ - if (!aa_may_manage_policy(__aa_current_profile(), NULL, op)) - return ERR_PTR(-EACCES); - /* freed by caller to simple_write_to_buffer */ - data = kvmalloc(alloc_size); + data = kvmalloc(sizeof(*data) + alloc_size); if (data == NULL) return ERR_PTR(-ENOMEM); + kref_init(&data->count); + data->size = copy_size; + data->hash = NULL; + data->abi = 0; - if (copy_from_user(data, userbuf, copy_size)) { + if (copy_from_user(data->data, userbuf, copy_size)) { kvfree(data); return ERR_PTR(-EFAULT); } @@ -116,26 +116,38 @@ static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, return data; } - -/* .load file hook fn to load policy */ -static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, - loff_t *pos) +static ssize_t policy_update(int binop, const char __user *buf, size_t size, + loff_t *pos) { - char *data; ssize_t error; + struct aa_loaddata *data; + struct aa_profile *profile = aa_current_profile(); + int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(profile, profile->ns, op); + if (error) + return error; - data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos); - + data = aa_simple_write_to_buffer(op, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(__aa_current_profile()->ns, data, - size, PROF_ADD); - kvfree(data); + error = aa_replace_profiles(profile->ns, binop, data); + aa_put_loaddata(data); } return error; } +static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, + loff_t *pos) +{ + int error = policy_update(PROF_ADD, buf, size, pos); + + return error; +} + static const struct file_operations aa_fs_profile_load = { .write = profile_load, .llseek = default_llseek, @@ -145,16 +157,7 @@ static const struct file_operations aa_fs_profile_load = { static ssize_t profile_replace(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - char *data; - ssize_t error; - - data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); - error = PTR_ERR(data); - if (!IS_ERR(data)) { - error = aa_replace_profiles(__aa_current_profile()->ns, data, - size, PROF_REPLACE); - kvfree(data); - } + int error = policy_update(PROF_REPLACE, buf, size, pos); return error; } @@ -164,27 +167,35 @@ static const struct file_operations aa_fs_profile_replace = { .llseek = default_llseek, }; -/* .remove file hook fn to remove loaded policy */ static ssize_t profile_remove(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - char *data; + struct aa_loaddata *data; + struct aa_profile *profile; ssize_t error; + profile = aa_current_profile(); + /* high level check about policy management - fine grained in + * below after unpack + */ + error = aa_may_manage_policy(profile, profile->ns, OP_PROF_RM); + if (error) + goto out; + /* * aa_remove_profile needs a null terminated string so 1 extra * byte is allocated and the copied data is null terminated. */ - data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos); + data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, + pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - data[size] = 0; - error = aa_remove_profiles(__aa_current_profile()->ns, data, - size); - kvfree(data); + data->data[size] = 0; + error = aa_remove_profiles(profile->ns, data->data, size); + aa_put_loaddata(data); } - + out: return error; } @@ -401,6 +412,100 @@ static const struct file_operations aa_fs_ns_name = { .release = single_release, }; +static int rawdata_release(struct inode *inode, struct file *file) +{ + /* TODO: switch to loaddata when profile switched to symlink */ + aa_put_loaddata(file->private_data); + + return 0; +} + +static int aa_fs_seq_raw_abi_show(struct seq_file *seq, void *v) +{ + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); + + if (profile->rawdata->abi) { + seq_printf(seq, "v%d", profile->rawdata->abi); + seq_puts(seq, "\n"); + } + aa_put_profile(profile); + + return 0; +} + +static int aa_fs_seq_raw_abi_open(struct inode *inode, struct file *file) +{ + return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_abi_show); +} + +static const struct file_operations aa_fs_seq_raw_abi_fops = { + .owner = THIS_MODULE, + .open = aa_fs_seq_raw_abi_open, + .read = seq_read, + .llseek = seq_lseek, + .release = aa_fs_seq_profile_release, +}; + +static int aa_fs_seq_raw_hash_show(struct seq_file *seq, void *v) +{ + struct aa_proxy *proxy = seq->private; + struct aa_profile *profile = aa_get_profile_rcu(&proxy->profile); + unsigned int i, size = aa_hash_size(); + + if (profile->rawdata->hash) { + for (i = 0; i < size; i++) + seq_printf(seq, "%.2x", profile->rawdata->hash[i]); + seq_puts(seq, "\n"); + } + aa_put_profile(profile); + + return 0; +} + +static int aa_fs_seq_raw_hash_open(struct inode *inode, struct file *file) +{ + return aa_fs_seq_profile_open(inode, file, aa_fs_seq_raw_hash_show); +} + +static const struct file_operations aa_fs_seq_raw_hash_fops = { + .owner = THIS_MODULE, + .open = aa_fs_seq_raw_hash_open, + .read = seq_read, + .llseek = seq_lseek, + .release = aa_fs_seq_profile_release, +}; + +static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, + loff_t *ppos) +{ + struct aa_loaddata *rawdata = file->private_data; + + return simple_read_from_buffer(buf, size, ppos, rawdata->data, + rawdata->size); +} + +static int rawdata_open(struct inode *inode, struct file *file) +{ + struct aa_proxy *proxy = inode->i_private; + struct aa_profile *profile; + + if (!policy_view_capable(NULL)) + return -EACCES; + profile = aa_get_profile_rcu(&proxy->profile); + file->private_data = aa_get_loaddata(profile->rawdata); + aa_put_profile(profile); + + return 0; +} + +static const struct file_operations aa_fs_rawdata_fops = { + .open = rawdata_open, + .read = rawdata_read, + .llseek = generic_file_llseek, + .release = rawdata_release, +}; + /** fns to setup dynamic per profile/namespace files **/ void __aa_fs_profile_rmdir(struct aa_profile *profile) { @@ -512,6 +617,29 @@ int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent) profile->dents[AAFS_PROF_HASH] = dent; } + if (profile->rawdata) { + dent = create_profile_file(dir, "raw_sha1", profile, + &aa_fs_seq_raw_hash_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_HASH] = dent; + + dent = create_profile_file(dir, "raw_abi", profile, + &aa_fs_seq_raw_abi_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_ABI] = dent; + + dent = securityfs_create_file("raw_data", S_IFREG | 0444, dir, + profile->proxy, + &aa_fs_rawdata_fops); + if (IS_ERR(dent)) + goto fail; + profile->dents[AAFS_PROF_RAW_DATA] = dent; + d_inode(dent)->i_size = profile->rawdata->size; + aa_get_proxy(profile->proxy); + } + list_for_each_entry(child, &profile->base.profiles, base.list) { error = __aa_fs_profile_mkdir(child, prof_child_dir(profile)); if (error) @@ -817,6 +945,9 @@ static const struct seq_operations aa_fs_profiles_op = { static int profiles_open(struct inode *inode, struct file *file) { + if (!policy_view_capable(NULL)) + return -EACCES; + return seq_open(file, &aa_fs_profiles_op); } diff --git a/security/apparmor/crypto.c b/security/apparmor/crypto.c index b75dab0df1cb..de8dc78b6144 100644 --- a/security/apparmor/crypto.c +++ b/security/apparmor/crypto.c @@ -29,6 +29,43 @@ unsigned int aa_hash_size(void) return apparmor_hash_size; } +char *aa_calc_hash(void *data, size_t len) +{ + struct { + struct shash_desc shash; + char ctx[crypto_shash_descsize(apparmor_tfm)]; + } desc; + char *hash = NULL; + int error = -ENOMEM; + + if (!apparmor_tfm) + return NULL; + + hash = kzalloc(apparmor_hash_size, GFP_KERNEL); + if (!hash) + goto fail; + + desc.shash.tfm = apparmor_tfm; + desc.shash.flags = 0; + + error = crypto_shash_init(&desc.shash); + if (error) + goto fail; + error = crypto_shash_update(&desc.shash, (u8 *) data, len); + if (error) + goto fail; + error = crypto_shash_final(&desc.shash, hash); + if (error) + goto fail; + + return hash; + +fail: + kfree(hash); + + return ERR_PTR(error); +} + int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len) { @@ -37,7 +74,7 @@ int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, char ctx[crypto_shash_descsize(apparmor_tfm)]; } desc; int error = -ENOMEM; - u32 le32_version = cpu_to_le32(version); + __le32 le32_version = cpu_to_le32(version); if (!aa_g_hash_policy) return 0; diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index eeeae5b0cc36..a593e75b3b03 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -70,6 +70,7 @@ enum aafs_ns_type { AAFS_NS_DIR, AAFS_NS_PROFS, AAFS_NS_NS, + AAFS_NS_RAW_DATA, AAFS_NS_COUNT, AAFS_NS_MAX_COUNT, AAFS_NS_SIZE, @@ -85,12 +86,16 @@ enum aafs_prof_type { AAFS_PROF_MODE, AAFS_PROF_ATTACH, AAFS_PROF_HASH, + AAFS_PROF_RAW_DATA, + AAFS_PROF_RAW_HASH, + AAFS_PROF_RAW_ABI, AAFS_PROF_SIZEOF, }; #define ns_dir(X) ((X)->dents[AAFS_NS_DIR]) #define ns_subns_dir(X) ((X)->dents[AAFS_NS_NS]) #define ns_subprofs_dir(X) ((X)->dents[AAFS_NS_PROFS]) +#define ns_subdata_dir(X) ((X)->dents[AAFS_NS_RAW_DATA]) #define prof_dir(X) ((X)->dents[AAFS_PROF_DIR]) #define prof_child_dir(X) ((X)->dents[AAFS_PROF_PROFS]) diff --git a/security/apparmor/include/crypto.h b/security/apparmor/include/crypto.h index dc418e5024d9..c1469f8db174 100644 --- a/security/apparmor/include/crypto.h +++ b/security/apparmor/include/crypto.h @@ -18,9 +18,14 @@ #ifdef CONFIG_SECURITY_APPARMOR_HASH unsigned int aa_hash_size(void); +char *aa_calc_hash(void *data, size_t len); int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len); #else +static inline char *aa_calc_hash(void *data, size_t len) +{ + return NULL; +} static inline int aa_calc_profile_hash(struct aa_profile *profile, u32 version, void *start, size_t len) { diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 95641e235d47..fbbc8677f527 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -161,6 +161,7 @@ struct aa_profile { struct aa_caps caps; struct aa_rlimit rlimits; + struct aa_loaddata *rawdata; unsigned char *hash; char *dirname; struct dentry *dents[AAFS_PROF_SIZEOF]; @@ -187,8 +188,8 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, - bool noreplace); +ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, + struct aa_loaddata *udata); ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); void __aa_profile_list_release(struct list_head *head); diff --git a/security/apparmor/include/policy_unpack.h b/security/apparmor/include/policy_unpack.h index c214fb88b1bc..7b675b6f7f02 100644 --- a/security/apparmor/include/policy_unpack.h +++ b/security/apparmor/include/policy_unpack.h @@ -16,6 +16,7 @@ #define __POLICY_INTERFACE_H #include +#include struct aa_load_ent { struct list_head list; @@ -34,6 +35,30 @@ struct aa_load_ent *aa_load_ent_alloc(void); #define PACKED_MODE_KILL 2 #define PACKED_MODE_UNCONFINED 3 -int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns); +/* struct aa_loaddata - buffer of policy load data set */ +struct aa_loaddata { + struct kref count; + size_t size; + int abi; + unsigned char *hash; + char data[]; +}; + +int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, const char **ns); + +static inline struct aa_loaddata * +aa_get_loaddata(struct aa_loaddata *data) +{ + if (data) + kref_get(&(data->count)); + return data; +} + +void aa_loaddata_kref(struct kref *kref); +static inline void aa_put_loaddata(struct aa_loaddata *data) +{ + if (data) + kref_put(&data->count, aa_loaddata_kref); +} #endif /* __POLICY_INTERFACE_H */ diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 3c5c0b28eac5..ff29b606f2b3 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -228,6 +228,7 @@ void aa_free_profile(struct aa_profile *profile) aa_put_proxy(profile->proxy); kzfree(profile->hash); + aa_put_loaddata(profile->rawdata); kzfree(profile); } @@ -802,10 +803,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from - * @profile: profile that is attempting to load/replace policy - * @udata: serialized data stream (NOT NULL) - * @size: size of the serialized data stream * @noreplace: true if only doing addition, no replacement allowed + * @udata: serialized data stream (NOT NULL) * * unpack and replace a profile on the profile list and uses of that profile * by any aa_task_cxt. If the profile does not exist on the profile list @@ -813,8 +812,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, - bool noreplace) +ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, + struct aa_loaddata *udata) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -824,7 +823,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, LIST_HEAD(lh); /* released below */ - error = aa_unpack(udata, size, &lh, &ns_name); + error = aa_unpack(udata, &lh, &ns_name); if (error) goto out; @@ -841,6 +840,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, void *udata, size_t size, /* setup parent and ns info */ list_for_each_entry(ent, &lh, list) { struct aa_policy *policy; + ent->new->rawdata = aa_get_loaddata(udata); error = __lookup_replace(ns, ent->new->base.hname, noreplace, &ent->old, &info); if (error) @@ -957,7 +957,7 @@ out: if (error) return error; - return size; + return udata->size; fail_lock: mutex_unlock(&ns->lock); diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 51a7f9fc8a3e..fb4ef84b88e1 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -117,6 +117,16 @@ static int audit_iface(struct aa_profile *new, const char *name, audit_cb); } +void aa_loaddata_kref(struct kref *kref) +{ + struct aa_loaddata *d = container_of(kref, struct aa_loaddata, count); + + if (d) { + kzfree(d->hash); + kvfree(d); + } +} + /* test if read will be in packed data bounds */ static bool inbounds(struct aa_ext *e, size_t size) { @@ -749,7 +759,6 @@ struct aa_load_ent *aa_load_ent_alloc(void) /** * 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) * @@ -759,15 +768,16 @@ struct aa_load_ent *aa_load_ent_alloc(void) * * Returns: profile(s) on @lh else error pointer if fails to unpack */ -int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) +int aa_unpack(struct aa_loaddata *udata, struct list_head *lh, + const char **ns) { struct aa_load_ent *tmp, *ent; struct aa_profile *profile = NULL; int error; struct aa_ext e = { - .start = udata, - .end = udata + size, - .pos = udata, + .start = udata->data, + .end = udata->data + udata->size, + .pos = udata->data, }; *ns = NULL; @@ -802,7 +812,13 @@ int aa_unpack(void *udata, size_t size, struct list_head *lh, const char **ns) ent->new = profile; list_add_tail(&ent->list, lh); } - + udata->abi = e.version & K_ABI_MASK; + udata->hash = aa_calc_hash(udata->data, udata->size); + if (IS_ERR(udata->hash)) { + error = PTR_ERR(udata->hash); + udata->hash = NULL; + goto fail; + } return 0; fail_profile: -- cgit v1.2.3 From 12dd7171d645a6658326ba234e6d4fc57a73bf98 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:42:57 -0800 Subject: apparmor: pass the subject profile into profile replace/remove This is just setup for new ns specific .load, .replace, .remove interface files. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 5 +++-- security/apparmor/include/policy.h | 7 ++++--- security/apparmor/policy.c | 25 ++++++++++++++----------- 3 files changed, 21 insertions(+), 16 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 2e6790cf54da..d654aacd7db4 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -133,7 +133,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, data = aa_simple_write_to_buffer(op, buf, size, size, pos); error = PTR_ERR(data); if (!IS_ERR(data)) { - error = aa_replace_profiles(profile->ns, binop, data); + error = aa_replace_profiles(profile->ns, profile, binop, data); aa_put_loaddata(data); } @@ -192,7 +192,8 @@ static ssize_t profile_remove(struct file *f, const char __user *buf, error = PTR_ERR(data); if (!IS_ERR(data)) { data->data[size] = 0; - error = aa_remove_profiles(profile->ns, data->data, size); + error = aa_remove_profiles(profile->ns, profile, data->data, + size); aa_put_loaddata(data); } out: diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index fbbc8677f527..b315ad5bdd85 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -188,9 +188,10 @@ struct aa_profile *aa_fqlookupn_profile(struct aa_profile *base, const char *fqname, size_t n); struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); -ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, - struct aa_loaddata *udata); -ssize_t aa_remove_profiles(struct aa_ns *view, char *name, size_t size); +ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, + bool noreplace, struct aa_loaddata *udata); +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, + char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index eb1ccd171789..912cdbed7977 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -803,6 +803,7 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, /** * aa_replace_profiles - replace profile(s) on the profile list * @view: namespace load is viewed from + * @label: label that is attempting to load/replace policy * @noreplace: true if only doing addition, no replacement allowed * @udata: serialized data stream (NOT NULL) * @@ -812,8 +813,8 @@ static int __lookup_replace(struct aa_ns *ns, const char *hname, * * Returns: size of data consumed else error code on failure. */ -ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, - struct aa_loaddata *udata) +ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, + bool noreplace, struct aa_loaddata *udata) { const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; @@ -935,7 +936,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, bool noreplace, list_del_init(&ent->list); op = (!ent->old && !ent->rename) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_ATOMIC, NULL, + audit_policy(profile, op, GFP_ATOMIC, NULL, ent->new->base.hname, NULL, error); if (ent->old) { @@ -991,8 +992,8 @@ fail_lock: /* audit cause of failure */ op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; fail: - audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, - ent->new->base.hname, info, error); + audit_policy(profile, op, GFP_KERNEL, ns_name, ent->new->base.hname, + info, error); /* audit status that rest of profiles in the atomic set failed too */ info = "valid profile in failed atomic policy load"; list_for_each_entry(tmp, &lh, list) { @@ -1002,7 +1003,7 @@ fail: continue; } op = (!ent->old) ? OP_PROF_LOAD : OP_PROF_REPL; - audit_policy(__aa_current_profile(), op, GFP_KERNEL, ns_name, + audit_policy(profile, op, GFP_KERNEL, ns_name, tmp->new->base.hname, info, error); } list_for_each_entry_safe(ent, tmp, &lh, list) { @@ -1016,6 +1017,7 @@ fail: /** * aa_remove_profiles - remove profile(s) from the system * @view: namespace the remove is being done from + * @subj: profile attempting to remove policy * @fqname: name of the profile or namespace to remove (NOT NULL) * @size: size of the name * @@ -1026,7 +1028,8 @@ fail: * * Returns: size of data consume else error code if fails */ -ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *subj, + char *fqname, size_t size) { struct aa_ns *root = NULL, *ns = NULL; struct aa_profile *profile = NULL; @@ -1075,8 +1078,8 @@ ssize_t aa_remove_profiles(struct aa_ns *view, char *fqname, size_t size) } /* don't fail removal if audit fails */ - (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - ns_name, name, info, error); + (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + error); aa_put_ns(ns); aa_put_profile(profile); return size; @@ -1086,7 +1089,7 @@ fail_ns_lock: aa_put_ns(ns); fail: - (void) audit_policy(__aa_current_profile(), OP_PROF_RM, GFP_KERNEL, - ns_name, name, info, error); + (void) audit_policy(subj, OP_PROF_RM, GFP_KERNEL, ns_name, name, info, + error); return error; } -- cgit v1.2.3 From 47f6e5cc7355e4ff2fd7ace919aa9e291077c26b Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 16 Jan 2017 00:43:01 -0800 Subject: apparmor: change op from int to const char * Having ops be an integer that is an index into an op name table is awkward and brittle. Every op change requires an edit for both the op constant and a string in the table. Instead switch to using const strings directly, eliminating the need for the table that needs to be kept in sync. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 4 +- security/apparmor/audit.c | 55 +------------------ security/apparmor/domain.c | 4 +- security/apparmor/file.c | 9 ++-- security/apparmor/include/audit.h | 108 ++++++++++++++++++------------------- security/apparmor/include/file.h | 9 ++-- security/apparmor/include/policy.h | 3 +- security/apparmor/lsm.c | 15 +++--- security/apparmor/policy.c | 7 +-- security/apparmor/procattr.c | 4 +- 10 files changed, 84 insertions(+), 134 deletions(-) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index af36af88c4ed..999a43e598f0 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -85,7 +85,7 @@ static int mangle_name(const char *name, char *target) * Returns: kernel buffer containing copy of user buffer data or an * ERR_PTR on failure. */ -static struct aa_loaddata *aa_simple_write_to_buffer(int op, +static struct aa_loaddata *aa_simple_write_to_buffer(const char *op, const char __user *userbuf, size_t alloc_size, size_t copy_size, @@ -122,7 +122,7 @@ static ssize_t policy_update(int binop, const char __user *buf, size_t size, ssize_t error; struct aa_loaddata *data; struct aa_profile *profile = aa_current_profile(); - int op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; + const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; /* high level check about policy management - fine grained in * below after unpack */ diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index 42101c42f446..bcd28d88df7b 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -20,59 +20,6 @@ #include "include/policy.h" #include "include/policy_ns.h" -const char *const op_table[] = { - "null", - - "sysctl", - "capable", - - "unlink", - "mkdir", - "rmdir", - "mknod", - "truncate", - "link", - "symlink", - "rename_src", - "rename_dest", - "chmod", - "chown", - "getattr", - "open", - - "file_perm", - "file_lock", - "file_mmap", - "file_mprotect", - - "create", - "post_create", - "bind", - "connect", - "listen", - "accept", - "sendmsg", - "recvmsg", - "getsockname", - "getpeername", - "getsockopt", - "setsockopt", - "socket_shutdown", - - "ptrace", - - "exec", - "change_hat", - "change_profile", - "change_onexec", - - "setprocattr", - "setrlimit", - - "profile_replace", - "profile_load", - "profile_remove" -}; const char *const audit_mode_names[] = { "normal", @@ -120,7 +67,7 @@ static void audit_pre(struct audit_buffer *ab, void *ca) if (sa->aad->op) { audit_log_format(ab, " operation="); - audit_log_string(ab, op_table[sa->aad->op]); + audit_log_string(ab, sa->aad->op); } if (sa->aad->info) { diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 84856b7bbee1..c2f1d651db23 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -750,8 +750,8 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, struct aa_profile *profile, *target = NULL; struct aa_ns *ns = NULL; struct file_perms perms = {}; - const char *name = NULL, *info = NULL; - int op, error = 0; + const char *name = NULL, *info = NULL, *op; + int error = 0; u32 request; if (!hname && !ns_name) diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 608971ac6781..e04f044340ba 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -104,7 +104,7 @@ static void file_audit_cb(struct audit_buffer *ab, void *va) * Returns: %0 or error on failure */ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, + gfp_t gfp, const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error) { int type = AUDIT_APPARMOR_AUTO; @@ -276,8 +276,9 @@ static inline bool is_deleted(struct dentry *dentry) * * Returns: %0 else error if access denied or other error */ -int aa_path_perm(int op, struct aa_profile *profile, const struct path *path, - int flags, u32 request, struct path_cond *cond) +int aa_path_perm(const char *op, struct aa_profile *profile, + const struct path *path, int flags, u32 request, + struct path_cond *cond) { char *buffer = NULL; struct file_perms perms = {}; @@ -446,7 +447,7 @@ audit: * * Returns: %0 if access allowed else error */ -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, u32 request) { struct path_cond cond = { diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index dbfb4a6d72b6..956c0b16a30f 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -46,65 +46,63 @@ enum audit_type { AUDIT_APPARMOR_AUTO }; -extern const char *const op_table[]; -enum aa_ops { - OP_NULL, - - OP_SYSCTL, - OP_CAPABLE, - - OP_UNLINK, - OP_MKDIR, - OP_RMDIR, - OP_MKNOD, - OP_TRUNC, - OP_LINK, - OP_SYMLINK, - OP_RENAME_SRC, - OP_RENAME_DEST, - OP_CHMOD, - OP_CHOWN, - OP_GETATTR, - OP_OPEN, - - OP_FPERM, - OP_FLOCK, - OP_FMMAP, - OP_FMPROT, - - OP_CREATE, - OP_POST_CREATE, - OP_BIND, - OP_CONNECT, - OP_LISTEN, - OP_ACCEPT, - OP_SENDMSG, - OP_RECVMSG, - OP_GETSOCKNAME, - OP_GETPEERNAME, - OP_GETSOCKOPT, - OP_SETSOCKOPT, - OP_SOCK_SHUTDOWN, - - OP_PTRACE, - - OP_EXEC, - OP_CHANGE_HAT, - OP_CHANGE_PROFILE, - OP_CHANGE_ONEXEC, - - OP_SETPROCATTR, - OP_SETRLIMIT, - - OP_PROF_REPL, - OP_PROF_LOAD, - OP_PROF_RM, -}; +#define OP_NULL NULL + +#define OP_SYSCTL "sysctl" +#define OP_CAPABLE "capable" + +#define OP_UNLINK "unlink" +#define OP_MKDIR "mkdir" +#define OP_RMDIR "rmdir" +#define OP_MKNOD "mknod" +#define OP_TRUNC "truncate" +#define OP_LINK "link" +#define OP_SYMLINK "symlink" +#define OP_RENAME_SRC "rename_src" +#define OP_RENAME_DEST "rename_dest" +#define OP_CHMOD "chmod" +#define OP_CHOWN "chown" +#define OP_GETATTR "getattr" +#define OP_OPEN "open" + +#define OP_FPERM "file_perm" +#define OP_FLOCK "file_lock" +#define OP_FMMAP "file_mmap" +#define OP_FMPROT "file_mprotect" + +#define OP_CREATE "create" +#define OP_POST_CREATE "post_create" +#define OP_BIND "bind" +#define OP_CONNECT "connect" +#define OP_LISTEN "listen" +#define OP_ACCEPT "accept" +#define OP_SENDMSG "sendmsg" +#define OP_RECVMSG "recvmsg" +#define OP_GETSOCKNAME "getsockname" +#define OP_GETPEERNAME "getpeername" +#define OP_GETSOCKOPT "getsockopt" +#define OP_SETSOCKOPT "setsockopt" +#define OP_SHUTDOWN "socket_shutdown" + +#define OP_PTRACE "ptrace" + +#define OP_EXEC "exec" + +#define OP_CHANGE_HAT "change_hat" +#define OP_CHANGE_PROFILE "change_profile" +#define OP_CHANGE_ONEXEC "change_onexec" + +#define OP_SETPROCATTR "setprocattr" +#define OP_SETRLIMIT "setrlimit" + +#define OP_PROF_REPL "profile_replace" +#define OP_PROF_LOAD "profile_load" +#define OP_PROF_RM "profile_remove" struct apparmor_audit_data { int error; - int op; + const char *op; int type; void *profile; const char *name; diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index 4803c97d1992..0eb54363e033 100644 --- a/security/apparmor/include/file.h +++ b/security/apparmor/include/file.h @@ -145,7 +145,7 @@ static inline u16 dfa_map_xindex(u16 mask) dfa_map_xindex((ACCEPT_TABLE(dfa)[state] >> 14) & 0x3fff) int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, - gfp_t gfp, int op, u32 request, const char *name, + gfp_t gfp, const char *op, u32 request, const char *name, const char *target, kuid_t ouid, const char *info, int error); /** @@ -171,13 +171,14 @@ unsigned int aa_str_perms(struct aa_dfa *dfa, unsigned int start, const char *name, struct path_cond *cond, struct file_perms *perms); -int aa_path_perm(int op, struct aa_profile *profile, const struct path *path, - int flags, u32 request, struct path_cond *cond); +int aa_path_perm(const char *op, struct aa_profile *profile, + const struct path *path, int flags, u32 request, + struct path_cond *cond); int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, const struct path *new_dir, struct dentry *new_dentry); -int aa_file_perm(int op, struct aa_profile *profile, struct file *file, +int aa_file_perm(const char *op, struct aa_profile *profile, struct file *file, u32 request); static inline void aa_free_file_rules(struct aa_file_rules *rules) diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index b315ad5bdd85..a5a997896836 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -303,6 +303,7 @@ static inline int AUDIT_MODE(struct aa_profile *profile) bool policy_view_capable(struct aa_ns *ns); bool policy_admin_capable(struct aa_ns *ns); -int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op); +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, + const char *op); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 84666114e9f5..c751b033420c 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -152,7 +152,7 @@ static int apparmor_capable(const struct cred *cred, struct user_namespace *ns, * * Returns: %0 else error code if error or permission denied */ -static int common_perm(int op, const struct path *path, u32 mask, +static int common_perm(const char *op, const struct path *path, u32 mask, struct path_cond *cond) { struct aa_profile *profile; @@ -175,7 +175,7 @@ static int common_perm(int op, const struct path *path, u32 mask, * * Returns: %0 else error code if error or permission denied */ -static int common_perm_dir_dentry(int op, const struct path *dir, +static int common_perm_dir_dentry(const char *op, const struct path *dir, struct dentry *dentry, u32 mask, struct path_cond *cond) { @@ -192,7 +192,8 @@ static int common_perm_dir_dentry(int op, const struct path *dir, * * Returns: %0 else error code if error or permission denied */ -static inline int common_perm_path(int op, const struct path *path, u32 mask) +static inline int common_perm_path(const char *op, const struct path *path, + u32 mask) { struct path_cond cond = { d_backing_inode(path->dentry)->i_uid, d_backing_inode(path->dentry)->i_mode @@ -212,7 +213,7 @@ static inline int common_perm_path(int op, const struct path *path, u32 mask) * * Returns: %0 else error code if error or permission denied */ -static int common_perm_rm(int op, const struct path *dir, +static int common_perm_rm(const char *op, const struct path *dir, struct dentry *dentry, u32 mask) { struct inode *inode = d_backing_inode(dentry); @@ -237,7 +238,7 @@ static int common_perm_rm(int op, const struct path *dir, * * Returns: %0 else error code if error or permission denied */ -static int common_perm_create(int op, const struct path *dir, +static int common_perm_create(const char *op, const struct path *dir, struct dentry *dentry, u32 mask, umode_t mode) { struct path_cond cond = { current_fsuid(), mode }; @@ -395,7 +396,7 @@ static void apparmor_file_free_security(struct file *file) aa_free_file_context(ctx); } -static int common_file_perm(int op, struct file *file, u32 mask) +static int common_file_perm(const char *op, struct file *file, u32 mask) { struct aa_file_ctx *fctx = file->f_security; struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); @@ -438,7 +439,7 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd) return common_file_perm(OP_FLOCK, file, mask); } -static int common_mmap(int op, struct file *file, unsigned long prot, +static int common_mmap(const char *op, struct file *file, unsigned long prot, unsigned long flags) { int mask = 0; diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4ec24474bd1a..17754ee58ff1 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -606,7 +606,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * * Returns: the error to be returned after audit is done */ -static int audit_policy(struct aa_profile *profile, int op, gfp_t gfp, +static int audit_policy(struct aa_profile *profile, const char *op, gfp_t gfp, const char *nsname, const char *name, const char *info, int error) { @@ -670,7 +670,8 @@ bool policy_admin_capable(struct aa_ns *ns) * * Returns: 0 if the task is allowed to manipulate policy else error */ -int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, int op) +int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, + const char *op) { /* check if loading policy is locked out */ if (aa_g_lock_policy) @@ -819,7 +820,7 @@ ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, const char *ns_name, *info = NULL; struct aa_ns *ns = NULL; struct aa_load_ent *ent, *tmp; - int op = OP_PROF_REPL; + const char *op = OP_PROF_REPL; ssize_t count, error; LIST_HEAD(lh); diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index 1babd3655520..4cb5f3dc906d 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -88,13 +88,13 @@ int aa_getprocattr(struct aa_profile *profile, char **string) * * Returns: start position of name after token else NULL on failure */ -static char *split_token_from_name(int op, char *args, u64 * token) +static char *split_token_from_name(const char *op, char *args, u64 *token) { char *name; *token = simple_strtoull(args, &name, 16); if ((name == args) || *name != '^') { - AA_ERROR("%s: Invalid input '%s'", op_table[op], args); + AA_ERROR("%s: Invalid input '%s'", op, args); return ERR_PTR(-EINVAL); } -- cgit v1.2.3 From e025be0f26d5597b0a2bdfa65145a0171e77b614 Mon Sep 17 00:00:00 2001 From: William Hua Date: Sun, 15 Jan 2017 16:49:28 -0800 Subject: apparmor: support querying extended trusted helper extra data Allow a profile to carry extra data that can be queried via userspace. This provides a means to store extra data in a profile that a trusted helper can extract and use from live policy. Signed-off-by: William Hua Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 139 +++++++++++++++++++++++++++++++++++++ security/apparmor/include/policy.h | 16 +++++ security/apparmor/lsm.c | 1 + security/apparmor/policy.c | 23 ++++++ security/apparmor/policy_unpack.c | 66 ++++++++++++++++++ 5 files changed, 245 insertions(+) (limited to 'security/apparmor/include/policy.h') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 7613a28f157e..6834000640d7 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -213,6 +213,144 @@ static const struct file_operations aa_fs_profile_remove = { .llseek = default_llseek, }; +/** + * query_data - queries a policy and writes its data to buf + * @buf: the resulting data is stored here (NOT NULL) + * @buf_len: size of buf + * @query: query string used to retrieve data + * @query_len: size of query including second NUL byte + * + * The buffers pointed to by buf and query may overlap. The query buffer is + * parsed before buf is written to. + * + * The query should look like "