diff options
author | John Johansen <john.johansen@canonical.com> | 2017-06-09 18:14:28 +0300 |
---|---|---|
committer | John Johansen <john.johansen@canonical.com> | 2017-06-11 03:11:38 +0300 |
commit | 637f688dc3dc304a89f441d76f49a0e35bc49c08 (patch) | |
tree | 78fee8a7aa212140c4c6b6a9b722bbba61802cab /security/apparmor/include | |
parent | f1bd904175e8190ce14aedee37e207ab51fe3b30 (diff) | |
download | linux-637f688dc3dc304a89f441d76f49a0e35bc49c08.tar.xz |
apparmor: switch from profiles to using labels on contexts
Begin the actual switch to using domain labels by storing them on
the context and converting the label to a singular profile where
possible.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security/apparmor/include')
-rw-r--r-- | security/apparmor/include/apparmor.h | 5 | ||||
-rw-r--r-- | security/apparmor/include/audit.h | 9 | ||||
-rw-r--r-- | security/apparmor/include/context.h | 158 | ||||
-rw-r--r-- | security/apparmor/include/perms.h | 12 | ||||
-rw-r--r-- | security/apparmor/include/policy.h | 110 | ||||
-rw-r--r-- | security/apparmor/include/policy_ns.h | 4 |
6 files changed, 132 insertions, 166 deletions
diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 1750cc0721c1..c4a900488e76 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -4,7 +4,7 @@ * This file contains AppArmor basic global * * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 Canonical Ltd. + * 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 @@ -27,8 +27,9 @@ #define AA_CLASS_NET 4 #define AA_CLASS_RLIMITS 5 #define AA_CLASS_DOMAIN 6 +#define AA_CLASS_LABEL 16 -#define AA_CLASS_LAST AA_CLASS_DOMAIN +#define AA_CLASS_LAST AA_CLASS_LABEL /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index d548261dd1b7..20fa6c77db05 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -22,8 +22,7 @@ #include <linux/slab.h> #include "file.h" - -struct aa_profile; +#include "label.h" extern const char *const audit_mode_names[]; #define AUDIT_MAX_INDEX 5 @@ -103,9 +102,9 @@ enum audit_type { struct apparmor_audit_data { int error; - const char *op; int type; - void *profile; + const char *op; + struct aa_label *label; const char *name; const char *info; u32 request; @@ -113,7 +112,7 @@ struct apparmor_audit_data { union { /* these entries require a custom callback fn */ struct { - struct aa_profile *peer; + struct aa_label *peer; struct { const char *target; kuid_t ouid; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 7665fae7131f..6ae07e9aaa17 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <linux/sched.h> -#include "policy.h" +#include "label.h" #include "policy_ns.h" #define cred_ctx(X) ((X)->security) @@ -27,20 +27,20 @@ /** * struct aa_task_ctx - primary label for confined tasks - * @profile: the current profile (NOT NULL) - * @exec: profile to transition to on next exec (MAYBE NULL) - * @previous: profile the task may return to (MAYBE NULL) - * @token: magic value the task must know for returning to @previous_profile + * @label: the current label (NOT NULL) + * @exec: label to transition to on next exec (MAYBE NULL) + * @previous: label the task may return to (MAYBE NULL) + * @token: magic value the task must know for returning to @previous * - * Contains the task's current profile (which could change due to + * Contains the task's current label (which could change due to * change_hat). Plus the hat_magic needed during change_hat. * * TODO: make so a task can be confined by a stack of contexts */ struct aa_task_ctx { - struct aa_profile *profile; - struct aa_profile *onexec; - struct aa_profile *previous; + struct aa_label *label; + struct aa_label *onexec; + struct aa_label *previous; u64 token; }; @@ -48,52 +48,51 @@ struct aa_task_ctx *aa_alloc_task_context(gfp_t flags); void aa_free_task_context(struct aa_task_ctx *ctx); void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old); -int aa_replace_current_profile(struct aa_profile *profile); -int aa_set_current_onexec(struct aa_profile *profile); -int aa_set_current_hat(struct aa_profile *profile, u64 token); -int aa_restore_previous_profile(u64 cookie); -struct aa_profile *aa_get_task_profile(struct task_struct *task); +int aa_replace_current_label(struct aa_label *label); +int aa_set_current_onexec(struct aa_label *label, bool stack); +int aa_set_current_hat(struct aa_label *label, u64 token); +int aa_restore_previous_label(u64 cookie); +struct aa_label *aa_get_task_label(struct task_struct *task); /** - * aa_cred_raw_profile - obtain cred's profiles - * @cred: cred to obtain profiles from (NOT NULL) + * aa_cred_raw_label - obtain cred's label + * @cred: cred to obtain label from (NOT NULL) * - * Returns: confining profile + * Returns: confining label * * does NOT increment reference count */ -static inline struct aa_profile *aa_cred_raw_profile(const struct cred *cred) +static inline struct aa_label *aa_cred_raw_label(const struct cred *cred) { struct aa_task_ctx *ctx = cred_ctx(cred); - AA_BUG(!ctx || !ctx->profile); - return ctx->profile; + AA_BUG(!ctx || !ctx->label); + return ctx->label; } /** - * aa_get_newest_cred_profile - obtain the newest profile on a cred - * @cred: cred to obtain profile from (NOT NULL) + * aa_get_newest_cred_label - obtain the newest label on a cred + * @cred: cred to obtain label from (NOT NULL) * - * Returns: newest version of confining profile + * Returns: newest version of confining label */ -static inline -struct aa_profile *aa_get_newest_cred_profile(const struct cred *cred) +static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) { - return aa_get_newest_profile(aa_cred_raw_profile(cred)); + return aa_get_newest_label(aa_cred_raw_label(cred)); } /** - * __aa_task_raw_profile - retrieve another task's profile + * __aa_task_raw_label - retrieve another task's label * @task: task to query (NOT NULL) * - * Returns: @task's profile without incrementing its ref count + * Returns: @task's label without incrementing its ref count * * If @task != current needs to be called in RCU safe critical section */ -static inline struct aa_profile *__aa_task_raw_profile(struct task_struct *task) +static inline struct aa_label *__aa_task_raw_label(struct task_struct *task) { - return aa_cred_raw_profile(__task_cred(task)); + return aa_cred_raw_label(__task_cred(task)); } /** @@ -104,113 +103,112 @@ static inline struct aa_profile *__aa_task_raw_profile(struct task_struct *task) */ static inline bool __aa_task_is_confined(struct task_struct *task) { - return !unconfined(__aa_task_raw_profile(task)); + return !unconfined(__aa_task_raw_label(task)); } /** - * aa_current_raw_profile - find the current tasks confining profile + * aa_current_raw_label - find the current tasks confining label * - * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) + * Returns: up to date confining label or the ns unconfined label (NOT NULL) * * This fn will not update the tasks cred to the most up to date version - * of the profile so it is safe to call when inside of locks. + * of the label so it is safe to call when inside of locks. */ -static inline struct aa_profile *aa_current_raw_profile(void) +static inline struct aa_label *aa_current_raw_label(void) { - return aa_cred_raw_profile(current_cred()); + return aa_cred_raw_label(current_cred()); } /** - * aa_get_current_profile - get the newest version of the current tasks profile + * aa_get_current_label - get the newest version of the current tasks label * - * Returns: newest version of confining profile (NOT NULL) + * Returns: newest version of confining label (NOT NULL) * * This fn will not update the tasks cred, so it is safe inside of locks * - * The returned reference must be put with aa_put_profile() + * The returned reference must be put with aa_put_label() */ -static inline struct aa_profile *aa_get_current_profile(void) +static inline struct aa_label *aa_get_current_label(void) { - struct aa_profile *p = aa_current_raw_profile(); + struct aa_label *l = aa_current_raw_label(); - if (profile_is_stale(p)) - return aa_get_newest_profile(p); - return aa_get_profile(p); + if (label_is_stale(l)) + return aa_get_newest_label(l); + return aa_get_label(l); } -#define __end_current_profile_crit_section(X) \ - end_current_profile_crit_section(X) +#define __end_current_label_crit_section(X) end_current_label_crit_section(X) /** - * end_profile_crit_section - put a reference found with begin_current_profile.. - * @profile: profile reference to put + * end_label_crit_section - put a reference found with begin_current_label.. + * @label: label reference to put * * Should only be used with a reference obtained with - * begin_current_profile_crit_section and never used in situations where the + * begin_current_label_crit_section and never used in situations where the * task cred may be updated */ -static inline void end_current_profile_crit_section(struct aa_profile *profile) +static inline void end_current_label_crit_section(struct aa_label *label) { - if (profile != aa_current_raw_profile()) - aa_put_profile(profile); + if (label != aa_current_raw_label()) + aa_put_label(label); } /** - * __begin_current_profile_crit_section - current's confining profile + * __begin_current_label_crit_section - current's confining label * - * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) + * Returns: up to date confining label or the ns unconfined label (NOT NULL) * * safe to call inside locks * - * The returned reference must be put with __end_current_profile_crit_section() + * The returned reference must be put with __end_current_label_crit_section() * This must NOT be used if the task cred could be updated within the - * critical section between __begin_current_profile_crit_section() .. - * __end_current_profile_crit_section() + * critical section between __begin_current_label_crit_section() .. + * __end_current_label_crit_section() */ -static inline struct aa_profile *__begin_current_profile_crit_section(void) +static inline struct aa_label *__begin_current_label_crit_section(void) { - struct aa_profile *profile = aa_current_raw_profile(); + struct aa_label *label = aa_current_raw_label(); - if (profile_is_stale(profile)) - profile = aa_get_newest_profile(profile); + if (label_is_stale(label)) + label = aa_get_newest_label(label); - return profile; + return label; } /** - * begin_current_profile_crit_section - current's profile and update if needed + * begin_current_label_crit_section - current's confining label and update it * - * Returns: up to date confining profile or the ns unconfined profile (NOT NULL) + * Returns: up to date confining label or the ns unconfined label (NOT NULL) * * Not safe to call inside locks * - * The returned reference must be put with end_current_profile_crit_section() + * The returned reference must be put with end_current_label_crit_section() * This must NOT be used if the task cred could be updated within the - * critical section between begin_current_profile_crit_section() .. - * end_current_profile_crit_section() + * critical section between begin_current_label_crit_section() .. + * end_current_label_crit_section() */ -static inline struct aa_profile *begin_current_profile_crit_section(void) +static inline struct aa_label *begin_current_label_crit_section(void) { - struct aa_profile *profile = aa_current_raw_profile(); + struct aa_label *label = aa_current_raw_label(); - if (profile_is_stale(profile)) { - profile = aa_get_newest_profile(profile); - if (aa_replace_current_profile(profile) == 0) + if (label_is_stale(label)) { + label = aa_get_newest_label(label); + if (aa_replace_current_label(label) == 0) /* task cred will keep the reference */ - aa_put_profile(profile); + aa_put_label(label); } - return profile; + return label; } static inline struct aa_ns *aa_get_current_ns(void) { - struct aa_profile *profile; + struct aa_label *label; struct aa_ns *ns; - profile = __begin_current_profile_crit_section(); - ns = aa_get_ns(profile->ns); - __end_current_profile_crit_section(profile); + label = __begin_current_label_crit_section(); + ns = aa_get_ns(labels_ns(label)); + __end_current_label_crit_section(label); return ns; } @@ -221,8 +219,8 @@ static inline struct aa_ns *aa_get_current_ns(void) */ static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) { - aa_put_profile(ctx->previous); - aa_put_profile(ctx->onexec); + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); ctx->previous = NULL; ctx->onexec = NULL; ctx->token = 0; diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 82946fb81f91..0c5c2b00be02 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -15,6 +15,7 @@ #define __AA_PERM_H #include <linux/fs.h> +#include "label.h" #define AA_MAY_EXEC MAY_EXEC #define AA_MAY_WRITE MAY_WRITE @@ -101,5 +102,14 @@ void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms); void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, struct aa_perms *perms); - +void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend); +void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend); +void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, + int type, u32 request, struct aa_perms *perms); +int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, + u32 request, int type, u32 *deny, + struct common_audit_data *sa); +int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, + u32 request, struct common_audit_data *sa, + void (*cb)(struct audit_buffer *, void *)); #endif /* __AA_PERM_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index d93f475bfd8b..17fe41a9cac3 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -29,6 +29,7 @@ #include "domain.h" #include "file.h" #include "lib.h" +#include "label.h" #include "perms.h" #include "resource.h" @@ -48,9 +49,9 @@ extern const char *const aa_profile_mode_names[]; #define KILL_MODE(_profile) PROFILE_MODE((_profile), APPARMOR_KILL) -#define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) +#define PROFILE_IS_HAT(_profile) ((_profile)->label.flags & FLAG_HAT) -#define profile_is_stale(_profile) ((_profile)->flags & PFLAG_STALE) +#define profile_is_stale(_profile) (label_is_stale(&(_profile)->label)) #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) @@ -67,22 +68,6 @@ enum profile_mode { APPARMOR_UNCONFINED, /* profile set to unconfined */ }; -enum profile_flags { - PFLAG_HAT = 1, /* profile is a hat */ - PFLAG_NULL = 4, /* profile is null learning profile */ - PFLAG_IX_ON_NAME_ERROR = 8, /* fallback to ix on name lookup fail */ - PFLAG_IMMUTABLE = 0x10, /* don't allow changes/replacement */ - 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_STALE = 0x200, /* profile replaced/removed */ - PFLAG_NS_COUNT = 0x400, /* carries NS ref count */ - - /* These flags must correspond with PATH_flags */ - PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ -}; - -struct aa_profile; /* struct aa_policydb - match engine for a policy * dfa: dfa pattern match @@ -95,11 +80,6 @@ struct aa_policydb { }; -struct aa_proxy { - struct kref count; - struct aa_profile __rcu *profile; -}; - /* struct aa_data - generic data structure * key: name for retrieving this data * size: size of data in bytes @@ -116,18 +96,15 @@ struct aa_data { /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) - * @count: reference count of the obj - * @rcu: rcu head used when removing from @list + * @label - label this profile is an extension of * @parent: parent of profile * @ns: namespace the profile is in - * @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 * @xmatch_len: xmatch prefix len, used to determine xmatch priority * @audit: the auditing mode of the profile * @mode: the enforcement mode of the profile - * @flags: flags controlling profile behavior * @path_flags: flags controlling path generation behavior * @disconnected: what to prepend if attach_disconnected is specified * @size: the memory consumed by this profiles rules @@ -145,8 +122,6 @@ struct aa_data { * used to determine profile attachment against unconfined tasks. All other * attachments are determined by profile X transition rules. * - * 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. * @@ -156,12 +131,9 @@ struct aa_data { */ struct aa_profile { struct aa_policy base; - struct kref count; - struct rcu_head rcu; struct aa_profile __rcu *parent; struct aa_ns *ns; - struct aa_proxy *proxy; const char *rename; const char *attach; @@ -169,7 +141,6 @@ struct aa_profile { int xmatch_len; enum audit_mode audit; long mode; - long flags; u32 path_flags; const char *disconnected; int size; @@ -184,6 +155,7 @@ struct aa_profile { char *dirname; struct dentry *dents[AAFS_PROF_SIZEOF]; struct rhashtable *data; + struct aa_label label; }; extern enum profile_mode aa_g_profile_mode; @@ -192,13 +164,15 @@ extern enum profile_mode aa_g_profile_mode; #define AA_MAY_REPLACE_POLICY AA_MAY_WRITE #define AA_MAY_REMOVE_POLICY AA_MAY_DELETE -void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); +#define profiles_ns(P) ((P)->ns) +#define name_is_shared(A, B) ((A)->hname && (A)->hname == (B)->hname) 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_alloc_profile(const char *name, struct aa_proxy *proxy, + gfp_t gfp); 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); @@ -207,20 +181,33 @@ 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, +struct aa_profile *aa_fqlookupn_profile(struct aa_label *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, struct aa_profile *profile, +ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_label *label, u32 mask, struct aa_loaddata *udata); -ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, - char *name, size_t size); +ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_label *label, + char *name, size_t size); void __aa_profile_list_release(struct list_head *head); #define PROF_ADD 1 #define PROF_REPLACE 0 -#define unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) +#define profile_unconfined(X) ((X)->mode == APPARMOR_UNCONFINED) + +/** + * aa_get_newest_profile - simple wrapper fn to wrap the label version + * @p: profile (NOT NULL) + * + * Returns refcount to newest version of the profile (maybe @p) + * + * Requires: @p must be held with a valid refcount + */ +static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) +{ + return labels_profile(aa_get_newest_label(&p->label)); +} #define PROFILE_MEDIATES(P, T) ((P)->policy.start[(T)]) /* safe version of POLICY_MEDIATES for full range input */ @@ -243,7 +230,7 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, static inline struct aa_profile *aa_get_profile(struct aa_profile *p) { if (p) - kref_get(&(p->count)); + kref_get(&(p->label.count)); return p; } @@ -257,7 +244,7 @@ static inline struct aa_profile *aa_get_profile(struct aa_profile *p) */ static inline struct aa_profile *aa_get_profile_not0(struct aa_profile *p) { - if (p && kref_get_unless_zero(&p->count)) + if (p && kref_get_unless_zero(&p->label.count)) return p; return NULL; @@ -277,53 +264,20 @@ static inline struct aa_profile *aa_get_profile_rcu(struct aa_profile __rcu **p) rcu_read_lock(); do { c = rcu_dereference(*p); - } while (c && !kref_get_unless_zero(&c->count)); + } while (c && !kref_get_unless_zero(&c->label.count)); rcu_read_unlock(); return c; } /** - * aa_get_newest_profile - find the newest version of @profile - * @profile: the profile to check for newer versions of - * - * Returns: refcounted newest version of @profile taking into account - * replacement, renames and removals - * return @profile. - */ -static inline struct aa_profile *aa_get_newest_profile(struct aa_profile *p) -{ - if (!p) - return NULL; - - if (profile_is_stale(p)) - return aa_get_profile_rcu(&p->proxy->profile); - - return aa_get_profile(p); -} - -/** * aa_put_profile - decrement refcount on profile @p * @p: profile (MAYBE NULL) */ static inline void aa_put_profile(struct aa_profile *p) { if (p) - kref_put(&p->count, aa_free_profile_kref); -} - -static inline struct aa_proxy *aa_get_proxy(struct aa_proxy *p) -{ - if (p) - kref_get(&(p->count)); - - return p; -} - -static inline void aa_put_proxy(struct aa_proxy *p) -{ - if (p) - kref_put(&p->count, aa_free_proxy_kref); + kref_put(&p->label.count, aa_label_kref); } static inline int AUDIT_MODE(struct aa_profile *profile) @@ -336,7 +290,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 aa_may_manage_policy(struct aa_label *label, struct aa_ns *ns, u32 mask); #endif /* __AA_POLICY_H */ diff --git a/security/apparmor/include/policy_ns.h b/security/apparmor/include/policy_ns.h index 2f7e480a34e0..9605f18624e2 100644 --- a/security/apparmor/include/policy_ns.h +++ b/security/apparmor/include/policy_ns.h @@ -19,6 +19,7 @@ #include "apparmor.h" #include "apparmorfs.h" +#include "label.h" #include "policy.h" @@ -71,6 +72,7 @@ struct aa_ns { long revision; wait_queue_head_t wait; + struct aa_labelset labels; struct list_head rawdata_list; struct dentry *dents[AAFS_NS_SIZEOF]; @@ -80,6 +82,8 @@ extern struct aa_ns *root_ns; extern const char *aa_hidden_ns_name; +#define ns_unconfined(NS) (&(NS)->unconfined->label) + bool aa_ns_visible(struct aa_ns *curr, struct aa_ns *view, bool subns); const char *aa_ns_name(struct aa_ns *parent, struct aa_ns *child, bool subns); void aa_free_ns(struct aa_ns *ns); |