Linux 6.9-rc1
[linux-2.6-microblaze.git] / security / apparmor / task.c
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 = list_first_entry(&profile->rules,
232                                                     typeof(*rules), list);
233         struct aa_perms perms = { };
234
235         ad->subj_cred = cred;
236         ad->peer = peer;
237         aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
238                                &perms);
239         aa_apply_modes_to_perms(profile, &perms);
240         return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb);
241 }
242
243 static int profile_tracee_perm(const struct cred *cred,
244                                struct aa_profile *tracee,
245                                struct aa_label *tracer, u32 request,
246                                struct apparmor_audit_data *ad)
247 {
248         if (profile_unconfined(tracee) || unconfined(tracer) ||
249             !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
250                 return 0;
251
252         return profile_ptrace_perm(cred, tracee, tracer, request, ad);
253 }
254
255 static int profile_tracer_perm(const struct cred *cred,
256                                struct aa_profile *tracer,
257                                struct aa_label *tracee, u32 request,
258                                struct apparmor_audit_data *ad)
259 {
260         if (profile_unconfined(tracer))
261                 return 0;
262
263         if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
264                 return profile_ptrace_perm(cred, tracer, tracee, request, ad);
265
266         /* profile uses the old style capability check for ptrace */
267         if (&tracer->label == tracee)
268                 return 0;
269
270         ad->subj_label = &tracer->label;
271         ad->peer = tracee;
272         ad->request = 0;
273         ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
274                                CAP_OPT_NONE);
275
276         return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb);
277 }
278
279 /**
280  * aa_may_ptrace - test if tracer task can trace the tracee
281  * @tracer_cred: cred of task doing the tracing  (NOT NULL)
282  * @tracer: label of the task doing the tracing  (NOT NULL)
283  * @tracee_cred: cred of task to be traced
284  * @tracee: task label to be traced
285  * @request: permission request
286  *
287  * Returns: %0 else error code if permission denied or error
288  */
289 int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
290                   const struct cred *tracee_cred, struct aa_label *tracee,
291                   u32 request)
292 {
293         struct aa_profile *profile;
294         u32 xrequest = request << PTRACE_PERM_SHIFT;
295         DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
296
297         return xcheck_labels(tracer, tracee, profile,
298                         profile_tracer_perm(tracer_cred, profile, tracee,
299                                             request, &sa),
300                         profile_tracee_perm(tracee_cred, profile, tracer,
301                                             xrequest, &sa));
302 }
303
304 /* call back to audit ptrace fields */
305 static void audit_ns_cb(struct audit_buffer *ab, void *va)
306 {
307         struct apparmor_audit_data *ad = aad_of_va(va);
308
309         if (ad->request & AA_USERNS_CREATE)
310                 audit_log_format(ab, " requested=\"userns_create\"");
311
312         if (ad->denied & AA_USERNS_CREATE)
313                 audit_log_format(ab, " denied=\"userns_create\"");
314 }
315
316 int aa_profile_ns_perm(struct aa_profile *profile,
317                        struct apparmor_audit_data *ad,
318                        u32 request)
319 {
320         struct aa_perms perms = { };
321         int error = 0;
322
323         ad->subj_label = &profile->label;
324         ad->request = request;
325
326         if (!profile_unconfined(profile)) {
327                 struct aa_ruleset *rules = list_first_entry(&profile->rules,
328                                                             typeof(*rules),
329                                                             list);
330                 aa_state_t state;
331
332                 state = RULE_MEDIATES(rules, ad->class);
333                 if (!state)
334                         /* TODO: add flag to complain about unmediated */
335                         return 0;
336                 perms = *aa_lookup_perms(rules->policy, state);
337                 aa_apply_modes_to_perms(profile, &perms);
338                 error = aa_check_perms(profile, &perms, request, ad,
339                                        audit_ns_cb);
340         }
341
342         return error;
343 }