Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/security/apparmor/task.c
26377 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* AppArmor security module
4
*
5
* This file contains AppArmor task related definitions and mediation
6
*
7
* Copyright 2017 Canonical Ltd.
8
*
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.
13
*/
14
15
#include <linux/gfp.h>
16
#include <linux/ptrace.h>
17
18
#include "include/audit.h"
19
#include "include/cred.h"
20
#include "include/policy.h"
21
#include "include/task.h"
22
23
/**
24
* aa_get_task_label - Get another task's label
25
* @task: task to query (NOT NULL)
26
*
27
* Returns: counted reference to @task's label
28
*/
29
struct aa_label *aa_get_task_label(struct task_struct *task)
30
{
31
struct aa_label *p;
32
33
rcu_read_lock();
34
p = aa_get_newest_cred_label(__task_cred(task));
35
rcu_read_unlock();
36
37
return p;
38
}
39
40
/**
41
* aa_replace_current_label - replace the current tasks label
42
* @label: new label (NOT NULL)
43
*
44
* Returns: 0 or error on failure
45
*/
46
int aa_replace_current_label(struct aa_label *label)
47
{
48
struct aa_label *old = aa_current_raw_label();
49
struct aa_task_ctx *ctx = task_ctx(current);
50
struct cred *new;
51
52
AA_BUG(!label);
53
54
if (old == label)
55
return 0;
56
57
if (current_cred() != current_real_cred())
58
return -EBUSY;
59
60
new = prepare_creds();
61
if (!new)
62
return -ENOMEM;
63
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
}
70
if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
71
/*
72
* if switching to unconfined or a different label namespace
73
* clear out context state
74
*/
75
aa_clear_task_ctx_trans(task_ctx(current));
76
77
/*
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
82
*/
83
aa_get_label(label);
84
aa_put_label(cred_label(new));
85
set_cred_label(new, label);
86
87
commit_creds(new);
88
return 0;
89
}
90
91
92
/**
93
* aa_set_current_onexec - set the tasks change_profile to happen onexec
94
* @label: system label to set at exec (MAYBE NULL to clear value)
95
* @stack: whether stacking should be done
96
*/
97
void aa_set_current_onexec(struct aa_label *label, bool stack)
98
{
99
struct aa_task_ctx *ctx = task_ctx(current);
100
101
aa_get_label(label);
102
aa_put_label(ctx->onexec);
103
ctx->onexec = label;
104
ctx->token = stack;
105
}
106
107
/**
108
* aa_set_current_hat - set the current tasks hat
109
* @label: label to set as the current hat (NOT NULL)
110
* @token: token value that must be specified to change from the hat
111
*
112
* Do switch of tasks hat. If the task is currently in a hat
113
* validate the token to match.
114
*
115
* Returns: 0 or error on failure
116
*/
117
int aa_set_current_hat(struct aa_label *label, u64 token)
118
{
119
struct aa_task_ctx *ctx = task_ctx(current);
120
struct cred *new;
121
122
new = prepare_creds();
123
if (!new)
124
return -ENOMEM;
125
AA_BUG(!label);
126
127
if (!ctx->previous) {
128
/* transfer refcount */
129
ctx->previous = cred_label(new);
130
ctx->token = token;
131
} else if (ctx->token == token) {
132
aa_put_label(cred_label(new));
133
} else {
134
/* previous_profile && ctx->token != token */
135
abort_creds(new);
136
return -EACCES;
137
}
138
139
set_cred_label(new, aa_get_newest_label(label));
140
/* clear exec on switching context */
141
aa_put_label(ctx->onexec);
142
ctx->onexec = NULL;
143
144
commit_creds(new);
145
return 0;
146
}
147
148
/**
149
* aa_restore_previous_label - exit from hat context restoring previous label
150
* @token: the token that must be matched to exit hat context
151
*
152
* Attempt to return out of a hat to the previous label. The token
153
* must match the stored token value.
154
*
155
* Returns: 0 or error of failure
156
*/
157
int aa_restore_previous_label(u64 token)
158
{
159
struct aa_task_ctx *ctx = task_ctx(current);
160
struct cred *new;
161
162
if (ctx->token != token)
163
return -EACCES;
164
/* ignore restores when there is no saved label */
165
if (!ctx->previous)
166
return 0;
167
168
new = prepare_creds();
169
if (!new)
170
return -ENOMEM;
171
172
aa_put_label(cred_label(new));
173
set_cred_label(new, aa_get_newest_label(ctx->previous));
174
AA_BUG(!cred_label(new));
175
/* clear exec && prev information when restoring to previous context */
176
aa_clear_task_ctx_trans(ctx);
177
178
commit_creds(new);
179
180
return 0;
181
}
182
183
/**
184
* audit_ptrace_mask - convert mask to permission string
185
* @mask: permission mask to convert
186
*
187
* Returns: pointer to static string
188
*/
189
static const char *audit_ptrace_mask(u32 mask)
190
{
191
switch (mask) {
192
case MAY_READ:
193
return "read";
194
case MAY_WRITE:
195
return "trace";
196
case AA_MAY_BE_READ:
197
return "readby";
198
case AA_MAY_BE_TRACED:
199
return "tracedby";
200
}
201
return "";
202
}
203
204
/* call back to audit ptrace fields */
205
static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
206
{
207
struct common_audit_data *sa = va;
208
struct apparmor_audit_data *ad = aad(sa);
209
210
if (ad->request & AA_PTRACE_PERM_MASK) {
211
audit_log_format(ab, " requested_mask=\"%s\"",
212
audit_ptrace_mask(ad->request));
213
214
if (ad->denied & AA_PTRACE_PERM_MASK) {
215
audit_log_format(ab, " denied_mask=\"%s\"",
216
audit_ptrace_mask(ad->denied));
217
}
218
}
219
audit_log_format(ab, " peer=");
220
aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
221
FLAGS_NONE, GFP_ATOMIC);
222
}
223
224
/* assumes check for RULE_MEDIATES is already done */
225
/* TODO: conditionals */
226
static int profile_ptrace_perm(const struct cred *cred,
227
struct aa_profile *profile,
228
struct aa_label *peer, u32 request,
229
struct apparmor_audit_data *ad)
230
{
231
struct aa_ruleset *rules = profile->label.rules[0];
232
struct aa_perms perms = { };
233
234
ad->subj_cred = cred;
235
ad->peer = peer;
236
aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
237
&perms);
238
aa_apply_modes_to_perms(profile, &perms);
239
return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb);
240
}
241
242
static int profile_tracee_perm(const struct cred *cred,
243
struct aa_profile *tracee,
244
struct aa_label *tracer, u32 request,
245
struct apparmor_audit_data *ad)
246
{
247
if (profile_unconfined(tracee) || unconfined(tracer) ||
248
!label_mediates(&tracee->label, AA_CLASS_PTRACE))
249
return 0;
250
251
return profile_ptrace_perm(cred, tracee, tracer, request, ad);
252
}
253
254
static int profile_tracer_perm(const struct cred *cred,
255
struct aa_profile *tracer,
256
struct aa_label *tracee, u32 request,
257
struct apparmor_audit_data *ad)
258
{
259
if (profile_unconfined(tracer))
260
return 0;
261
262
if (label_mediates(&tracer->label, AA_CLASS_PTRACE))
263
return profile_ptrace_perm(cred, tracer, tracee, request, ad);
264
265
/* profile uses the old style capability check for ptrace */
266
if (&tracer->label == tracee)
267
return 0;
268
269
ad->subj_label = &tracer->label;
270
ad->peer = tracee;
271
ad->request = 0;
272
ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
273
CAP_OPT_NONE);
274
275
return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb);
276
}
277
278
/**
279
* aa_may_ptrace - test if tracer task can trace the tracee
280
* @tracer_cred: cred of task doing the tracing (NOT NULL)
281
* @tracer: label of the task doing the tracing (NOT NULL)
282
* @tracee_cred: cred of task to be traced
283
* @tracee: task label to be traced
284
* @request: permission request
285
*
286
* Returns: %0 else error code if permission denied or error
287
*/
288
int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
289
const struct cred *tracee_cred, struct aa_label *tracee,
290
u32 request)
291
{
292
struct aa_profile *profile;
293
u32 xrequest = request << PTRACE_PERM_SHIFT;
294
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
295
296
return xcheck_labels(tracer, tracee, profile,
297
profile_tracer_perm(tracer_cred, profile, tracee,
298
request, &sa),
299
profile_tracee_perm(tracee_cred, profile, tracer,
300
xrequest, &sa));
301
}
302
303
/* call back to audit ptrace fields */
304
static void audit_ns_cb(struct audit_buffer *ab, void *va)
305
{
306
struct apparmor_audit_data *ad = aad_of_va(va);
307
308
if (ad->request & AA_USERNS_CREATE)
309
audit_log_format(ab, " requested=\"userns_create\"");
310
311
if (ad->denied & AA_USERNS_CREATE)
312
audit_log_format(ab, " denied=\"userns_create\"");
313
}
314
315
int aa_profile_ns_perm(struct aa_profile *profile,
316
struct apparmor_audit_data *ad,
317
u32 request)
318
{
319
struct aa_perms perms = { };
320
int error = 0;
321
322
ad->subj_label = &profile->label;
323
ad->request = request;
324
325
if (!profile_unconfined(profile)) {
326
struct aa_ruleset *rules = profile->label.rules[0];
327
aa_state_t state;
328
329
state = RULE_MEDIATES(rules, ad->class);
330
if (!state)
331
/* TODO: add flag to complain about unmediated */
332
return 0;
333
perms = *aa_lookup_perms(rules->policy, state);
334
aa_apply_modes_to_perms(profile, &perms);
335
error = aa_check_perms(profile, &perms, request, ad,
336
audit_ns_cb);
337
}
338
339
return error;
340
}
341
342