From 17322cc3f9ba578f20b5c09fb1630bd234040008 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 18 Feb 2013 15:59:34 -0800 Subject: apparmor: fix auditing of domain transition failures due to incomplete policy When policy specifies a transition to a profile that is not currently loaded, it result in exec being denied. However the failure is not being audited correctly because the audit code is treating this as an allowed permission and thus not reporting it. Signed-off-by: John Johansen Acked-By: Steve Beattie --- security/apparmor/domain.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'security/apparmor/domain.c') diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 859abdaac1ea..7bc85c7f4573 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -443,6 +443,8 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } else { error = -ENOENT; info = "profile not found"; + /* remove MAY_EXEC to audit as failure */ + perms.allow &= ~MAY_EXEC; } } } else if (COMPLAIN_MODE(profile)) { -- cgit v1.2.3 From 04266236b1c3030bb7f75472ac85a8b78fcfb284 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 18 Feb 2013 16:00:34 -0800 Subject: apparmor: Remove -W1 warnings Signed-off-by: John Johansen Acked-By: Steve Beattie --- security/apparmor/domain.c | 2 -- security/apparmor/lsm.c | 4 ---- 2 files changed, 6 deletions(-) (limited to 'security/apparmor/domain.c') diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 7bc85c7f4573..7a78e814f0d4 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -752,7 +752,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, bool permtest) { const struct cred *cred; - struct aa_task_cxt *cxt; struct aa_profile *profile, *target = NULL; struct aa_namespace *ns = NULL; struct file_perms perms = {}; @@ -772,7 +771,6 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, } cred = get_current_cred(); - cxt = cred->security; profile = aa_cred_profile(cred); /* diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b21830eced41..0f61dadca9e6 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -469,7 +469,6 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd) static int common_mmap(int op, struct file *file, unsigned long prot, unsigned long flags) { - struct dentry *dentry; int mask = 0; if (!file || !file->f_security) @@ -486,7 +485,6 @@ static int common_mmap(int op, struct file *file, unsigned long prot, if (prot & PROT_EXEC) mask |= AA_EXEC_MMAP; - dentry = file->f_path.dentry; return common_file_perm(op, file, mask); } @@ -507,11 +505,9 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, char **value) { int error = -ENOENT; - struct aa_profile *profile; /* released below */ const struct cred *cred = get_task_cred(task); struct aa_task_cxt *cxt = cred->security; - profile = aa_cred_profile(cred); if (strcmp(name, "current") == 0) error = aa_getprocattr(aa_newest_version(cxt->profile), -- cgit v1.2.3 From 3cfcc19e0b5390c04cb5bfa4e8fde39395410e61 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 18 Feb 2013 16:03:34 -0800 Subject: apparmor: add utility function to get an arbitrary tasks profile. Signed-off-by: John Johansen Acked-by: Steve Beattie --- security/apparmor/context.c | 17 +++++++++++++++ security/apparmor/domain.c | 10 +++------ security/apparmor/include/context.h | 41 ++++++++++++++++++++++--------------- security/apparmor/ipc.c | 13 ++++-------- 4 files changed, 49 insertions(+), 32 deletions(-) (limited to 'security/apparmor/domain.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 8a9b5027c813..611e6ce70b03 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -68,6 +68,23 @@ void aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old) aa_get_profile(new->onexec); } +/** + * aa_get_task_profile - Get another task's profile + * @task: task to query (NOT NULL) + * + * Returns: counted reference to @task's profile + */ +struct aa_profile *aa_get_task_profile(struct task_struct *task) +{ + struct aa_profile *p; + + rcu_read_lock(); + p = aa_get_profile(__aa_task_profile(task)); + rcu_read_unlock(); + + return p; +} + /** * aa_replace_current_profile - replace the current tasks profiles * @profile: new profile (NOT NULL) diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 7a78e814f0d4..fb47d5b71ea6 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -62,17 +62,14 @@ static int may_change_ptraced_domain(struct task_struct *task, struct aa_profile *to_profile) { struct task_struct *tracer; - const struct cred *cred = NULL; struct aa_profile *tracerp = NULL; int error = 0; rcu_read_lock(); tracer = ptrace_parent(task); - if (tracer) { + if (tracer) /* released below */ - cred = get_task_cred(tracer); - tracerp = aa_cred_profile(cred); - } + tracerp = aa_get_task_profile(tracer); /* not ptraced */ if (!tracer || unconfined(tracerp)) @@ -82,8 +79,7 @@ static int may_change_ptraced_domain(struct task_struct *task, out: rcu_read_unlock(); - if (cred) - put_cred(cred); + aa_put_profile(tracerp); return error; } diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index a9cbee4d9e48..1e9443a58877 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -80,23 +80,8 @@ 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); -/** - * __aa_task_is_confined - determine if @task has any confinement - * @task: task to check confinement of (NOT NULL) - * - * If @task != current needs to be called in RCU safe critical section - */ -static inline bool __aa_task_is_confined(struct task_struct *task) -{ - struct aa_task_cxt *cxt = __task_cred(task)->security; - - BUG_ON(!cxt || !cxt->profile); - if (unconfined(aa_newest_version(cxt->profile))) - return 0; - - return 1; -} /** * aa_cred_profile - obtain cred's profiles @@ -113,6 +98,30 @@ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) return aa_newest_version(cxt->profile); } +/** + * __aa_task_profile - retrieve another task's profile + * @task: task to query (NOT NULL) + * + * Returns: @task's profile without incrementing its ref count + * + * If @task != current needs to be called in RCU safe critical section + */ +static inline struct aa_profile *__aa_task_profile(struct task_struct *task) +{ + return aa_cred_profile(__task_cred(task)); +} + +/** + * __aa_task_is_confined - determine if @task has any confinement + * @task: task to check confinement of (NOT NULL) + * + * If @task != current needs to be called in RCU safe critical section + */ +static inline bool __aa_task_is_confined(struct task_struct *task) +{ + return !unconfined(__aa_task_profile(task)); +} + /** * __aa_current_profile - find the current tasks confining profile * diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index cf1071b14232..c51d2266587e 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -95,23 +95,18 @@ int aa_ptrace(struct task_struct *tracer, struct task_struct *tracee, * - tracer profile has CAP_SYS_PTRACE */ - struct aa_profile *tracer_p; - /* cred released below */ - const struct cred *cred = get_task_cred(tracer); + struct aa_profile *tracer_p = aa_get_task_profile(tracer); int error = 0; - tracer_p = aa_cred_profile(cred); if (!unconfined(tracer_p)) { - /* lcred released below */ - const struct cred *lcred = get_task_cred(tracee); - struct aa_profile *tracee_p = aa_cred_profile(lcred); + struct aa_profile *tracee_p = aa_get_task_profile(tracee); error = aa_may_ptrace(tracer, tracer_p, tracee_p, mode); error = aa_audit_ptrace(tracer_p, tracee_p, error); - put_cred(lcred); + aa_put_profile(tracee_p); } - put_cred(cred); + aa_put_profile(tracer_p); return error; } -- cgit v1.2.3 From 7a2871b566f34d980556072943295efd107eb53c Mon Sep 17 00:00:00 2001 From: John Johansen Date: Mon, 18 Feb 2013 16:05:34 -0800 Subject: apparmor: use common fn to clear task_context for domain transitions Signed-off-by: John Johansen Acked-by: Steve Beattie --- security/apparmor/context.c | 17 ++++++----------- security/apparmor/domain.c | 6 +----- security/apparmor/include/context.h | 13 +++++++++++++ 3 files changed, 20 insertions(+), 16 deletions(-) (limited to 'security/apparmor/domain.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 611e6ce70b03..3f911afa2bb9 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -105,16 +105,12 @@ int aa_replace_current_profile(struct aa_profile *profile) return -ENOMEM; cxt = new->security; - if (unconfined(profile) || (cxt->profile->ns != profile->ns)) { + if (unconfined(profile) || (cxt->profile->ns != profile->ns)) /* if switching to unconfined or a different profile namespace * clear out context state */ - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); - cxt->previous = NULL; - cxt->onexec = NULL; - cxt->token = 0; - } + aa_clear_task_cxt_trans(cxt); + /* be careful switching cxt->profile, when racing replacement it * is possible that cxt->profile->replacedby is the reference keeping * @profile valid, so make sure to get its reference before dropping @@ -222,11 +218,10 @@ int aa_restore_previous_profile(u64 token) aa_get_profile(cxt->profile); aa_put_profile(cxt->previous); } - /* clear exec && prev information when restoring to previous context */ + /* ref has been transfered so avoid putting ref in clear_task_cxt */ cxt->previous = NULL; - cxt->token = 0; - aa_put_profile(cxt->onexec); - cxt->onexec = NULL; + /* clear exec && prev information when restoring to previous context */ + aa_clear_task_cxt_trans(cxt); commit_creds(new); return 0; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index fb47d5b71ea6..07fcb09b990f 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -512,11 +512,7 @@ x_clear: cxt->profile = new_profile; /* clear out all temporary/transitional state from the context */ - aa_put_profile(cxt->previous); - aa_put_profile(cxt->onexec); - cxt->previous = NULL; - cxt->onexec = NULL; - cxt->token = 0; + aa_clear_task_cxt_trans(cxt); audit: error = aa_audit_file(profile, &perms, GFP_KERNEL, OP_EXEC, MAY_EXEC, diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 1e9443a58877..4cecad313227 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -160,4 +160,17 @@ static inline struct aa_profile *aa_current_profile(void) return profile; } +/** + * aa_clear_task_cxt_trans - clear transition tracking info from the cxt + * @cxt: task context to clear (NOT NULL) + */ +static inline void aa_clear_task_cxt_trans(struct aa_task_cxt *cxt) +{ + aa_put_profile(cxt->previous); + aa_put_profile(cxt->onexec); + cxt->previous = NULL; + cxt->onexec = NULL; + cxt->token = 0; +} + #endif /* __AA_CONTEXT_H */ -- cgit v1.2.3 From 214beacaa7b669473bc963af719fa359a8312ea4 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 27 Feb 2013 03:43:40 -0800 Subject: apparmor: localize getting the security context to a few macros Signed-off-by: John Johansen Acked-by: Seth Arnold --- security/apparmor/context.c | 10 +++++----- security/apparmor/domain.c | 6 +++--- security/apparmor/include/context.h | 7 +++++-- security/apparmor/lsm.c | 22 +++++++++++----------- 4 files changed, 24 insertions(+), 21 deletions(-) (limited to 'security/apparmor/domain.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 3f911afa2bb9..d5af1d15f26d 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -93,7 +93,7 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task) */ int aa_replace_current_profile(struct aa_profile *profile) { - struct aa_task_cxt *cxt = current_cred()->security; + struct aa_task_cxt *cxt = current_cxt(); struct cred *new; BUG_ON(!profile); @@ -104,7 +104,7 @@ int aa_replace_current_profile(struct aa_profile *profile) if (!new) return -ENOMEM; - cxt = new->security; + cxt = cred_cxt(new); if (unconfined(profile) || (cxt->profile->ns != profile->ns)) /* if switching to unconfined or a different profile namespace * clear out context state @@ -136,7 +136,7 @@ int aa_set_current_onexec(struct aa_profile *profile) if (!new) return -ENOMEM; - cxt = new->security; + cxt = cred_cxt(new); aa_get_profile(profile); aa_put_profile(cxt->onexec); cxt->onexec = profile; @@ -163,7 +163,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) return -ENOMEM; BUG_ON(!profile); - cxt = new->security; + cxt = cred_cxt(new); if (!cxt->previous) { /* transfer refcount */ cxt->previous = cxt->profile; @@ -200,7 +200,7 @@ int aa_restore_previous_profile(u64 token) if (!new) return -ENOMEM; - cxt = new->security; + cxt = cred_cxt(new); if (cxt->token != token) { abort_creds(new); return -EACCES; diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 07fcb09b990f..01b7bd669a88 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -356,7 +356,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->cred_prepared) return 0; - cxt = bprm->cred->security; + cxt = cred_cxt(bprm->cred); BUG_ON(!cxt); profile = aa_get_profile(aa_newest_version(cxt->profile)); @@ -551,7 +551,7 @@ int apparmor_bprm_secureexec(struct linux_binprm *bprm) void apparmor_bprm_committing_creds(struct linux_binprm *bprm) { struct aa_profile *profile = __aa_current_profile(); - struct aa_task_cxt *new_cxt = bprm->cred->security; + struct aa_task_cxt *new_cxt = cred_cxt(bprm->cred); /* bail out if unconfined or not changing profile */ if ((new_cxt->profile == profile) || @@ -628,7 +628,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) /* released below */ cred = get_current_cred(); - cxt = cred->security; + cxt = cred_cxt(cred); profile = aa_cred_profile(cred); previous_profile = cxt->previous; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 4cecad313227..d44ba5802e3d 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -21,6 +21,9 @@ #include "policy.h" +#define cred_cxt(X) (X)->security +#define current_cxt() cred_cxt(current_cred()) + /* struct aa_file_cxt - the AppArmor context the file was opened in * @perms: the permission the file was opened with * @@ -93,7 +96,7 @@ struct aa_profile *aa_get_task_profile(struct task_struct *task); */ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) { - struct aa_task_cxt *cxt = cred->security; + struct aa_task_cxt *cxt = cred_cxt(cred); BUG_ON(!cxt || !cxt->profile); return aa_newest_version(cxt->profile); } @@ -145,7 +148,7 @@ static inline struct aa_profile *__aa_current_profile(void) */ static inline struct aa_profile *aa_current_profile(void) { - const struct aa_task_cxt *cxt = current_cred()->security; + const struct aa_task_cxt *cxt = current_cxt(); struct aa_profile *profile; BUG_ON(!cxt || !cxt->profile); diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 10843aa5a368..2027fdf2060b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -48,8 +48,8 @@ int apparmor_initialized __initdata; */ static void apparmor_cred_free(struct cred *cred) { - aa_free_task_context(cred->security); - cred->security = NULL; + aa_free_task_context(cred_cxt(cred)); + cred_cxt(cred) = NULL; } /* @@ -62,7 +62,7 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) if (!cxt) return -ENOMEM; - cred->security = cxt; + cred_cxt(cred) = cxt; return 0; } @@ -77,8 +77,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, if (!cxt) return -ENOMEM; - aa_dup_task_context(cxt, old->security); - new->security = cxt; + aa_dup_task_context(cxt, cred_cxt(old)); + cred_cxt(new) = cxt; return 0; } @@ -87,8 +87,8 @@ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, */ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) { - const struct aa_task_cxt *old_cxt = old->security; - struct aa_task_cxt *new_cxt = new->security; + const struct aa_task_cxt *old_cxt = cred_cxt(old); + struct aa_task_cxt *new_cxt = cred_cxt(new); aa_dup_task_context(new_cxt, old_cxt); } @@ -507,7 +507,7 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, int error = -ENOENT; /* released below */ const struct cred *cred = get_task_cred(task); - struct aa_task_cxt *cxt = cred->security; + struct aa_task_cxt *cxt = cred_cxt(cred); if (strcmp(name, "current") == 0) error = aa_getprocattr(aa_newest_version(cxt->profile), @@ -880,7 +880,7 @@ static int __init set_init_cxt(void) return -ENOMEM; cxt->profile = aa_get_profile(root_ns->unconfined); - cred->security = cxt; + cred_cxt(cred) = cxt; return 0; } @@ -910,8 +910,8 @@ static int __init apparmor_init(void) error = register_security(&apparmor_ops); if (error) { struct cred *cred = (struct cred *)current->real_cred; - aa_free_task_context(cred->security); - cred->security = NULL; + aa_free_task_context(cred_cxt(cred)); + cred_cxt(cred) = NULL; AA_ERROR("Unable to register AppArmor\n"); goto register_security_out; } -- cgit v1.2.3