summaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorJohn Johansen <john.johansen@canonical.com>2017-01-20 01:59:25 -0800
committerJohn Johansen <john.johansen@canonical.com>2018-02-09 11:30:01 -0800
commit3b529a7600d834f450ac244f43a7c082687284b4 (patch)
tree76cfaede7be88ba9890f4cca4533e6bf69ef360a /security
parent4d2f8ba3e3b76e34f84ae1de456934713e9e59af (diff)
downloadlinux-3b529a7600d834f450ac244f43a7c082687284b4.tar.gz
linux-3b529a7600d834f450ac244f43a7c082687284b4.tar.xz
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 <john.johansen@canonical.com>
Diffstat (limited to 'security')
-rw-r--r--security/apparmor/context.c91
-rw-r--r--security/apparmor/domain.c14
-rw-r--r--security/apparmor/include/context.h31
-rw-r--r--security/apparmor/lsm.c48
4 files changed, 132 insertions, 52 deletions
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);
}
/**
@@ -86,6 +82,43 @@ 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
+ */
+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)