Merge tag 'printk-for-6.6-fixup' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-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
eac93125
JJ
15#include <linux/gfp.h>
16#include <linux/ptrace.h>
17
18#include "include/audit.h"
d8889d49 19#include "include/cred.h"
eac93125 20#include "include/policy.h"
de62de59 21#include "include/task.h"
c75afcd1 22
3cfcc19e 23/**
637f688d 24 * aa_get_task_label - Get another task's label
3cfcc19e
JJ
25 * @task: task to query (NOT NULL)
26 *
637f688d 27 * Returns: counted reference to @task's label
3cfcc19e 28 */
637f688d 29struct aa_label *aa_get_task_label(struct task_struct *task)
3cfcc19e 30{
637f688d 31 struct aa_label *p;
3cfcc19e
JJ
32
33 rcu_read_lock();
adaa9a3f 34 p = aa_get_newest_cred_label(__task_cred(task));
3cfcc19e
JJ
35 rcu_read_unlock();
36
37 return p;
38}
39
c75afcd1 40/**
637f688d
JJ
41 * aa_replace_current_label - replace the current tasks label
42 * @label: new label (NOT NULL)
c75afcd1
JJ
43 *
44 * Returns: 0 or error on failure
45 */
637f688d 46int aa_replace_current_label(struct aa_label *label)
c75afcd1 47{
d9087c49 48 struct aa_label *old = aa_current_raw_label();
9fcf78cc 49 struct aa_task_ctx *ctx = task_ctx(current);
c75afcd1 50 struct cred *new;
d9087c49 51
637f688d 52 AA_BUG(!label);
c75afcd1 53
d9087c49 54 if (old == label)
c75afcd1
JJ
55 return 0;
56
a20aa95f
JJ
57 if (current_cred() != current_real_cred())
58 return -EBUSY;
59
c75afcd1
JJ
60 new = prepare_creds();
61 if (!new)
62 return -ENOMEM;
63
9fcf78cc
JJ
64 if (ctx->nnp && label_is_stale(ctx->nnp)) {
65 struct aa_label *tmp = ctx->nnp;
66
67 ctx->nnp = aa_get_newest_label(tmp);
68 aa_put_label(tmp);
69 }
d9087c49
JJ
70 if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
71 /*
72 * if switching to unconfined or a different label namespace
c75afcd1
JJ
73 * clear out context state
74 */
de62de59 75 aa_clear_task_ctx_trans(task_ctx(current));
7a2871b5 76
55a26ebf 77 /*
d9087c49
JJ
78 * be careful switching cred label, when racing replacement it
79 * is possible that the cred labels's->proxy->label is the reference
80 * keeping @label valid, so make sure to get its reference before
81 * dropping the reference on the cred's label
55a26ebf 82 */
637f688d 83 aa_get_label(label);
d9087c49 84 aa_put_label(cred_label(new));
69b5a44a 85 set_cred_label(new, label);
c75afcd1
JJ
86
87 commit_creds(new);
88 return 0;
89}
90
de62de59 91
c75afcd1
JJ
92/**
93 * aa_set_current_onexec - set the tasks change_profile to happen onexec
637f688d
JJ
94 * @label: system label to set at exec (MAYBE NULL to clear value)
95 * @stack: whether stacking should be done
c75afcd1
JJ
96 * Returns: 0 or error on failure
97 */
637f688d 98int aa_set_current_onexec(struct aa_label *label, bool stack)
c75afcd1 99{
de62de59 100 struct aa_task_ctx *ctx = task_ctx(current);
c75afcd1 101
637f688d 102 aa_get_label(label);
3b529a76 103 aa_put_label(ctx->onexec);
637f688d
JJ
104 ctx->onexec = label;
105 ctx->token = stack;
c75afcd1 106
c75afcd1
JJ
107 return 0;
108}
109
110/**
111 * aa_set_current_hat - set the current tasks hat
637f688d 112 * @label: label to set as the current hat (NOT NULL)
c75afcd1
JJ
113 * @token: token value that must be specified to change from the hat
114 *
115 * Do switch of tasks hat. If the task is currently in a hat
116 * validate the token to match.
117 *
118 * Returns: 0 or error on failure
119 */
637f688d 120int aa_set_current_hat(struct aa_label *label, u64 token)
c75afcd1 121{
de62de59 122 struct aa_task_ctx *ctx = task_ctx(current);
d9087c49 123 struct cred *new;
3b529a76 124
d9087c49 125 new = prepare_creds();
c75afcd1
JJ
126 if (!new)
127 return -ENOMEM;
637f688d 128 AA_BUG(!label);
c75afcd1 129
f175221a 130 if (!ctx->previous) {
c75afcd1 131 /* transfer refcount */
f175221a
JJ
132 ctx->previous = cred_label(new);
133 ctx->token = token;
134 } else if (ctx->token == token) {
d9087c49 135 aa_put_label(cred_label(new));
c75afcd1 136 } else {
55a26ebf 137 /* previous_profile && ctx->token != token */
c75afcd1
JJ
138 abort_creds(new);
139 return -EACCES;
140 }
3b529a76 141
69b5a44a 142 set_cred_label(new, aa_get_newest_label(label));
c75afcd1 143 /* clear exec on switching context */
f175221a
JJ
144 aa_put_label(ctx->onexec);
145 ctx->onexec = NULL;
c75afcd1
JJ
146
147 commit_creds(new);
148 return 0;
149}
150
151/**
637f688d 152 * aa_restore_previous_label - exit from hat context restoring previous label
c75afcd1
JJ
153 * @token: the token that must be matched to exit hat context
154 *
637f688d 155 * Attempt to return out of a hat to the previous label. The token
c75afcd1
JJ
156 * must match the stored token value.
157 *
158 * Returns: 0 or error of failure
159 */
637f688d 160int aa_restore_previous_label(u64 token)
c75afcd1 161{
de62de59 162 struct aa_task_ctx *ctx = task_ctx(current);
3b529a76 163 struct cred *new;
c75afcd1 164
f175221a 165 if (ctx->token != token)
c75afcd1 166 return -EACCES;
637f688d 167 /* ignore restores when there is no saved label */
f175221a 168 if (!ctx->previous)
c75afcd1 169 return 0;
3b529a76
JJ
170
171 new = prepare_creds();
172 if (!new)
173 return -ENOMEM;
c75afcd1 174
d9087c49 175 aa_put_label(cred_label(new));
69b5a44a 176 set_cred_label(new, aa_get_newest_label(ctx->previous));
d9087c49 177 AA_BUG(!cred_label(new));
7a2871b5 178 /* clear exec && prev information when restoring to previous context */
f175221a 179 aa_clear_task_ctx_trans(ctx);
c75afcd1
JJ
180
181 commit_creds(new);
3b529a76 182
c75afcd1
JJ
183 return 0;
184}
eac93125
JJ
185
186/**
187 * audit_ptrace_mask - convert mask to permission string
188 * @mask: permission mask to convert
189 *
190 * Returns: pointer to static string
191 */
192static const char *audit_ptrace_mask(u32 mask)
193{
194 switch (mask) {
195 case MAY_READ:
196 return "read";
197 case MAY_WRITE:
198 return "trace";
199 case AA_MAY_BE_READ:
200 return "readby";
201 case AA_MAY_BE_TRACED:
202 return "tracedby";
203 }
204 return "";
205}
206
207/* call back to audit ptrace fields */
208static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
209{
210 struct common_audit_data *sa = va;
211
212 if (aad(sa)->request & AA_PTRACE_PERM_MASK) {
213 audit_log_format(ab, " requested_mask=\"%s\"",
214 audit_ptrace_mask(aad(sa)->request));
215
216 if (aad(sa)->denied & AA_PTRACE_PERM_MASK) {
217 audit_log_format(ab, " denied_mask=\"%s\"",
218 audit_ptrace_mask(aad(sa)->denied));
219 }
220 }
221 audit_log_format(ab, " peer=");
222 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
223 FLAGS_NONE, GFP_ATOMIC);
224}
225
217af7e2 226/* assumes check for RULE_MEDIATES is already done */
eac93125
JJ
227/* TODO: conditionals */
228static int profile_ptrace_perm(struct aa_profile *profile,
229 struct aa_label *peer, u32 request,
230 struct common_audit_data *sa)
231{
1ad22fcc
JJ
232 struct aa_ruleset *rules = list_first_entry(&profile->rules,
233 typeof(*rules), list);
eac93125
JJ
234 struct aa_perms perms = { };
235
236 aad(sa)->peer = peer;
1ad22fcc
JJ
237 aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
238 &perms);
eac93125
JJ
239 aa_apply_modes_to_perms(profile, &perms);
240 return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb);
241}
242
243static int profile_tracee_perm(struct aa_profile *tracee,
244 struct aa_label *tracer, u32 request,
245 struct common_audit_data *sa)
246{
247 if (profile_unconfined(tracee) || unconfined(tracer) ||
1ad22fcc 248 !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
eac93125
JJ
249 return 0;
250
251 return profile_ptrace_perm(tracee, tracer, request, sa);
252}
253
254static int profile_tracer_perm(struct aa_profile *tracer,
255 struct aa_label *tracee, u32 request,
256 struct common_audit_data *sa)
257{
258 if (profile_unconfined(tracer))
259 return 0;
260
1ad22fcc 261 if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
eac93125
JJ
262 return profile_ptrace_perm(tracer, tracee, request, sa);
263
264 /* profile uses the old style capability check for ptrace */
265 if (&tracer->label == tracee)
266 return 0;
267
268 aad(sa)->label = &tracer->label;
269 aad(sa)->peer = tracee;
270 aad(sa)->request = 0;
271 aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE,
272 CAP_OPT_NONE);
273
274 return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb);
275}
276
277/**
278 * aa_may_ptrace - test if tracer task can trace the tracee
279 * @tracer: label of the task doing the tracing (NOT NULL)
280 * @tracee: task label to be traced
281 * @request: permission request
282 *
283 * Returns: %0 else error code if permission denied or error
284 */
285int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
286 u32 request)
287{
288 struct aa_profile *profile;
289 u32 xrequest = request << PTRACE_PERM_SHIFT;
8c4b785a 290 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
eac93125
JJ
291
292 return xcheck_labels(tracer, tracee, profile,
293 profile_tracer_perm(profile, tracee, request, &sa),
294 profile_tracee_perm(profile, tracer, xrequest, &sa));
295}