KVM: x86: create mmu/ subdirectory
[linux-2.6-block.git] / security / apparmor / task.c
CommitLineData
b886d83c 1// SPDX-License-Identifier: GPL-2.0-only
c75afcd1
JJ
2/*
3 * AppArmor security module
4 *
de62de59 5 * This file contains AppArmor task related definitions and mediation
c75afcd1 6 *
de62de59 7 * Copyright 2017 Canonical Ltd.
c75afcd1 8 *
c75afcd1
JJ
9 * TODO
10 * If a task uses change_hat it currently does not return to the old
11 * cred or task context but instead creates a new one. Ideally the task
12 * should return to the previous cred if it has not been modified.
c75afcd1
JJ
13 */
14
d8889d49 15#include "include/cred.h"
de62de59 16#include "include/task.h"
c75afcd1 17
3cfcc19e 18/**
637f688d 19 * aa_get_task_label - Get another task's label
3cfcc19e
JJ
20 * @task: task to query (NOT NULL)
21 *
637f688d 22 * Returns: counted reference to @task's label
3cfcc19e 23 */
637f688d 24struct aa_label *aa_get_task_label(struct task_struct *task)
3cfcc19e 25{
637f688d 26 struct aa_label *p;
3cfcc19e
JJ
27
28 rcu_read_lock();
637f688d 29 p = aa_get_newest_label(__aa_task_raw_label(task));
3cfcc19e
JJ
30 rcu_read_unlock();
31
32 return p;
33}
34
c75afcd1 35/**
637f688d
JJ
36 * aa_replace_current_label - replace the current tasks label
37 * @label: new label (NOT NULL)
c75afcd1
JJ
38 *
39 * Returns: 0 or error on failure
40 */
637f688d 41int aa_replace_current_label(struct aa_label *label)
c75afcd1 42{
d9087c49 43 struct aa_label *old = aa_current_raw_label();
9fcf78cc 44 struct aa_task_ctx *ctx = task_ctx(current);
c75afcd1 45 struct cred *new;
d9087c49 46
637f688d 47 AA_BUG(!label);
c75afcd1 48
d9087c49 49 if (old == label)
c75afcd1
JJ
50 return 0;
51
a20aa95f
JJ
52 if (current_cred() != current_real_cred())
53 return -EBUSY;
54
c75afcd1
JJ
55 new = prepare_creds();
56 if (!new)
57 return -ENOMEM;
58
9fcf78cc
JJ
59 if (ctx->nnp && label_is_stale(ctx->nnp)) {
60 struct aa_label *tmp = ctx->nnp;
61
62 ctx->nnp = aa_get_newest_label(tmp);
63 aa_put_label(tmp);
64 }
d9087c49
JJ
65 if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
66 /*
67 * if switching to unconfined or a different label namespace
c75afcd1
JJ
68 * clear out context state
69 */
de62de59 70 aa_clear_task_ctx_trans(task_ctx(current));
7a2871b5 71
55a26ebf 72 /*
d9087c49
JJ
73 * be careful switching cred label, when racing replacement it
74 * is possible that the cred labels's->proxy->label is the reference
75 * keeping @label valid, so make sure to get its reference before
76 * dropping the reference on the cred's label
55a26ebf 77 */
637f688d 78 aa_get_label(label);
d9087c49 79 aa_put_label(cred_label(new));
69b5a44a 80 set_cred_label(new, label);
c75afcd1
JJ
81
82 commit_creds(new);
83 return 0;
84}
85
de62de59 86
c75afcd1
JJ
87/**
88 * aa_set_current_onexec - set the tasks change_profile to happen onexec
637f688d
JJ
89 * @label: system label to set at exec (MAYBE NULL to clear value)
90 * @stack: whether stacking should be done
c75afcd1
JJ
91 * Returns: 0 or error on failure
92 */
637f688d 93int aa_set_current_onexec(struct aa_label *label, bool stack)
c75afcd1 94{
de62de59 95 struct aa_task_ctx *ctx = task_ctx(current);
c75afcd1 96
637f688d 97 aa_get_label(label);
3b529a76 98 aa_put_label(ctx->onexec);
637f688d
JJ
99 ctx->onexec = label;
100 ctx->token = stack;
c75afcd1 101
c75afcd1
JJ
102 return 0;
103}
104
105/**
106 * aa_set_current_hat - set the current tasks hat
637f688d 107 * @label: label to set as the current hat (NOT NULL)
c75afcd1
JJ
108 * @token: token value that must be specified to change from the hat
109 *
110 * Do switch of tasks hat. If the task is currently in a hat
111 * validate the token to match.
112 *
113 * Returns: 0 or error on failure
114 */
637f688d 115int aa_set_current_hat(struct aa_label *label, u64 token)
c75afcd1 116{
de62de59 117 struct aa_task_ctx *ctx = task_ctx(current);
d9087c49 118 struct cred *new;
3b529a76 119
d9087c49 120 new = prepare_creds();
c75afcd1
JJ
121 if (!new)
122 return -ENOMEM;
637f688d 123 AA_BUG(!label);
c75afcd1 124
f175221a 125 if (!ctx->previous) {
c75afcd1 126 /* transfer refcount */
f175221a
JJ
127 ctx->previous = cred_label(new);
128 ctx->token = token;
129 } else if (ctx->token == token) {
d9087c49 130 aa_put_label(cred_label(new));
c75afcd1 131 } else {
55a26ebf 132 /* previous_profile && ctx->token != token */
c75afcd1
JJ
133 abort_creds(new);
134 return -EACCES;
135 }
3b529a76 136
69b5a44a 137 set_cred_label(new, aa_get_newest_label(label));
c75afcd1 138 /* clear exec on switching context */
f175221a
JJ
139 aa_put_label(ctx->onexec);
140 ctx->onexec = NULL;
c75afcd1
JJ
141
142 commit_creds(new);
143 return 0;
144}
145
146/**
637f688d 147 * aa_restore_previous_label - exit from hat context restoring previous label
c75afcd1
JJ
148 * @token: the token that must be matched to exit hat context
149 *
637f688d 150 * Attempt to return out of a hat to the previous label. The token
c75afcd1
JJ
151 * must match the stored token value.
152 *
153 * Returns: 0 or error of failure
154 */
637f688d 155int aa_restore_previous_label(u64 token)
c75afcd1 156{
de62de59 157 struct aa_task_ctx *ctx = task_ctx(current);
3b529a76 158 struct cred *new;
c75afcd1 159
f175221a 160 if (ctx->token != token)
c75afcd1 161 return -EACCES;
637f688d 162 /* ignore restores when there is no saved label */
f175221a 163 if (!ctx->previous)
c75afcd1 164 return 0;
3b529a76
JJ
165
166 new = prepare_creds();
167 if (!new)
168 return -ENOMEM;
c75afcd1 169
d9087c49 170 aa_put_label(cred_label(new));
69b5a44a 171 set_cred_label(new, aa_get_newest_label(ctx->previous));
d9087c49 172 AA_BUG(!cred_label(new));
7a2871b5 173 /* clear exec && prev information when restoring to previous context */
f175221a 174 aa_clear_task_ctx_trans(ctx);
c75afcd1
JJ
175
176 commit_creds(new);
3b529a76 177
c75afcd1
JJ
178 return 0;
179}