From 4d2f8ba3e3b76e34f84ae1de456934713e9e59af Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 19 Jan 2017 14:08:36 -0800 Subject: apparmor: rename task_ctx to the more accurate cred_ctx Signed-off-by: John Johansen --- security/apparmor/lsm.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 9a65eeaf7dfa..0624eb2081f3 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -51,11 +51,11 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers); */ /* - * free the associated aa_task_ctx and put its labels + * free the associated aa_cred_ctx and put its labels */ static void apparmor_cred_free(struct cred *cred) { - aa_free_task_context(cred_ctx(cred)); + aa_free_cred_ctx(cred_ctx(cred)); cred_ctx(cred) = NULL; } @@ -65,7 +65,7 @@ static void apparmor_cred_free(struct cred *cred) static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) { /* freed by apparmor_cred_free */ - struct aa_task_ctx *ctx = aa_alloc_task_context(gfp); + struct aa_cred_ctx *ctx = aa_alloc_cred_ctx(gfp); if (!ctx) return -ENOMEM; @@ -75,18 +75,18 @@ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) } /* - * prepare new aa_task_ctx for modification by prepare_cred block + * prepare new aa_cred_ctx for modification by prepare_cred block */ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { /* freed by apparmor_cred_free */ - struct aa_task_ctx *ctx = aa_alloc_task_context(gfp); + struct aa_cred_ctx *ctx = aa_alloc_cred_ctx(gfp); if (!ctx) return -ENOMEM; - aa_dup_task_context(ctx, cred_ctx(old)); + aa_dup_cred_ctx(ctx, cred_ctx(old)); cred_ctx(new) = ctx; return 0; } @@ -96,10 +96,10 @@ 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_ctx *old_ctx = cred_ctx(old); - struct aa_task_ctx *new_ctx = cred_ctx(new); + const struct aa_cred_ctx *old_ctx = cred_ctx(old); + struct aa_cred_ctx *new_ctx = cred_ctx(new); - aa_dup_task_context(new_ctx, old_ctx); + aa_dup_cred_ctx(new_ctx, old_ctx); } static int apparmor_ptrace_access_check(struct task_struct *child, @@ -577,7 +577,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_ctx *ctx = cred_ctx(cred); + struct aa_cred_ctx *ctx = cred_ctx(cred); struct aa_label *label = NULL; if (strcmp(name, "current") == 0) @@ -678,7 +678,7 @@ fail: static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) { struct aa_label *label = aa_current_raw_label(); - struct aa_task_ctx *new_ctx = cred_ctx(bprm->cred); + struct aa_cred_ctx *new_ctx = cred_ctx(bprm->cred); /* bail out if unconfined or not changing profile */ if ((new_ctx->label->proxy == label->proxy) || @@ -1024,9 +1024,9 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; - struct aa_task_ctx *ctx; + struct aa_cred_ctx *ctx; - ctx = aa_alloc_task_context(GFP_KERNEL); + ctx = aa_alloc_cred_ctx(GFP_KERNEL); if (!ctx) return -ENOMEM; -- cgit v1.2.3 From 3b529a7600d834f450ac244f43a7c082687284b4 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 20 Jan 2017 01:59:25 -0800 Subject: apparmor: move task domain change info to task security The task domain change info is task specific and its and abuse of the cred to store the information in there. Now that a task->security field exists store it in the proper place. Signed-off-by: John Johansen --- security/apparmor/context.c | 91 +++++++++++++++++++++++++------------ security/apparmor/domain.c | 14 +++--- security/apparmor/include/context.h | 31 +++++++++---- security/apparmor/lsm.c | 48 ++++++++++++++++--- 4 files changed, 132 insertions(+), 52 deletions(-) (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 89c03053303e..432672b18945 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -48,8 +48,6 @@ void aa_free_cred_ctx(struct aa_cred_ctx *ctx) { if (ctx) { aa_put_label(ctx->label); - aa_put_label(ctx->previous); - aa_put_label(ctx->onexec); kzfree(ctx); } @@ -64,8 +62,6 @@ void aa_dup_cred_ctx(struct aa_cred_ctx *new, const struct aa_cred_ctx *old) { *new = *old; aa_get_label(new->label); - aa_get_label(new->previous); - aa_get_label(new->onexec); } /** @@ -85,6 +81,43 @@ struct aa_label *aa_get_task_label(struct task_struct *task) return p; } +/** + * aa_alloc_task_ctx - allocate a new task_ctx + * @flags: gfp flags for allocation + * + * Returns: allocated buffer or NULL on failure + */ +struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) +{ + return kzalloc(sizeof(struct aa_task_ctx), flags); +} + +/** + * aa_free_task_ctx - free a task_ctx + * @ctx: task_ctx to free (MAYBE NULL) + */ +void aa_free_task_ctx(struct aa_task_ctx *ctx) +{ + if (ctx) { + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); + + kzfree(ctx); + } +} + +/** + * aa_dup_task_ctx - duplicate a task context, incrementing reference counts + * @new: a blank task context (NOT NULL) + * @old: the task context to copy (NOT NULL) + */ +void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old) +{ + *new = *old; + aa_get_label(new->previous); + aa_get_label(new->onexec); +} + /** * aa_replace_current_label - replace the current tasks label * @label: new label (NOT NULL) @@ -112,7 +145,7 @@ int aa_replace_current_label(struct aa_label *label) /* if switching to unconfined or a different label namespace * clear out context state */ - aa_clear_cred_ctx_trans(ctx); + aa_clear_task_ctx_trans(current_task_ctx()); /* * be careful switching ctx->profile, when racing replacement it @@ -136,18 +169,13 @@ int aa_replace_current_label(struct aa_label *label) */ int aa_set_current_onexec(struct aa_label *label, bool stack) { - struct aa_cred_ctx *ctx; - struct cred *new = prepare_creds(); - if (!new) - return -ENOMEM; + struct aa_task_ctx *ctx = current_task_ctx(); - ctx = cred_ctx(new); aa_get_label(label); - aa_clear_cred_ctx_trans(ctx); + aa_put_label(ctx->onexec); ctx->onexec = label; ctx->token = stack; - commit_creds(new); return 0; } @@ -163,28 +191,31 @@ int aa_set_current_onexec(struct aa_label *label, bool stack) */ int aa_set_current_hat(struct aa_label *label, u64 token) { + struct aa_task_ctx *tctx = current_task_ctx(); struct aa_cred_ctx *ctx; struct cred *new = prepare_creds(); + if (!new) return -ENOMEM; AA_BUG(!label); ctx = cred_ctx(new); - if (!ctx->previous) { + if (!tctx->previous) { /* transfer refcount */ - ctx->previous = ctx->label; - ctx->token = token; - } else if (ctx->token == token) { + tctx->previous = ctx->label; + tctx->token = token; + } else if (tctx->token == token) { aa_put_label(ctx->label); } else { /* previous_profile && ctx->token != token */ abort_creds(new); return -EACCES; } + ctx->label = aa_get_newest_label(label); /* clear exec on switching context */ - aa_put_label(ctx->onexec); - ctx->onexec = NULL; + aa_put_label(tctx->onexec); + tctx->onexec = NULL; commit_creds(new); return 0; @@ -201,28 +232,28 @@ int aa_set_current_hat(struct aa_label *label, u64 token) */ int aa_restore_previous_label(u64 token) { + struct aa_task_ctx *tctx = current_task_ctx(); struct aa_cred_ctx *ctx; - struct cred *new = prepare_creds(); - if (!new) - return -ENOMEM; + struct cred *new; - ctx = cred_ctx(new); - if (ctx->token != token) { - abort_creds(new); + if (tctx->token != token) return -EACCES; - } /* ignore restores when there is no saved label */ - if (!ctx->previous) { - abort_creds(new); + if (!tctx->previous) return 0; - } + + new = prepare_creds(); + if (!new) + return -ENOMEM; + ctx = cred_ctx(new); aa_put_label(ctx->label); - ctx->label = aa_get_newest_label(ctx->previous); + ctx->label = aa_get_newest_label(tctx->previous); AA_BUG(!ctx->label); /* clear exec && prev information when restoring to previous context */ - aa_clear_cred_ctx_trans(ctx); + aa_clear_task_ctx_trans(tctx); commit_creds(new); + return 0; } diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 90967de96be0..b90759a765b5 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -780,6 +780,7 @@ static struct aa_label *handle_onexec(struct aa_label *label, int apparmor_bprm_set_creds(struct linux_binprm *bprm) { struct aa_cred_ctx *ctx; + struct aa_task_ctx *tctx; struct aa_label *label, *new = NULL; struct aa_profile *profile; char *buffer = NULL; @@ -795,15 +796,17 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) return 0; ctx = cred_ctx(bprm->cred); + tctx = current_task_ctx(); AA_BUG(!ctx); + AA_BUG(!tctx); label = aa_get_newest_label(ctx->label); /* buffer freed below, name is pointer into buffer */ get_buffers(buffer); /* Test for onexec first as onexec override other x transitions. */ - if (ctx->onexec) - new = handle_onexec(label, ctx->onexec, ctx->token, + if (tctx->onexec) + new = handle_onexec(label, tctx->onexec, tctx->token, bprm, buffer, &cond, &unsafe); else new = fn_label_build(label, profile, GFP_ATOMIC, @@ -858,9 +861,6 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) ctx->label = new; done: - /* clear out temporary/transitional state from the context */ - aa_clear_cred_ctx_trans(ctx); - aa_put_label(label); put_buffers(buffer); @@ -1050,6 +1050,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) { const struct cred *cred; struct aa_cred_ctx *ctx; + struct aa_task_ctx *tctx; struct aa_label *label, *previous, *new = NULL, *target = NULL; struct aa_profile *profile; struct aa_perms perms = {}; @@ -1070,8 +1071,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* released below */ cred = get_current_cred(); ctx = cred_ctx(cred); + tctx = current_task_ctx(); label = aa_get_newest_cred_label(cred); - previous = aa_get_newest_label(ctx->previous); + previous = aa_get_newest_label(tctx->previous); if (unconfined(label)) { info = "unconfined can not change_hat"; diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index 0622fcf2a695..c3b51d88275b 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -25,20 +25,24 @@ #define cred_ctx(X) ((X)->security) #define current_cred_ctx() cred_ctx(current_cred()) +#define task_ctx(X) ((X)->security) +#define current_task_ctx() (task_ctx(current)) + /** * struct aa_cred_ctx - primary label for confined tasks * @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 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_cred_ctx { struct aa_label *label; +}; + +/** + * struct aa_task_ctx - information for current task label change + * @onexec: profile to transition to on next exec (MAY BE NULL) + * @previous: profile the task may return to (MAY BE NULL) + * @token: magic value the task must know for returning to @previous_profile + */ +struct aa_task_ctx { struct aa_label *onexec; struct aa_label *previous; u64 token; @@ -47,6 +51,11 @@ struct aa_cred_ctx { struct aa_cred_ctx *aa_alloc_cred_ctx(gfp_t flags); void aa_free_cred_ctx(struct aa_cred_ctx *ctx); void aa_dup_cred_ctx(struct aa_cred_ctx *new, const struct aa_cred_ctx *old); + +struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags); +void aa_free_task_ctx(struct aa_task_ctx *ctx); +void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old); + 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); @@ -213,11 +222,13 @@ static inline struct aa_ns *aa_get_current_ns(void) } /** - * aa_clear_cred_ctx_trans - clear transition tracking info from the ctx + * aa_clear_task_ctx_trans - clear transition tracking info from the ctx * @ctx: task context to clear (NOT NULL) */ -static inline void aa_clear_cred_ctx_trans(struct aa_cred_ctx *ctx) +static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) { + AA_BUG(!ctx); + aa_put_label(ctx->previous); aa_put_label(ctx->onexec); ctx->previous = NULL; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 0624eb2081f3..a1d63d93b862 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -102,6 +102,27 @@ static void apparmor_cred_transfer(struct cred *new, const struct cred *old) aa_dup_cred_ctx(new_ctx, old_ctx); } +static void apparmor_task_free(struct task_struct *task) +{ + + aa_free_task_ctx(task_ctx(task)); + task_ctx(task) = NULL; +} + +static int apparmor_task_alloc(struct task_struct *task, + unsigned long clone_flags) +{ + struct aa_task_ctx *new = aa_alloc_task_ctx(GFP_KERNEL); + + if (!new) + return -ENOMEM; + + aa_dup_task_ctx(new, current_task_ctx()); + task_ctx(task) = new; + + return 0; +} + static int apparmor_ptrace_access_check(struct task_struct *child, unsigned int mode) { @@ -577,15 +598,16 @@ 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_ctx *tctx = current_task_ctx(); struct aa_cred_ctx *ctx = cred_ctx(cred); struct aa_label *label = NULL; if (strcmp(name, "current") == 0) label = aa_get_newest_label(ctx->label); - else if (strcmp(name, "prev") == 0 && ctx->previous) - label = aa_get_newest_label(ctx->previous); - else if (strcmp(name, "exec") == 0 && ctx->onexec) - label = aa_get_newest_label(ctx->onexec); + else if (strcmp(name, "prev") == 0 && tctx->previous) + label = aa_get_newest_label(tctx->previous); + else if (strcmp(name, "exec") == 0 && tctx->onexec) + label = aa_get_newest_label(tctx->onexec); else error = -EINVAL; @@ -699,7 +721,9 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) */ static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) { - /* TODO: cleanup signals - ipc mediation */ + /* clear out temporary/transitional state from the context */ + aa_clear_task_ctx_trans(current_task_ctx()); + return; } @@ -779,6 +803,8 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), + LSM_HOOK_INIT(task_free, apparmor_task_free), + LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), LSM_HOOK_INIT(task_kill, apparmor_task_kill), }; @@ -1025,15 +1051,25 @@ static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; struct aa_cred_ctx *ctx; + struct aa_task_ctx *tctx; ctx = aa_alloc_cred_ctx(GFP_KERNEL); if (!ctx) - return -ENOMEM; + goto fail_cred; + tctx = aa_alloc_task_ctx(GFP_KERNEL); + if (!tctx) + goto fail_task; ctx->label = aa_get_label(ns_unconfined(root_ns)); cred_ctx(cred) = ctx; + task_ctx(current) = tctx; return 0; + +fail_task: + aa_free_cred_ctx(ctx); +fail_cred: + return -ENOMEM; } static void destroy_buffers(void) -- cgit v1.2.3 From d9087c49d4388e3f35f09a5cf7ed6e09c9106604 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 27 Jan 2017 03:53:53 -0800 Subject: apparmor: drop cred_ctx and reference the label directly With the task domain change information now stored in the task->security context, the cred->security context only stores the label. We can get rid of the cred_ctx and directly reference the label, removing a layer of indirection, and unneeded extra allocations. Signed-off-by: John Johansen --- security/apparmor/context.c | 83 ++++++++++--------------------------- security/apparmor/domain.c | 14 +++---- security/apparmor/include/context.h | 24 +++-------- security/apparmor/lsm.c | 55 +++++++----------------- 4 files changed, 47 insertions(+), 129 deletions(-) (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 432672b18945..70e4a094add8 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -13,11 +13,9 @@ * License. * * - * AppArmor sets confinement on every task, via the the aa_cred_ctx and - * the aa_cred_ctx.label, both of which are required and are not allowed - * to be NULL. The aa_cred_ctx is not reference counted and is unique - * to each cred (which is reference count). The label pointed to by - * the cred_ctx is reference counted. + * AppArmor sets confinement on every task, via the cred_label() which + * is required and are not allowed to be NULL. The cred_label is + * reference counted. * * TODO * If a task uses change_hat it currently does not return to the old @@ -29,40 +27,6 @@ #include "include/context.h" #include "include/policy.h" -/** - * aa_alloc_cred_ctx - allocate a new cred_ctx - * @flags: gfp flags for allocation - * - * Returns: allocated buffer or NULL on failure - */ -struct aa_cred_ctx *aa_alloc_cred_ctx(gfp_t flags) -{ - return kzalloc(sizeof(struct aa_cred_ctx), flags); -} - -/** - * aa_free_cred_ctx - free a cred_ctx - * @ctx: cred_ctx to free (MAYBE NULL) - */ -void aa_free_cred_ctx(struct aa_cred_ctx *ctx) -{ - if (ctx) { - aa_put_label(ctx->label); - - kzfree(ctx); - } -} - -/** - * aa_dup_cred_ctx - duplicate a task context, incrementing reference counts - * @new: a blank task context (NOT NULL) - * @old: the task context to copy (NOT NULL) - */ -void aa_dup_cred_ctx(struct aa_cred_ctx *new, const struct aa_cred_ctx *old) -{ - *new = *old; - aa_get_label(new->label); -} /** * aa_get_task_label - Get another task's label @@ -126,11 +90,12 @@ void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old) */ int aa_replace_current_label(struct aa_label *label) { - struct aa_cred_ctx *ctx = current_cred_ctx(); + struct aa_label *old = aa_current_raw_label(); struct cred *new; + AA_BUG(!label); - if (ctx->label == label) + if (old == label) return 0; if (current_cred() != current_real_cred()) @@ -140,22 +105,22 @@ int aa_replace_current_label(struct aa_label *label) if (!new) return -ENOMEM; - ctx = cred_ctx(new); - if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label))) - /* if switching to unconfined or a different label namespace + if (unconfined(label) || (labels_ns(old) != labels_ns(label))) + /* + * if switching to unconfined or a different label namespace * clear out context state */ aa_clear_task_ctx_trans(current_task_ctx()); /* - * be careful switching ctx->profile, when racing replacement it - * is possible that ctx->profile->proxy->profile is the reference - * keeping @profile valid, so make sure to get its reference before - * dropping the reference on ctx->profile + * be careful switching cred label, when racing replacement it + * is possible that the cred labels's->proxy->label is the reference + * keeping @label valid, so make sure to get its reference before + * dropping the reference on the cred's label */ aa_get_label(label); - aa_put_label(ctx->label); - ctx->label = label; + aa_put_label(cred_label(new)); + cred_label(new) = label; commit_creds(new); return 0; @@ -193,26 +158,26 @@ int aa_set_current_hat(struct aa_label *label, u64 token) { struct aa_task_ctx *tctx = current_task_ctx(); struct aa_cred_ctx *ctx; - struct cred *new = prepare_creds(); + struct cred *new; + new = prepare_creds(); if (!new) return -ENOMEM; AA_BUG(!label); - ctx = cred_ctx(new); if (!tctx->previous) { /* transfer refcount */ - tctx->previous = ctx->label; + tctx->previous = cred_label(new); tctx->token = token; } else if (tctx->token == token) { - aa_put_label(ctx->label); + aa_put_label(cred_label(new)); } else { /* previous_profile && ctx->token != token */ abort_creds(new); return -EACCES; } - ctx->label = aa_get_newest_label(label); + cred_label(new) = aa_get_newest_label(label); /* clear exec on switching context */ aa_put_label(tctx->onexec); tctx->onexec = NULL; @@ -233,7 +198,6 @@ int aa_set_current_hat(struct aa_label *label, u64 token) int aa_restore_previous_label(u64 token) { struct aa_task_ctx *tctx = current_task_ctx(); - struct aa_cred_ctx *ctx; struct cred *new; if (tctx->token != token) @@ -245,11 +209,10 @@ int aa_restore_previous_label(u64 token) new = prepare_creds(); if (!new) return -ENOMEM; - ctx = cred_ctx(new); - aa_put_label(ctx->label); - ctx->label = aa_get_newest_label(tctx->previous); - AA_BUG(!ctx->label); + aa_put_label(cred_label(new)); + cred_label(new) = aa_get_newest_label(tctx->previous); + AA_BUG(!cred_label(new)); /* clear exec && prev information when restoring to previous context */ aa_clear_task_ctx_trans(tctx); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index b90759a765b5..5285938680e0 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -779,7 +779,6 @@ static struct aa_label *handle_onexec(struct aa_label *label, */ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { - struct aa_cred_ctx *ctx; struct aa_task_ctx *tctx; struct aa_label *label, *new = NULL; struct aa_profile *profile; @@ -795,12 +794,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->called_set_creds) return 0; - ctx = cred_ctx(bprm->cred); tctx = current_task_ctx(); - AA_BUG(!ctx); + AA_BUG(!cred_label(bprm->cred)); AA_BUG(!tctx); - label = aa_get_newest_label(ctx->label); + label = aa_get_newest_label(cred_label(bprm->cred)); /* buffer freed below, name is pointer into buffer */ get_buffers(buffer); @@ -856,9 +854,9 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) } bprm->per_clear |= PER_CLEAR_ON_SETID; } - aa_put_label(ctx->label); - /* transfer reference, released when ctx is freed */ - ctx->label = new; + aa_put_label(cred_label(bprm->cred)); + /* transfer reference, released when cred is freed */ + cred_label(bprm->cred) = new; done: aa_put_label(label); @@ -1049,7 +1047,6 @@ build: int aa_change_hat(const char *hats[], int count, u64 token, int flags) { const struct cred *cred; - struct aa_cred_ctx *ctx; struct aa_task_ctx *tctx; struct aa_label *label, *previous, *new = NULL, *target = NULL; struct aa_profile *profile; @@ -1070,7 +1067,6 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* released below */ cred = get_current_cred(); - ctx = cred_ctx(cred); tctx = current_task_ctx(); label = aa_get_newest_cred_label(cred); previous = aa_get_newest_label(tctx->previous); diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index c3b51d88275b..8d36c14bc76d 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -22,21 +22,11 @@ #include "label.h" #include "policy_ns.h" -#define cred_ctx(X) ((X)->security) -#define current_cred_ctx() cred_ctx(current_cred()) - #define task_ctx(X) ((X)->security) #define current_task_ctx() (task_ctx(current)) +#define cred_label(X) ((X)->security) -/** - * struct aa_cred_ctx - primary label for confined tasks - * @label: the current label (NOT NULL) - */ -struct aa_cred_ctx { - struct aa_label *label; -}; - -/** +/* * struct aa_task_ctx - information for current task label change * @onexec: profile to transition to on next exec (MAY BE NULL) * @previous: profile the task may return to (MAY BE NULL) @@ -48,10 +38,6 @@ struct aa_task_ctx { u64 token; }; -struct aa_cred_ctx *aa_alloc_cred_ctx(gfp_t flags); -void aa_free_cred_ctx(struct aa_cred_ctx *ctx); -void aa_dup_cred_ctx(struct aa_cred_ctx *new, const struct aa_cred_ctx *old); - struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags); void aa_free_task_ctx(struct aa_task_ctx *ctx); void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old); @@ -73,10 +59,10 @@ struct aa_label *aa_get_task_label(struct task_struct *task); */ static inline struct aa_label *aa_cred_raw_label(const struct cred *cred) { - struct aa_cred_ctx *ctx = cred_ctx(cred); + struct aa_label *label = cred_label(cred); - AA_BUG(!ctx || !ctx->label); - return ctx->label; + AA_BUG(!label); + return label; } /** diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index a1d63d93b862..628c6a07df64 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -51,12 +51,12 @@ DEFINE_PER_CPU(struct aa_buffers, aa_buffers); */ /* - * free the associated aa_cred_ctx and put its labels + * put the associated labels */ static void apparmor_cred_free(struct cred *cred) { - aa_free_cred_ctx(cred_ctx(cred)); - cred_ctx(cred) = NULL; + aa_put_label(cred_label(cred)); + cred_label(cred) = NULL; } /* @@ -64,30 +64,17 @@ static void apparmor_cred_free(struct cred *cred) */ static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) { - /* freed by apparmor_cred_free */ - struct aa_cred_ctx *ctx = aa_alloc_cred_ctx(gfp); - - if (!ctx) - return -ENOMEM; - - cred_ctx(cred) = ctx; + cred_label(cred) = NULL; return 0; } /* - * prepare new aa_cred_ctx for modification by prepare_cred block + * prepare new cred label for modification by prepare_cred block */ static int apparmor_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { - /* freed by apparmor_cred_free */ - struct aa_cred_ctx *ctx = aa_alloc_cred_ctx(gfp); - - if (!ctx) - return -ENOMEM; - - aa_dup_cred_ctx(ctx, cred_ctx(old)); - cred_ctx(new) = ctx; + cred_label(new) = aa_get_newest_label(cred_label(old)); return 0; } @@ -96,10 +83,7 @@ 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_cred_ctx *old_ctx = cred_ctx(old); - struct aa_cred_ctx *new_ctx = cred_ctx(new); - - aa_dup_cred_ctx(new_ctx, old_ctx); + cred_label(new) = aa_get_newest_label(cred_label(old)); } static void apparmor_task_free(struct task_struct *task) @@ -599,11 +583,10 @@ static int apparmor_getprocattr(struct task_struct *task, char *name, /* released below */ const struct cred *cred = get_task_cred(task); struct aa_task_ctx *tctx = current_task_ctx(); - struct aa_cred_ctx *ctx = cred_ctx(cred); struct aa_label *label = NULL; if (strcmp(name, "current") == 0) - label = aa_get_newest_label(ctx->label); + label = aa_get_newest_label(cred_label(cred)); else if (strcmp(name, "prev") == 0 && tctx->previous) label = aa_get_newest_label(tctx->previous); else if (strcmp(name, "exec") == 0 && tctx->onexec) @@ -700,11 +683,11 @@ fail: static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) { struct aa_label *label = aa_current_raw_label(); - struct aa_cred_ctx *new_ctx = cred_ctx(bprm->cred); + struct aa_label *new_label = cred_label(bprm->cred); /* bail out if unconfined or not changing profile */ - if ((new_ctx->label->proxy == label->proxy) || - (unconfined(new_ctx->label))) + if ((new_label->proxy == label->proxy) || + (unconfined(new_label))) return; aa_inherit_files(bprm->cred, current->files); @@ -712,7 +695,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) current->pdeath_signal = 0; /* reset soft limits and set hard limits for the new label */ - __aa_transition_rlimits(label, new_ctx->label); + __aa_transition_rlimits(label, new_label); } /** @@ -1050,26 +1033,16 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; - struct aa_cred_ctx *ctx; struct aa_task_ctx *tctx; - ctx = aa_alloc_cred_ctx(GFP_KERNEL); - if (!ctx) - goto fail_cred; tctx = aa_alloc_task_ctx(GFP_KERNEL); if (!tctx) - goto fail_task; + return -ENOMEM; - ctx->label = aa_get_label(ns_unconfined(root_ns)); - cred_ctx(cred) = ctx; + cred_label(cred) = aa_get_label(ns_unconfined(root_ns)); task_ctx(current) = tctx; return 0; - -fail_task: - aa_free_cred_ctx(ctx); -fail_cred: - return -ENOMEM; } static void destroy_buffers(void) -- cgit v1.2.3 From f175221af35bedf99b201d861a0fe54e19ef36c2 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Fri, 27 Jan 2017 04:09:40 -0800 Subject: apparmor: rename tctx to ctx now that cred_ctx has been removed we can rename task_ctxs from tctx without causing confusion. Signed-off-by: John Johansen --- security/apparmor/context.c | 25 ++++++++++++------------- security/apparmor/domain.c | 16 ++++++++-------- security/apparmor/lsm.c | 18 +++++++++--------- 3 files changed, 29 insertions(+), 30 deletions(-) (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/context.c b/security/apparmor/context.c index 70e4a094add8..d95a3d47cb92 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c @@ -156,8 +156,7 @@ int aa_set_current_onexec(struct aa_label *label, bool stack) */ int aa_set_current_hat(struct aa_label *label, u64 token) { - struct aa_task_ctx *tctx = current_task_ctx(); - struct aa_cred_ctx *ctx; + struct aa_task_ctx *ctx = current_task_ctx(); struct cred *new; new = prepare_creds(); @@ -165,11 +164,11 @@ int aa_set_current_hat(struct aa_label *label, u64 token) return -ENOMEM; AA_BUG(!label); - if (!tctx->previous) { + if (!ctx->previous) { /* transfer refcount */ - tctx->previous = cred_label(new); - tctx->token = token; - } else if (tctx->token == token) { + ctx->previous = cred_label(new); + ctx->token = token; + } else if (ctx->token == token) { aa_put_label(cred_label(new)); } else { /* previous_profile && ctx->token != token */ @@ -179,8 +178,8 @@ int aa_set_current_hat(struct aa_label *label, u64 token) cred_label(new) = aa_get_newest_label(label); /* clear exec on switching context */ - aa_put_label(tctx->onexec); - tctx->onexec = NULL; + aa_put_label(ctx->onexec); + ctx->onexec = NULL; commit_creds(new); return 0; @@ -197,13 +196,13 @@ int aa_set_current_hat(struct aa_label *label, u64 token) */ int aa_restore_previous_label(u64 token) { - struct aa_task_ctx *tctx = current_task_ctx(); + struct aa_task_ctx *ctx = current_task_ctx(); struct cred *new; - if (tctx->token != token) + if (ctx->token != token) return -EACCES; /* ignore restores when there is no saved label */ - if (!tctx->previous) + if (!ctx->previous) return 0; new = prepare_creds(); @@ -211,10 +210,10 @@ int aa_restore_previous_label(u64 token) return -ENOMEM; aa_put_label(cred_label(new)); - cred_label(new) = aa_get_newest_label(tctx->previous); + cred_label(new) = aa_get_newest_label(ctx->previous); AA_BUG(!cred_label(new)); /* clear exec && prev information when restoring to previous context */ - aa_clear_task_ctx_trans(tctx); + aa_clear_task_ctx_trans(ctx); commit_creds(new); diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 5285938680e0..b180e10f2b86 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -779,7 +779,7 @@ static struct aa_label *handle_onexec(struct aa_label *label, */ int apparmor_bprm_set_creds(struct linux_binprm *bprm) { - struct aa_task_ctx *tctx; + struct aa_task_ctx *ctx; struct aa_label *label, *new = NULL; struct aa_profile *profile; char *buffer = NULL; @@ -794,17 +794,17 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->called_set_creds) return 0; - tctx = current_task_ctx(); + ctx = current_task_ctx(); AA_BUG(!cred_label(bprm->cred)); - AA_BUG(!tctx); + AA_BUG(!ctx); label = aa_get_newest_label(cred_label(bprm->cred)); /* buffer freed below, name is pointer into buffer */ get_buffers(buffer); /* Test for onexec first as onexec override other x transitions. */ - if (tctx->onexec) - new = handle_onexec(label, tctx->onexec, tctx->token, + if (ctx->onexec) + new = handle_onexec(label, ctx->onexec, ctx->token, bprm, buffer, &cond, &unsafe); else new = fn_label_build(label, profile, GFP_ATOMIC, @@ -1047,7 +1047,7 @@ build: int aa_change_hat(const char *hats[], int count, u64 token, int flags) { const struct cred *cred; - struct aa_task_ctx *tctx; + struct aa_task_ctx *ctx; struct aa_label *label, *previous, *new = NULL, *target = NULL; struct aa_profile *profile; struct aa_perms perms = {}; @@ -1067,9 +1067,9 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* released below */ cred = get_current_cred(); - tctx = current_task_ctx(); + ctx = current_task_ctx(); label = aa_get_newest_cred_label(cred); - previous = aa_get_newest_label(tctx->previous); + previous = aa_get_newest_label(ctx->previous); if (unconfined(label)) { info = "unconfined can not change_hat"; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 628c6a07df64..fda36f3e3820 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -582,15 +582,15 @@ 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_ctx *tctx = current_task_ctx(); + struct aa_task_ctx *ctx = current_task_ctx(); struct aa_label *label = NULL; if (strcmp(name, "current") == 0) label = aa_get_newest_label(cred_label(cred)); - else if (strcmp(name, "prev") == 0 && tctx->previous) - label = aa_get_newest_label(tctx->previous); - else if (strcmp(name, "exec") == 0 && tctx->onexec) - label = aa_get_newest_label(tctx->onexec); + else if (strcmp(name, "prev") == 0 && ctx->previous) + label = aa_get_newest_label(ctx->previous); + else if (strcmp(name, "exec") == 0 && ctx->onexec) + label = aa_get_newest_label(ctx->onexec); else error = -EINVAL; @@ -1033,14 +1033,14 @@ static int param_set_mode(const char *val, const struct kernel_param *kp) static int __init set_init_ctx(void) { struct cred *cred = (struct cred *)current->real_cred; - struct aa_task_ctx *tctx; + struct aa_task_ctx *ctx; - tctx = aa_alloc_task_ctx(GFP_KERNEL); - if (!tctx) + ctx = aa_alloc_task_ctx(GFP_KERNEL); + if (!ctx) return -ENOMEM; cred_label(cred) = aa_get_label(ns_unconfined(root_ns)); - task_ctx(current) = tctx; + task_ctx(current) = ctx; return 0; } -- cgit v1.2.3 From de62de59c27881c59c7df2e535cb9e1275cd52cc Mon Sep 17 00:00:00 2001 From: John Johansen Date: Sun, 8 Oct 2017 00:43:02 -0700 Subject: apparmor: move task related defines and fns to task.X files Signed-off-by: John Johansen --- security/apparmor/Makefile | 2 +- security/apparmor/context.c | 221 ------------------------------------ security/apparmor/domain.c | 4 +- security/apparmor/include/context.h | 40 +------ security/apparmor/include/task.h | 90 +++++++++++++++ security/apparmor/lsm.c | 6 +- security/apparmor/task.c | 176 ++++++++++++++++++++++++++++ 7 files changed, 273 insertions(+), 266 deletions(-) delete mode 100644 security/apparmor/context.c create mode 100644 security/apparmor/include/task.h create mode 100644 security/apparmor/task.c (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 9a6b4033d52b..380c8e08174a 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o -apparmor-y := apparmorfs.o audit.o capability.o context.o ipc.o lib.o match.o \ +apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ resource.o secid.o file.o policy_ns.o label.o mount.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o diff --git a/security/apparmor/context.c b/security/apparmor/context.c deleted file mode 100644 index d95a3d47cb92..000000000000 --- a/security/apparmor/context.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * AppArmor security module - * - * This file contains AppArmor functions used to manipulate object security - * contexts. - * - * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 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 sets confinement on every task, via the cred_label() which - * is required and are not allowed to be NULL. The cred_label is - * reference counted. - * - * TODO - * If a task uses change_hat it currently does not return to the old - * cred or task context but instead creates a new one. Ideally the task - * should return to the previous cred if it has not been modified. - * - */ - -#include "include/context.h" -#include "include/policy.h" - - -/** - * aa_get_task_label - Get another task's label - * @task: task to query (NOT NULL) - * - * Returns: counted reference to @task's label - */ -struct aa_label *aa_get_task_label(struct task_struct *task) -{ - struct aa_label *p; - - rcu_read_lock(); - p = aa_get_newest_label(__aa_task_raw_label(task)); - rcu_read_unlock(); - - return p; -} - -/** - * aa_alloc_task_ctx - allocate a new task_ctx - * @flags: gfp flags for allocation - * - * Returns: allocated buffer or NULL on failure - */ -struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) -{ - return kzalloc(sizeof(struct aa_task_ctx), flags); -} - -/** - * aa_free_task_ctx - free a task_ctx - * @ctx: task_ctx to free (MAYBE NULL) - */ -void aa_free_task_ctx(struct aa_task_ctx *ctx) -{ - if (ctx) { - aa_put_label(ctx->previous); - aa_put_label(ctx->onexec); - - kzfree(ctx); - } -} - -/** - * aa_dup_task_ctx - duplicate a task context, incrementing reference counts - * @new: a blank task context (NOT NULL) - * @old: the task context to copy (NOT NULL) - */ -void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old) -{ - *new = *old; - aa_get_label(new->previous); - aa_get_label(new->onexec); -} - -/** - * aa_replace_current_label - replace the current tasks label - * @label: new label (NOT NULL) - * - * Returns: 0 or error on failure - */ -int aa_replace_current_label(struct aa_label *label) -{ - struct aa_label *old = aa_current_raw_label(); - struct cred *new; - - AA_BUG(!label); - - if (old == label) - return 0; - - if (current_cred() != current_real_cred()) - return -EBUSY; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - if (unconfined(label) || (labels_ns(old) != labels_ns(label))) - /* - * if switching to unconfined or a different label namespace - * clear out context state - */ - aa_clear_task_ctx_trans(current_task_ctx()); - - /* - * be careful switching cred label, when racing replacement it - * is possible that the cred labels's->proxy->label is the reference - * keeping @label valid, so make sure to get its reference before - * dropping the reference on the cred's label - */ - aa_get_label(label); - aa_put_label(cred_label(new)); - cred_label(new) = label; - - commit_creds(new); - return 0; -} - -/** - * aa_set_current_onexec - set the tasks change_profile to happen onexec - * @label: system label to set at exec (MAYBE NULL to clear value) - * @stack: whether stacking should be done - * Returns: 0 or error on failure - */ -int aa_set_current_onexec(struct aa_label *label, bool stack) -{ - struct aa_task_ctx *ctx = current_task_ctx(); - - aa_get_label(label); - aa_put_label(ctx->onexec); - ctx->onexec = label; - ctx->token = stack; - - return 0; -} - -/** - * aa_set_current_hat - set the current tasks hat - * @label: label to set as the current hat (NOT NULL) - * @token: token value that must be specified to change from the hat - * - * Do switch of tasks hat. If the task is currently in a hat - * validate the token to match. - * - * Returns: 0 or error on failure - */ -int aa_set_current_hat(struct aa_label *label, u64 token) -{ - struct aa_task_ctx *ctx = current_task_ctx(); - struct cred *new; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - AA_BUG(!label); - - if (!ctx->previous) { - /* transfer refcount */ - ctx->previous = cred_label(new); - ctx->token = token; - } else if (ctx->token == token) { - aa_put_label(cred_label(new)); - } else { - /* previous_profile && ctx->token != token */ - abort_creds(new); - return -EACCES; - } - - cred_label(new) = aa_get_newest_label(label); - /* clear exec on switching context */ - aa_put_label(ctx->onexec); - ctx->onexec = NULL; - - commit_creds(new); - return 0; -} - -/** - * aa_restore_previous_label - exit from hat context restoring previous label - * @token: the token that must be matched to exit hat context - * - * Attempt to return out of a hat to the previous label. The token - * must match the stored token value. - * - * Returns: 0 or error of failure - */ -int aa_restore_previous_label(u64 token) -{ - struct aa_task_ctx *ctx = current_task_ctx(); - struct cred *new; - - if (ctx->token != token) - return -EACCES; - /* ignore restores when there is no saved label */ - if (!ctx->previous) - return 0; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - aa_put_label(cred_label(new)); - cred_label(new) = aa_get_newest_label(ctx->previous); - AA_BUG(!cred_label(new)); - /* clear exec && prev information when restoring to previous context */ - aa_clear_task_ctx_trans(ctx); - - commit_creds(new); - - return 0; -} diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index b180e10f2b86..56d080a6d774 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -794,7 +794,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) if (bprm->called_set_creds) return 0; - ctx = current_task_ctx(); + ctx = task_ctx(current); AA_BUG(!cred_label(bprm->cred)); AA_BUG(!ctx); @@ -1067,7 +1067,7 @@ int aa_change_hat(const char *hats[], int count, u64 token, int flags) /* released below */ cred = get_current_cred(); - ctx = current_task_ctx(); + ctx = task_ctx(current); label = aa_get_newest_cred_label(cred); previous = aa_get_newest_label(ctx->previous); diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index b2aeb1da7e77..e287b7d0d4be 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h @@ -21,33 +21,10 @@ #include "label.h" #include "policy_ns.h" +#include "task.h" -#define task_ctx(X) ((X)->security) -#define current_task_ctx() (task_ctx(current)) #define cred_label(X) ((X)->security) -/* - * struct aa_task_ctx - information for current task label change - * @onexec: profile to transition to on next exec (MAY BE NULL) - * @previous: profile the task may return to (MAY BE NULL) - * @token: magic value the task must know for returning to @previous_profile - */ -struct aa_task_ctx { - struct aa_label *onexec; - struct aa_label *previous; - u64 token; -}; - -struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags); -void aa_free_task_ctx(struct aa_task_ctx *ctx); -void aa_dup_task_ctx(struct aa_task_ctx *new, const struct aa_task_ctx *old); - -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_label - obtain cred's label @@ -196,19 +173,4 @@ static inline struct aa_ns *aa_get_current_ns(void) return ns; } -/** - * aa_clear_task_ctx_trans - clear transition tracking info from the ctx - * @ctx: task context to clear (NOT NULL) - */ -static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) -{ - AA_BUG(!ctx); - - aa_put_label(ctx->previous); - aa_put_label(ctx->onexec); - ctx->previous = NULL; - ctx->onexec = NULL; - ctx->token = 0; -} - #endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/include/task.h b/security/apparmor/include/task.h new file mode 100644 index 000000000000..d222197db299 --- /dev/null +++ b/security/apparmor/include/task.h @@ -0,0 +1,90 @@ +/* + * AppArmor security module + * + * This file contains AppArmor task related definitions and mediation + * + * Copyright 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_TASK_H +#define __AA_TASK_H + +#define task_ctx(X) ((X)->security) + +/* + * struct aa_task_ctx - information for current task label change + * @onexec: profile to transition to on next exec (MAY BE NULL) + * @previous: profile the task may return to (MAY BE NULL) + * @token: magic value the task must know for returning to @previous_profile + */ +struct aa_task_ctx { + struct aa_label *onexec; + struct aa_label *previous; + u64 token; +}; + +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_alloc_task_ctx - allocate a new task_ctx + * @flags: gfp flags for allocation + * + * Returns: allocated buffer or NULL on failure + */ +static inline struct aa_task_ctx *aa_alloc_task_ctx(gfp_t flags) +{ + return kzalloc(sizeof(struct aa_task_ctx), flags); +} + +/** + * aa_free_task_ctx - free a task_ctx + * @ctx: task_ctx to free (MAYBE NULL) + */ +static inline void aa_free_task_ctx(struct aa_task_ctx *ctx) +{ + if (ctx) { + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); + + kzfree(ctx); + } +} + +/** + * aa_dup_task_ctx - duplicate a task context, incrementing reference counts + * @new: a blank task context (NOT NULL) + * @old: the task context to copy (NOT NULL) + */ +static inline void aa_dup_task_ctx(struct aa_task_ctx *new, + const struct aa_task_ctx *old) +{ + *new = *old; + aa_get_label(new->previous); + aa_get_label(new->onexec); +} + +/** + * aa_clear_task_ctx_trans - clear transition tracking info from the ctx + * @ctx: task context to clear (NOT NULL) + */ +static inline void aa_clear_task_ctx_trans(struct aa_task_ctx *ctx) +{ + AA_BUG(!ctx); + + aa_put_label(ctx->previous); + aa_put_label(ctx->onexec); + ctx->previous = NULL; + ctx->onexec = NULL; + ctx->token = 0; +} + +#endif /* __AA_TASK_H */ diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index fda36f3e3820..7577cd982230 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -101,7 +101,7 @@ static int apparmor_task_alloc(struct task_struct *task, if (!new) return -ENOMEM; - aa_dup_task_ctx(new, current_task_ctx()); + aa_dup_task_ctx(new, task_ctx(current)); task_ctx(task) = new; return 0; @@ -582,7 +582,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_ctx *ctx = current_task_ctx(); + struct aa_task_ctx *ctx = task_ctx(current); struct aa_label *label = NULL; if (strcmp(name, "current") == 0) @@ -705,7 +705,7 @@ static void apparmor_bprm_committing_creds(struct linux_binprm *bprm) static void apparmor_bprm_committed_creds(struct linux_binprm *bprm) { /* clear out temporary/transitional state from the context */ - aa_clear_task_ctx_trans(current_task_ctx()); + aa_clear_task_ctx_trans(task_ctx(current)); return; } diff --git a/security/apparmor/task.c b/security/apparmor/task.c new file mode 100644 index 000000000000..36eb8707ad89 --- /dev/null +++ b/security/apparmor/task.c @@ -0,0 +1,176 @@ +/* + * AppArmor security module + * + * This file contains AppArmor task related definitions and mediation + * + * Copyright 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. + * + * TODO + * If a task uses change_hat it currently does not return to the old + * cred or task context but instead creates a new one. Ideally the task + * should return to the previous cred if it has not been modified. + */ + +#include "include/context.h" +#include "include/task.h" + +/** + * aa_get_task_label - Get another task's label + * @task: task to query (NOT NULL) + * + * Returns: counted reference to @task's label + */ +struct aa_label *aa_get_task_label(struct task_struct *task) +{ + struct aa_label *p; + + rcu_read_lock(); + p = aa_get_newest_label(__aa_task_raw_label(task)); + rcu_read_unlock(); + + return p; +} + +/** + * aa_replace_current_label - replace the current tasks label + * @label: new label (NOT NULL) + * + * Returns: 0 or error on failure + */ +int aa_replace_current_label(struct aa_label *label) +{ + struct aa_label *old = aa_current_raw_label(); + struct cred *new; + + AA_BUG(!label); + + if (old == label) + return 0; + + if (current_cred() != current_real_cred()) + return -EBUSY; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + if (unconfined(label) || (labels_ns(old) != labels_ns(label))) + /* + * if switching to unconfined or a different label namespace + * clear out context state + */ + aa_clear_task_ctx_trans(task_ctx(current)); + + /* + * be careful switching cred label, when racing replacement it + * is possible that the cred labels's->proxy->label is the reference + * keeping @label valid, so make sure to get its reference before + * dropping the reference on the cred's label + */ + aa_get_label(label); + aa_put_label(cred_label(new)); + cred_label(new) = label; + + commit_creds(new); + return 0; +} + + +/** + * aa_set_current_onexec - set the tasks change_profile to happen onexec + * @label: system label to set at exec (MAYBE NULL to clear value) + * @stack: whether stacking should be done + * Returns: 0 or error on failure + */ +int aa_set_current_onexec(struct aa_label *label, bool stack) +{ + struct aa_task_ctx *ctx = task_ctx(current); + + aa_get_label(label); + aa_put_label(ctx->onexec); + ctx->onexec = label; + ctx->token = stack; + + return 0; +} + +/** + * aa_set_current_hat - set the current tasks hat + * @label: label to set as the current hat (NOT NULL) + * @token: token value that must be specified to change from the hat + * + * Do switch of tasks hat. If the task is currently in a hat + * validate the token to match. + * + * Returns: 0 or error on failure + */ +int aa_set_current_hat(struct aa_label *label, u64 token) +{ + struct aa_task_ctx *ctx = task_ctx(current); + struct cred *new; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + AA_BUG(!label); + + if (!ctx->previous) { + /* transfer refcount */ + ctx->previous = cred_label(new); + ctx->token = token; + } else if (ctx->token == token) { + aa_put_label(cred_label(new)); + } else { + /* previous_profile && ctx->token != token */ + abort_creds(new); + return -EACCES; + } + + cred_label(new) = aa_get_newest_label(label); + /* clear exec on switching context */ + aa_put_label(ctx->onexec); + ctx->onexec = NULL; + + commit_creds(new); + return 0; +} + +/** + * aa_restore_previous_label - exit from hat context restoring previous label + * @token: the token that must be matched to exit hat context + * + * Attempt to return out of a hat to the previous label. The token + * must match the stored token value. + * + * Returns: 0 or error of failure + */ +int aa_restore_previous_label(u64 token) +{ + struct aa_task_ctx *ctx = task_ctx(current); + struct cred *new; + + if (ctx->token != token) + return -EACCES; + /* ignore restores when there is no saved label */ + if (!ctx->previous) + return 0; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + + aa_put_label(cred_label(new)); + cred_label(new) = aa_get_newest_label(ctx->previous); + AA_BUG(!cred_label(new)); + /* clear exec && prev information when restoring to previous context */ + aa_clear_task_ctx_trans(ctx); + + commit_creds(new); + + return 0; +} -- cgit v1.2.3 From d8889d49e414b371eb235c08c3a759ab3e0cfa51 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 11 Oct 2017 01:04:48 -0700 Subject: apparmor: move context.h to cred.h Now that file contexts have been moved into file, and task context fns() and data have been split from the context, only the cred context remains in context.h so rename to cred.h to better reflect what it deals with. Signed-off-by: John Johansen --- security/apparmor/apparmorfs.c | 2 +- security/apparmor/capability.c | 2 +- security/apparmor/domain.c | 2 +- security/apparmor/file.c | 2 +- security/apparmor/include/context.h | 176 ------------------------------------ security/apparmor/include/cred.h | 176 ++++++++++++++++++++++++++++++++++++ security/apparmor/ipc.c | 2 +- security/apparmor/label.c | 2 +- security/apparmor/lsm.c | 2 +- security/apparmor/mount.c | 2 +- security/apparmor/policy.c | 2 +- security/apparmor/policy_ns.c | 2 +- security/apparmor/policy_unpack.c | 2 +- security/apparmor/procattr.c | 2 +- security/apparmor/resource.c | 2 +- security/apparmor/task.c | 2 +- 16 files changed, 190 insertions(+), 190 deletions(-) delete mode 100644 security/apparmor/include/context.h create mode 100644 security/apparmor/include/cred.h (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 00fc4f9f7f14..874c1bf6b84a 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -30,7 +30,7 @@ #include "include/apparmor.h" #include "include/apparmorfs.h" #include "include/audit.h" -#include "include/context.h" +#include "include/cred.h" #include "include/crypto.h" #include "include/ipc.h" #include "include/label.h" diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 67e347192a55..253ef6e9d445 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c @@ -19,7 +19,7 @@ #include "include/apparmor.h" #include "include/capability.h" -#include "include/context.h" +#include "include/cred.h" #include "include/policy.h" #include "include/audit.h" diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 56d080a6d774..cd58eef4eb8d 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -22,7 +22,7 @@ #include "include/audit.h" #include "include/apparmorfs.h" -#include "include/context.h" +#include "include/cred.h" #include "include/domain.h" #include "include/file.h" #include "include/ipc.h" diff --git a/security/apparmor/file.c b/security/apparmor/file.c index e79bf44396a3..9a67a33904b3 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -18,7 +18,7 @@ #include "include/apparmor.h" #include "include/audit.h" -#include "include/context.h" +#include "include/cred.h" #include "include/file.h" #include "include/match.h" #include "include/path.h" diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h deleted file mode 100644 index e287b7d0d4be..000000000000 --- a/security/apparmor/include/context.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * AppArmor security module - * - * This file contains AppArmor contexts used to associate "labels" to objects. - * - * Copyright (C) 1998-2008 Novell/SUSE - * Copyright 2009-2010 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_CONTEXT_H -#define __AA_CONTEXT_H - -#include -#include -#include - -#include "label.h" -#include "policy_ns.h" -#include "task.h" - -#define cred_label(X) ((X)->security) - - -/** - * aa_cred_raw_label - obtain cred's label - * @cred: cred to obtain label from (NOT NULL) - * - * Returns: confining label - * - * does NOT increment reference count - */ -static inline struct aa_label *aa_cred_raw_label(const struct cred *cred) -{ - struct aa_label *label = cred_label(cred); - - AA_BUG(!label); - return label; -} - -/** - * 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 label - */ -static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) -{ - return aa_get_newest_label(aa_cred_raw_label(cred)); -} - -/** - * __aa_task_raw_label - retrieve another task's label - * @task: task to query (NOT NULL) - * - * 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_label *__aa_task_raw_label(struct task_struct *task) -{ - return aa_cred_raw_label(__task_cred(task)); -} - -/** - * aa_current_raw_label - find the current tasks confining label - * - * 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 label so it is safe to call when inside of locks. - */ -static inline struct aa_label *aa_current_raw_label(void) -{ - return aa_cred_raw_label(current_cred()); -} - -/** - * aa_get_current_label - get the newest version of the current tasks label - * - * 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_label() - */ -static inline struct aa_label *aa_get_current_label(void) -{ - struct aa_label *l = aa_current_raw_label(); - - if (label_is_stale(l)) - return aa_get_newest_label(l); - return aa_get_label(l); -} - -#define __end_current_label_crit_section(X) end_current_label_crit_section(X) - -/** - * 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_label_crit_section and never used in situations where the - * task cred may be updated - */ -static inline void end_current_label_crit_section(struct aa_label *label) -{ - if (label != aa_current_raw_label()) - aa_put_label(label); -} - -/** - * __begin_current_label_crit_section - current's confining label - * - * 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_label_crit_section() - * This must NOT be used if the task cred could be updated within the - * critical section between __begin_current_label_crit_section() .. - * __end_current_label_crit_section() - */ -static inline struct aa_label *__begin_current_label_crit_section(void) -{ - struct aa_label *label = aa_current_raw_label(); - - if (label_is_stale(label)) - label = aa_get_newest_label(label); - - return label; -} - -/** - * begin_current_label_crit_section - current's confining label and update it - * - * 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_label_crit_section() - * This must NOT be used if the task cred could be updated within the - * critical section between begin_current_label_crit_section() .. - * end_current_label_crit_section() - */ -static inline struct aa_label *begin_current_label_crit_section(void) -{ - struct aa_label *label = aa_current_raw_label(); - - 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_label(label); - } - - return label; -} - -static inline struct aa_ns *aa_get_current_ns(void) -{ - struct aa_label *label; - struct aa_ns *ns; - - label = __begin_current_label_crit_section(); - ns = aa_get_ns(labels_ns(label)); - __end_current_label_crit_section(label); - - return ns; -} - -#endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/include/cred.h b/security/apparmor/include/cred.h new file mode 100644 index 000000000000..e287b7d0d4be --- /dev/null +++ b/security/apparmor/include/cred.h @@ -0,0 +1,176 @@ +/* + * AppArmor security module + * + * This file contains AppArmor contexts used to associate "labels" to objects. + * + * Copyright (C) 1998-2008 Novell/SUSE + * Copyright 2009-2010 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_CONTEXT_H +#define __AA_CONTEXT_H + +#include +#include +#include + +#include "label.h" +#include "policy_ns.h" +#include "task.h" + +#define cred_label(X) ((X)->security) + + +/** + * aa_cred_raw_label - obtain cred's label + * @cred: cred to obtain label from (NOT NULL) + * + * Returns: confining label + * + * does NOT increment reference count + */ +static inline struct aa_label *aa_cred_raw_label(const struct cred *cred) +{ + struct aa_label *label = cred_label(cred); + + AA_BUG(!label); + return label; +} + +/** + * 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 label + */ +static inline struct aa_label *aa_get_newest_cred_label(const struct cred *cred) +{ + return aa_get_newest_label(aa_cred_raw_label(cred)); +} + +/** + * __aa_task_raw_label - retrieve another task's label + * @task: task to query (NOT NULL) + * + * 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_label *__aa_task_raw_label(struct task_struct *task) +{ + return aa_cred_raw_label(__task_cred(task)); +} + +/** + * aa_current_raw_label - find the current tasks confining label + * + * 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 label so it is safe to call when inside of locks. + */ +static inline struct aa_label *aa_current_raw_label(void) +{ + return aa_cred_raw_label(current_cred()); +} + +/** + * aa_get_current_label - get the newest version of the current tasks label + * + * 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_label() + */ +static inline struct aa_label *aa_get_current_label(void) +{ + struct aa_label *l = aa_current_raw_label(); + + if (label_is_stale(l)) + return aa_get_newest_label(l); + return aa_get_label(l); +} + +#define __end_current_label_crit_section(X) end_current_label_crit_section(X) + +/** + * 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_label_crit_section and never used in situations where the + * task cred may be updated + */ +static inline void end_current_label_crit_section(struct aa_label *label) +{ + if (label != aa_current_raw_label()) + aa_put_label(label); +} + +/** + * __begin_current_label_crit_section - current's confining label + * + * 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_label_crit_section() + * This must NOT be used if the task cred could be updated within the + * critical section between __begin_current_label_crit_section() .. + * __end_current_label_crit_section() + */ +static inline struct aa_label *__begin_current_label_crit_section(void) +{ + struct aa_label *label = aa_current_raw_label(); + + if (label_is_stale(label)) + label = aa_get_newest_label(label); + + return label; +} + +/** + * begin_current_label_crit_section - current's confining label and update it + * + * 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_label_crit_section() + * This must NOT be used if the task cred could be updated within the + * critical section between begin_current_label_crit_section() .. + * end_current_label_crit_section() + */ +static inline struct aa_label *begin_current_label_crit_section(void) +{ + struct aa_label *label = aa_current_raw_label(); + + 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_label(label); + } + + return label; +} + +static inline struct aa_ns *aa_get_current_ns(void) +{ + struct aa_label *label; + struct aa_ns *ns; + + label = __begin_current_label_crit_section(); + ns = aa_get_ns(labels_ns(label)); + __end_current_label_crit_section(label); + + return ns; +} + +#endif /* __AA_CONTEXT_H */ diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index d7b137d4eb74..527ea1557120 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c @@ -17,7 +17,7 @@ #include "include/audit.h" #include "include/capability.h" -#include "include/context.h" +#include "include/cred.h" #include "include/policy.h" #include "include/ipc.h" #include "include/sig_names.h" diff --git a/security/apparmor/label.c b/security/apparmor/label.c index 69c7451becef..523250e34837 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c @@ -16,7 +16,7 @@ #include #include "include/apparmor.h" -#include "include/context.h" +#include "include/cred.h" #include "include/label.h" #include "include/policy.h" #include "include/secid.h" diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 7577cd982230..ef6334e11597 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -30,7 +30,7 @@ #include "include/apparmorfs.h" #include "include/audit.h" #include "include/capability.h" -#include "include/context.h" +#include "include/cred.h" #include "include/file.h" #include "include/ipc.h" #include "include/path.h" diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 8c558cbce930..6e8c7ac0b33d 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c @@ -18,7 +18,7 @@ #include "include/apparmor.h" #include "include/audit.h" -#include "include/context.h" +#include "include/cred.h" #include "include/domain.h" #include "include/file.h" #include "include/match.h" diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index a158af1f1b38..a8e096a88e62 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -82,7 +82,7 @@ #include "include/apparmor.h" #include "include/capability.h" -#include "include/context.h" +#include "include/cred.h" #include "include/file.h" #include "include/ipc.h" #include "include/match.h" diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index b1e629cba70b..b0f9dc3f765a 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c @@ -21,7 +21,7 @@ #include #include "include/apparmor.h" -#include "include/context.h" +#include "include/cred.h" #include "include/policy_ns.h" #include "include/label.h" #include "include/policy.h" diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index ece0c246cfe6..40c8dc617b13 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -23,7 +23,7 @@ #include "include/apparmor.h" #include "include/audit.h" -#include "include/context.h" +#include "include/cred.h" #include "include/crypto.h" #include "include/match.h" #include "include/path.h" diff --git a/security/apparmor/procattr.c b/security/apparmor/procattr.c index d81617379d63..80c34ed373c3 100644 --- a/security/apparmor/procattr.c +++ b/security/apparmor/procattr.c @@ -13,7 +13,7 @@ */ #include "include/apparmor.h" -#include "include/context.h" +#include "include/cred.h" #include "include/policy.h" #include "include/policy_ns.h" #include "include/domain.h" diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index cf4d234febe9..d022137143b9 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -16,7 +16,7 @@ #include #include "include/audit.h" -#include "include/context.h" +#include "include/cred.h" #include "include/resource.h" #include "include/policy.h" diff --git a/security/apparmor/task.c b/security/apparmor/task.c index 36eb8707ad89..44b9b938e06d 100644 --- a/security/apparmor/task.c +++ b/security/apparmor/task.c @@ -16,7 +16,7 @@ * should return to the previous cred if it has not been modified. */ -#include "include/context.h" +#include "include/cred.h" #include "include/task.h" /** -- cgit v1.2.3 From 56974a6fcfef69ee0825bd66ed13e92070ac5224 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Tue, 18 Jul 2017 23:18:33 -0700 Subject: apparmor: add base infastructure for socket mediation version 2 - Force an abi break. Network mediation will only be available in v8 abi complaint policy. Provide a basic mediation of sockets. This is not a full net mediation but just whether a spcific family of socket can be used by an application, along with setting up some basic infrastructure for network mediation to follow. the user space rule hav the basic form of NETWORK RULE = [ QUALIFIERS ] 'network' [ DOMAIN ] [ TYPE | PROTOCOL ] DOMAIN = ( 'inet' | 'ax25' | 'ipx' | 'appletalk' | 'netrom' | 'bridge' | 'atmpvc' | 'x25' | 'inet6' | 'rose' | 'netbeui' | 'security' | 'key' | 'packet' | 'ash' | 'econet' | 'atmsvc' | 'sna' | 'irda' | 'pppox' | 'wanpipe' | 'bluetooth' | 'netlink' | 'unix' | 'rds' | 'llc' | 'can' | 'tipc' | 'iucv' | 'rxrpc' | 'isdn' | 'phonet' | 'ieee802154' | 'caif' | 'alg' | 'nfc' | 'vsock' | 'mpls' | 'ib' | 'kcm' ) ',' TYPE = ( 'stream' | 'dgram' | 'seqpacket' | 'rdm' | 'raw' | 'packet' ) PROTOCOL = ( 'tcp' | 'udp' | 'icmp' ) eg. network, network inet, Signed-off-by: John Johansen Acked-by: Seth Arnold --- security/apparmor/.gitignore | 1 + security/apparmor/Makefile | 43 +++- security/apparmor/apparmorfs.c | 2 + security/apparmor/file.c | 30 +++ security/apparmor/include/apparmor.h | 3 +- security/apparmor/include/audit.h | 6 + security/apparmor/include/net.h | 106 ++++++++++ security/apparmor/include/perms.h | 5 +- security/apparmor/include/policy.h | 11 + security/apparmor/lib.c | 5 +- security/apparmor/lsm.c | 392 +++++++++++++++++++++++++++++++++++ security/apparmor/net.c | 187 +++++++++++++++++ security/apparmor/policy_unpack.c | 3 +- 13 files changed, 786 insertions(+), 8 deletions(-) create mode 100644 security/apparmor/include/net.h create mode 100644 security/apparmor/net.c (limited to 'security/apparmor/lsm.c') diff --git a/security/apparmor/.gitignore b/security/apparmor/.gitignore index 9cdec70d72b8..d5b291e94264 100644 --- a/security/apparmor/.gitignore +++ b/security/apparmor/.gitignore @@ -1,5 +1,6 @@ # # Generated include files # +net_names.h capability_names.h rlim_names.h diff --git a/security/apparmor/Makefile b/security/apparmor/Makefile index 380c8e08174a..ff23fcfefe19 100644 --- a/security/apparmor/Makefile +++ b/security/apparmor/Makefile @@ -5,11 +5,44 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ - resource.o secid.o file.o policy_ns.o label.o mount.o + resource.o secid.o file.o policy_ns.o label.o mount.o net.o apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o -clean-files := capability_names.h rlim_names.h +clean-files := capability_names.h rlim_names.h net_names.h +# Build a lower case string table of address family names +# Transform lines from +# #define AF_LOCAL 1 /* POSIX name for AF_UNIX */ +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# [1] = "local", +# [2] = "inet", +# +# and build the securityfs entries for the mapping. +# Transforms lines from +# #define AF_INET 2 /* Internet IP Protocol */ +# to +# #define AA_SFS_AF_MASK "local inet" +quiet_cmd_make-af = GEN $@ +cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ + sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ ;\ + printf '%s' '\#define AA_SFS_AF_MASK "' >> $@ ;\ + sed -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ + 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/\L\1/p'\ + $< | tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + +# Build a lower case string table of sock type names +# Transform lines from +# SOCK_STREAM = 1, +# to +# [1] = "stream", +quiet_cmd_make-sock = GEN $@ +cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ + sed $^ >>$@ -r -n \ + -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ + echo "};" >> $@ # Build a lower case string table of capability names # Transforms lines from @@ -62,6 +95,7 @@ cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ $(obj)/capability.o : $(obj)/capability_names.h +$(obj)/net.o : $(obj)/net_names.h $(obj)/resource.o : $(obj)/rlim_names.h $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ $(src)/Makefile @@ -69,3 +103,8 @@ $(obj)/capability_names.h : $(srctree)/include/uapi/linux/capability.h \ $(obj)/rlim_names.h : $(srctree)/include/uapi/asm-generic/resource.h \ $(src)/Makefile $(call cmd,make-rlim) +$(obj)/net_names.h : $(srctree)/include/linux/socket.h \ + $(srctree)/include/linux/net.h \ + $(src)/Makefile + $(call cmd,make-af) + $(call cmd,make-sock) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index 3dcc122234c8..10d16e3abed9 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -2169,6 +2169,7 @@ static struct aa_sfs_entry aa_sfs_entry_versions[] = { AA_SFS_FILE_BOOLEAN("v5", 1), AA_SFS_FILE_BOOLEAN("v6", 1), AA_SFS_FILE_BOOLEAN("v7", 1), + AA_SFS_FILE_BOOLEAN("v8", 1), { } }; @@ -2204,6 +2205,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = { AA_SFS_DIR("policy", aa_sfs_entry_policy), AA_SFS_DIR("domain", aa_sfs_entry_domain), AA_SFS_DIR("file", aa_sfs_entry_file), + AA_SFS_DIR("network_v8", aa_sfs_entry_network), AA_SFS_DIR("mount", aa_sfs_entry_mount), AA_SFS_DIR("namespaces", aa_sfs_entry_ns), AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 9a67a33904b3..224b2fef93ca 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -21,6 +21,7 @@ #include "include/cred.h" #include "include/file.h" #include "include/match.h" +#include "include/net.h" #include "include/path.h" #include "include/policy.h" #include "include/label.h" @@ -560,6 +561,32 @@ static int __file_path_perm(const char *op, struct aa_label *label, return error; } +static int __file_sock_perm(const char *op, struct aa_label *label, + struct aa_label *flabel, struct file *file, + u32 request, u32 denied) +{ + struct socket *sock = (struct socket *) file->private_data; + int error; + + AA_BUG(!sock); + + /* revalidation due to label out of date. No revocation at this time */ + if (!denied && aa_label_is_subset(flabel, label)) + return 0; + + /* TODO: improve to skip profiles cached in flabel */ + error = aa_sock_file_perm(label, op, request, sock); + if (denied) { + /* TODO: improve to skip profiles checked above */ + /* check every profile in file label to is cached */ + last_error(error, aa_sock_file_perm(flabel, op, request, sock)); + } + if (!error) + update_file_ctx(file_ctx(file), label, request); + + return error; +} + /** * aa_file_perm - do permission revalidation check & audit for @file * @op: operation being checked @@ -604,6 +631,9 @@ int aa_file_perm(const char *op, struct aa_label *label, struct file *file, error = __file_path_perm(op, label, flabel, file, request, denied); + else if (S_ISSOCK(file_inode(file)->i_mode)) + error = __file_sock_perm(op, label, flabel, file, request, + denied); done: rcu_read_unlock(); diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index 829082c35faa..73d63b58d875 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -24,12 +24,13 @@ #define AA_CLASS_UNKNOWN 1 #define AA_CLASS_FILE 2 #define AA_CLASS_CAP 3 -#define AA_CLASS_NET 4 +#define AA_CLASS_DEPRECATED 4 #define AA_CLASS_RLIMITS 5 #define AA_CLASS_DOMAIN 6 #define AA_CLASS_MOUNT 7 #define AA_CLASS_PTRACE 9 #define AA_CLASS_SIGNAL 10 +#define AA_CLASS_NET 14 #define AA_CLASS_LABEL 16 #define AA_CLASS_LAST AA_CLASS_LABEL diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 41ad2c947bf4..9c9be9c98c15 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -134,6 +134,12 @@ struct apparmor_audit_data { int signal; int unmappedsig; }; + struct { + int type, protocol; + struct sock *peer_sk; + void *addr; + int addrlen; + } net; }; }; struct { diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h new file mode 100644 index 000000000000..ec7228e857a9 --- /dev/null +++ b/security/apparmor/include/net.h @@ -0,0 +1,106 @@ +/* + * AppArmor security module + * + * This file contains AppArmor network mediation 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_NET_H +#define __AA_NET_H + +#include +#include + +#include "apparmorfs.h" +#include "label.h" +#include "perms.h" +#include "policy.h" + +#define AA_MAY_SEND AA_MAY_WRITE +#define AA_MAY_RECEIVE AA_MAY_READ + +#define AA_MAY_SHUTDOWN AA_MAY_DELETE + +#define AA_MAY_CONNECT AA_MAY_OPEN +#define AA_MAY_ACCEPT 0x00100000 + +#define AA_MAY_BIND 0x00200000 +#define AA_MAY_LISTEN 0x00400000 + +#define AA_MAY_SETOPT 0x01000000 +#define AA_MAY_GETOPT 0x02000000 + +#define NET_PERMS_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ + AA_MAY_SHUTDOWN | AA_MAY_BIND | AA_MAY_LISTEN | \ + AA_MAY_CONNECT | AA_MAY_ACCEPT | AA_MAY_SETATTR | \ + AA_MAY_GETATTR | AA_MAY_SETOPT | AA_MAY_GETOPT) + +#define NET_FS_PERMS (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CREATE | \ + AA_MAY_SHUTDOWN | AA_MAY_CONNECT | AA_MAY_RENAME |\ + AA_MAY_SETATTR | AA_MAY_GETATTR | AA_MAY_CHMOD | \ + AA_MAY_CHOWN | AA_MAY_CHGRP | AA_MAY_LOCK | \ + AA_MAY_MPROT) + +#define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ + AA_MAY_ACCEPT) +struct aa_sk_ctx { + struct aa_label *label; + struct aa_label *peer; +}; + +#define SK_CTX(X) ((X)->sk_security) +#define SOCK_ctx(X) SOCK_INODE(X)->i_security +#define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ + struct lsm_network_audit NAME ## _net = { .sk = (SK), \ + .family = (F)}; \ + DEFINE_AUDIT_DATA(NAME, \ + ((SK) && (F) != AF_UNIX) ? LSM_AUDIT_DATA_NET : \ + LSM_AUDIT_DATA_NONE, \ + OP); \ + NAME.u.net = &(NAME ## _net); \ + aad(&NAME)->net.type = (T); \ + aad(&NAME)->net.protocol = (P) + +#define DEFINE_AUDIT_SK(NAME, OP, SK) \ + DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ + (SK)->sk_protocol) + + +#define af_select(FAMILY, FN, DEF_FN) \ +({ \ + int __e; \ + switch ((FAMILY)) { \ + default: \ + __e = DEF_FN; \ + } \ + __e; \ +}) + +extern struct aa_sfs_entry aa_sfs_entry_network[]; + +void audit_net_cb(struct audit_buffer *ab, void *va); +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, + u32 request, u16 family, int type); +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, + int type, int protocol); +static inline int aa_profile_af_sk_perm(struct aa_profile *profile, + struct common_audit_data *sa, + u32 request, + struct sock *sk) +{ + return aa_profile_af_perm(profile, sa, request, sk->sk_family, + sk->sk_type); +} +int aa_sk_perm(const char *op, u32 request, struct sock *sk); + +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock); + +#endif /* __AA_NET_H */ diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index d7b7e7115160..38aa6247d00f 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h @@ -138,9 +138,10 @@ extern struct aa_perms allperms; void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, + u32 mask); void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, - u32 chrsmask, const char **names, u32 namesmask); + u32 chrsmask, const char * const *names, u32 namesmask); 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, diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index c93b9ed55490..ffe12a2366e0 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -30,6 +30,7 @@ #include "file.h" #include "lib.h" #include "label.h" +#include "net.h" #include "perms.h" #include "resource.h" @@ -224,6 +225,16 @@ static inline unsigned int PROFILE_MEDIATES_SAFE(struct aa_profile *profile, return 0; } +static inline unsigned int PROFILE_MEDIATES_AF(struct aa_profile *profile, + u16 AF) { + unsigned int state = PROFILE_MEDIATES(profile, AA_CLASS_NET); + __be16 be_af = cpu_to_be16(AF); + + if (!state) + return 0; + return aa_dfa_match_len(profile->policy.dfa, state, (char *) &be_af, 2); +} + /** * aa_get_profile - increment refcount on profile @p * @p: profile (MAYBE NULL) diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 4d5e98e49d5e..068a9f471f77 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c @@ -211,7 +211,8 @@ void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) *str = '\0'; } -void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) +void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, + u32 mask) { const char *fmt = "%s"; unsigned int i, perm = 1; @@ -229,7 +230,7 @@ void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) } void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, - u32 chrsmask, const char **names, u32 namesmask) + u32 chrsmask, const char * const *names, u32 namesmask) { char str[33]; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index ef6334e11597..956edebf83eb 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -33,6 +33,7 @@ #include "include/cred.h" #include "include/file.h" #include "include/ipc.h" +#include "include/net.h" #include "include/path.h" #include "include/label.h" #include "include/policy.h" @@ -743,6 +744,373 @@ static int apparmor_task_kill(struct task_struct *target, struct siginfo *info, return error; } +/** + * apparmor_sk_alloc_security - allocate and attach the sk_security field + */ +static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) +{ + struct aa_sk_ctx *ctx; + + ctx = kzalloc(sizeof(*ctx), flags); + if (!ctx) + return -ENOMEM; + + SK_CTX(sk) = ctx; + + return 0; +} + +/** + * apparmor_sk_free_security - free the sk_security field + */ +static void apparmor_sk_free_security(struct sock *sk) +{ + struct aa_sk_ctx *ctx = SK_CTX(sk); + + SK_CTX(sk) = NULL; + aa_put_label(ctx->label); + aa_put_label(ctx->peer); + kfree(ctx); +} + +/** + * apparmor_clone_security - clone the sk_security field + */ +static void apparmor_sk_clone_security(const struct sock *sk, + struct sock *newsk) +{ + struct aa_sk_ctx *ctx = SK_CTX(sk); + struct aa_sk_ctx *new = SK_CTX(newsk); + + new->label = aa_get_label(ctx->label); + new->peer = aa_get_label(ctx->peer); +} + +/** + * apparmor_socket_create - check perms before creating a new socket + */ +static int apparmor_socket_create(int family, int type, int protocol, int kern) +{ + struct aa_label *label; + int error = 0; + + AA_BUG(in_interrupt()); + + label = begin_current_label_crit_section(); + if (!(kern || unconfined(label))) + error = af_select(family, + create_perm(label, family, type, protocol), + aa_af_perm(label, OP_CREATE, AA_MAY_CREATE, + family, type, protocol)); + end_current_label_crit_section(label); + + return error; +} + +/** + * apparmor_socket_post_create - setup the per-socket security struct + * + * Note: + * - kernel sockets currently labeled unconfined but we may want to + * move to a special kernel label + * - socket may not have sk here if created with sock_create_lite or + * sock_alloc. These should be accept cases which will be handled in + * sock_graft. + */ +static int apparmor_socket_post_create(struct socket *sock, int family, + int type, int protocol, int kern) +{ + struct aa_label *label; + + if (kern) { + struct aa_ns *ns = aa_get_current_ns(); + + label = aa_get_label(ns_unconfined(ns)); + aa_put_ns(ns); + } else + label = aa_get_current_label(); + + if (sock->sk) { + struct aa_sk_ctx *ctx = SK_CTX(sock->sk); + + aa_put_label(ctx->label); + ctx->label = aa_get_label(label); + } + aa_put_label(label); + + return 0; +} + +/** + * apparmor_socket_bind - check perms before bind addr to socket + */ +static int apparmor_socket_bind(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(!address); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + bind_perm(sock, address, addrlen), + aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk)); +} + +/** + * apparmor_socket_connect - check perms before connecting @sock to @address + */ +static int apparmor_socket_connect(struct socket *sock, + struct sockaddr *address, int addrlen) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(!address); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + connect_perm(sock, address, addrlen), + aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk)); +} + +/** + * apparmor_socket_list - check perms before allowing listen + */ +static int apparmor_socket_listen(struct socket *sock, int backlog) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + listen_perm(sock, backlog), + aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk)); +} + +/** + * apparmor_socket_accept - check perms before accepting a new connection. + * + * Note: while @newsock is created and has some information, the accept + * has not been done. + */ +static int apparmor_socket_accept(struct socket *sock, struct socket *newsock) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(!newsock); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + accept_perm(sock, newsock), + aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk)); +} + +static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, + struct msghdr *msg, int size) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(!msg); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + msg_perm(op, request, sock, msg, size), + aa_sk_perm(op, request, sock->sk)); +} + +/** + * apparmor_socket_sendmsg - check perms before sending msg to another socket + */ +static int apparmor_socket_sendmsg(struct socket *sock, + struct msghdr *msg, int size) +{ + return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size); +} + +/** + * apparmor_socket_recvmsg - check perms before receiving a message + */ +static int apparmor_socket_recvmsg(struct socket *sock, + struct msghdr *msg, int size, int flags) +{ + return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size); +} + +/* revaliation, get/set attr, shutdown */ +static int aa_sock_perm(const char *op, u32 request, struct socket *sock) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + sock_perm(op, request, sock), + aa_sk_perm(op, request, sock->sk)); +} + +/** + * apparmor_socket_getsockname - check perms before getting the local address + */ +static int apparmor_socket_getsockname(struct socket *sock) +{ + return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock); +} + +/** + * apparmor_socket_getpeername - check perms before getting remote address + */ +static int apparmor_socket_getpeername(struct socket *sock) +{ + return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock); +} + +/* revaliation, get/set attr, opt */ +static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, + int level, int optname) +{ + AA_BUG(!sock); + AA_BUG(!sock->sk); + AA_BUG(in_interrupt()); + + return af_select(sock->sk->sk_family, + opt_perm(op, request, sock, level, optname), + aa_sk_perm(op, request, sock->sk)); +} + +/** + * apparmor_getsockopt - check perms before getting socket options + */ +static int apparmor_socket_getsockopt(struct socket *sock, int level, + int optname) +{ + return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock, + level, optname); +} + +/** + * apparmor_setsockopt - check perms before setting socket options + */ +static int apparmor_socket_setsockopt(struct socket *sock, int level, + int optname) +{ + return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock, + level, optname); +} + +/** + * apparmor_socket_shutdown - check perms before shutting down @sock conn + */ +static int apparmor_socket_shutdown(struct socket *sock, int how) +{ + return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); +} + +/** + * apparmor_socket_sock_recv_skb - check perms before associating skb to sk + * + * Note: can not sleep may be called with locks held + * + * dont want protocol specific in __skb_recv_datagram() + * to deny an incoming connection socket_sock_rcv_skb() + */ +static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) +{ + return 0; +} + + +static struct aa_label *sk_peer_label(struct sock *sk) +{ + struct aa_sk_ctx *ctx = SK_CTX(sk); + + if (ctx->peer) + return ctx->peer; + + return ERR_PTR(-ENOPROTOOPT); +} + +/** + * apparmor_socket_getpeersec_stream - get security context of peer + * + * Note: for tcp only valid if using ipsec or cipso on lan + */ +static int apparmor_socket_getpeersec_stream(struct socket *sock, + char __user *optval, + int __user *optlen, + unsigned int len) +{ + char *name; + int slen, error = 0; + struct aa_label *label; + struct aa_label *peer; + + label = begin_current_label_crit_section(); + peer = sk_peer_label(sock->sk); + if (IS_ERR(peer)) { + error = PTR_ERR(peer); + goto done; + } + slen = aa_label_asxprint(&name, labels_ns(label), peer, + FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | + FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); + /* don't include terminating \0 in slen, it breaks some apps */ + if (slen < 0) { + error = -ENOMEM; + } else { + if (slen > len) { + error = -ERANGE; + } else if (copy_to_user(optval, name, slen)) { + error = -EFAULT; + goto out; + } + if (put_user(slen, optlen)) + error = -EFAULT; +out: + kfree(name); + + } + +done: + end_current_label_crit_section(label); + + return error; +} + +/** + * apparmor_socket_getpeersec_dgram - get security label of packet + * @sock: the peer socket + * @skb: packet data + * @secid: pointer to where to put the secid of the packet + * + * Sets the netlabel socket state on sk from parent + */ +static int apparmor_socket_getpeersec_dgram(struct socket *sock, + struct sk_buff *skb, u32 *secid) + +{ + /* TODO: requires secid support */ + return -ENOPROTOOPT; +} + +/** + * apparmor_sock_graft - Initialize newly created socket + * @sk: child sock + * @parent: parent socket + * + * Note: could set off of SOCK_CTX(parent) but need to track inode and we can + * just set sk security information off of current creating process label + * Labeling of sk for accept case - probably should be sock based + * instead of task, because of the case where an implicitly labeled + * socket is shared by different tasks. + */ +static void apparmor_sock_graft(struct sock *sk, struct socket *parent) +{ + struct aa_sk_ctx *ctx = SK_CTX(sk); + + if (!ctx->label) + ctx->label = aa_get_current_label(); +} + static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), @@ -777,6 +1145,30 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), + LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), + LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), + LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), + + LSM_HOOK_INIT(socket_create, apparmor_socket_create), + LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), + LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), + LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), + LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), + LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), + LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), + LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), + LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), + LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), + LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), + LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), + LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), + LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), + LSM_HOOK_INIT(socket_getpeersec_stream, + apparmor_socket_getpeersec_stream), + LSM_HOOK_INIT(socket_getpeersec_dgram, + apparmor_socket_getpeersec_dgram), + LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), + LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), LSM_HOOK_INIT(cred_free, apparmor_cred_free), LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), diff --git a/security/apparmor/net.c b/security/apparmor/net.c new file mode 100644 index 000000000000..bb24cfa0a164 --- /dev/null +++ b/security/apparmor/net.c @@ -0,0 +1,187 @@ +/* + * AppArmor security module + * + * This file contains AppArmor network mediation + * + * 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. + */ + +#include "include/apparmor.h" +#include "include/audit.h" +#include "include/cred.h" +#include "include/label.h" +#include "include/net.h" +#include "include/policy.h" + +#include "net_names.h" + + +struct aa_sfs_entry aa_sfs_entry_network[] = { + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), + { } +}; + +static const char * const net_mask_names[] = { + "unknown", + "send", + "receive", + "unknown", + + "create", + "shutdown", + "connect", + "unknown", + + "setattr", + "getattr", + "setcred", + "getcred", + + "chmod", + "chown", + "chgrp", + "lock", + + "mmap", + "mprot", + "unknown", + "unknown", + + "accept", + "bind", + "listen", + "unknown", + + "setopt", + "getopt", + "unknown", + "unknown", + + "unknown", + "unknown", + "unknown", + "unknown", +}; + + +/* audit callback for net specific fields */ +void audit_net_cb(struct audit_buffer *ab, void *va) +{ + struct common_audit_data *sa = va; + + audit_log_format(ab, " family="); + if (address_family_names[sa->u.net->family]) + audit_log_string(ab, address_family_names[sa->u.net->family]); + else + audit_log_format(ab, "\"unknown(%d)\"", sa->u.net->family); + audit_log_format(ab, " sock_type="); + if (sock_type_names[aad(sa)->net.type]) + audit_log_string(ab, sock_type_names[aad(sa)->net.type]); + else + audit_log_format(ab, "\"unknown(%d)\"", aad(sa)->net.type); + audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol); + + if (aad(sa)->request & NET_PERMS_MASK) { + audit_log_format(ab, " requested_mask="); + aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0, + net_mask_names, NET_PERMS_MASK); + + if (aad(sa)->denied & NET_PERMS_MASK) { + audit_log_format(ab, " denied_mask="); + aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0, + net_mask_names, NET_PERMS_MASK); + } + } + if (aad(sa)->peer) { + audit_log_format(ab, " peer="); + aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, + FLAGS_NONE, GFP_ATOMIC); + } +} + +/* Generic af perm */ +int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa, + u32 request, u16 family, int type) +{ + struct aa_perms perms = { }; + unsigned int state; + __be16 buffer[2]; + + AA_BUG(family >= AF_MAX); + AA_BUG(type < 0 || type >= SOCK_MAX); + + if (profile_unconfined(profile)) + return 0; + state = PROFILE_MEDIATES(profile, AA_CLASS_NET); + if (!state) + return 0; + + buffer[0] = cpu_to_be16(family); + buffer[1] = cpu_to_be16((u16) type); + state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer, + 4); + aa_compute_perms(profile->policy.dfa, state, &perms); + aa_apply_modes_to_perms(profile, &perms); + + return aa_check_perms(profile, &perms, request, sa, audit_net_cb); +} + +int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family, + int type, int protocol) +{ + struct aa_profile *profile; + DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol); + + return fn_for_each_confined(label, profile, + aa_profile_af_perm(profile, &sa, request, family, + type)); +} + +static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request, + struct sock *sk) +{ + struct aa_profile *profile; + DEFINE_AUDIT_SK(sa, op, sk); + + AA_BUG(!label); + AA_BUG(!sk); + + if (unconfined(label)) + return 0; + + return fn_for_each_confined(label, profile, + aa_profile_af_sk_perm(profile, &sa, request, sk)); +} + +int aa_sk_perm(const char *op, u32 request, struct sock *sk) +{ + struct aa_label *label; + int error; + + AA_BUG(!sk); + AA_BUG(in_interrupt()); + + /* TODO: switch to begin_current_label ???? */ + label = begin_current_label_crit_section(); + error = aa_label_sk_perm(label, op, request, sk); + end_current_label_crit_section(label); + + return error; +} + + +int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request, + struct socket *sock) +{ + AA_BUG(!label); + AA_BUG(!sock); + AA_BUG(!sock->sk); + + return aa_label_sk_perm(label, op, request, sock->sk); +} diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 8a31ddd474d7..b9e6b2cafa69 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c @@ -37,7 +37,8 @@ #define v5 5 /* base version */ #define v6 6 /* per entry policydb mediation check */ -#define v7 7 /* full network masking */ +#define v7 7 +#define v8 8 /* full network masking */ /* * The AppArmor interface treats data as a type byte followed by the -- cgit v1.2.3