apparmor: pass cred through to audit info.
[platform/kernel/linux-rpi.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  * Returns: 0 or error on failure
97  */
98 int aa_set_current_onexec(struct aa_label *label, bool stack)
99 {
100         struct aa_task_ctx *ctx = task_ctx(current);
101
102         aa_get_label(label);
103         aa_put_label(ctx->onexec);
104         ctx->onexec = label;
105         ctx->token = stack;
106
107         return 0;
108 }
109
110 /**
111  * aa_set_current_hat - set the current tasks hat
112  * @label: label to set as the current hat  (NOT NULL)
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  */
120 int aa_set_current_hat(struct aa_label *label, u64 token)
121 {
122         struct aa_task_ctx *ctx = task_ctx(current);
123         struct cred *new;
124
125         new = prepare_creds();
126         if (!new)
127                 return -ENOMEM;
128         AA_BUG(!label);
129
130         if (!ctx->previous) {
131                 /* transfer refcount */
132                 ctx->previous = cred_label(new);
133                 ctx->token = token;
134         } else if (ctx->token == token) {
135                 aa_put_label(cred_label(new));
136         } else {
137                 /* previous_profile && ctx->token != token */
138                 abort_creds(new);
139                 return -EACCES;
140         }
141
142         set_cred_label(new, aa_get_newest_label(label));
143         /* clear exec on switching context */
144         aa_put_label(ctx->onexec);
145         ctx->onexec = NULL;
146
147         commit_creds(new);
148         return 0;
149 }
150
151 /**
152  * aa_restore_previous_label - exit from hat context restoring previous label
153  * @token: the token that must be matched to exit hat context
154  *
155  * Attempt to return out of a hat to the previous label.  The token
156  * must match the stored token value.
157  *
158  * Returns: 0 or error of failure
159  */
160 int aa_restore_previous_label(u64 token)
161 {
162         struct aa_task_ctx *ctx = task_ctx(current);
163         struct cred *new;
164
165         if (ctx->token != token)
166                 return -EACCES;
167         /* ignore restores when there is no saved label */
168         if (!ctx->previous)
169                 return 0;
170
171         new = prepare_creds();
172         if (!new)
173                 return -ENOMEM;
174
175         aa_put_label(cred_label(new));
176         set_cred_label(new, aa_get_newest_label(ctx->previous));
177         AA_BUG(!cred_label(new));
178         /* clear exec && prev information when restoring to previous context */
179         aa_clear_task_ctx_trans(ctx);
180
181         commit_creds(new);
182
183         return 0;
184 }
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  */
192 static 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 */
208 static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
209 {
210         struct common_audit_data *sa = va;
211         struct apparmor_audit_data *ad = aad(sa);
212
213         if (ad->request & AA_PTRACE_PERM_MASK) {
214                 audit_log_format(ab, " requested_mask=\"%s\"",
215                                  audit_ptrace_mask(ad->request));
216
217                 if (ad->denied & AA_PTRACE_PERM_MASK) {
218                         audit_log_format(ab, " denied_mask=\"%s\"",
219                                          audit_ptrace_mask(ad->denied));
220                 }
221         }
222         audit_log_format(ab, " peer=");
223         aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
224                         FLAGS_NONE, GFP_ATOMIC);
225 }
226
227 /* assumes check for RULE_MEDIATES is already done */
228 /* TODO: conditionals */
229 static int profile_ptrace_perm(const struct cred *cred,
230                                struct aa_profile *profile,
231                                struct aa_label *peer, u32 request,
232                                struct apparmor_audit_data *ad)
233 {
234         struct aa_ruleset *rules = list_first_entry(&profile->rules,
235                                                     typeof(*rules), list);
236         struct aa_perms perms = { };
237
238         ad->subj_cred = cred;
239         ad->peer = peer;
240         aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
241                                &perms);
242         aa_apply_modes_to_perms(profile, &perms);
243         return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb);
244 }
245
246 static int profile_tracee_perm(const struct cred *cred,
247                                struct aa_profile *tracee,
248                                struct aa_label *tracer, u32 request,
249                                struct apparmor_audit_data *ad)
250 {
251         if (profile_unconfined(tracee) || unconfined(tracer) ||
252             !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE))
253                 return 0;
254
255         return profile_ptrace_perm(cred, tracee, tracer, request, ad);
256 }
257
258 static int profile_tracer_perm(const struct cred *cred,
259                                struct aa_profile *tracer,
260                                struct aa_label *tracee, u32 request,
261                                struct apparmor_audit_data *ad)
262 {
263         if (profile_unconfined(tracer))
264                 return 0;
265
266         if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE))
267                 return profile_ptrace_perm(cred, tracer, tracee, request, ad);
268
269         /* profile uses the old style capability check for ptrace */
270         if (&tracer->label == tracee)
271                 return 0;
272
273         ad->subj_label = &tracer->label;
274         ad->peer = tracee;
275         ad->request = 0;
276         ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
277                                CAP_OPT_NONE);
278
279         return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb);
280 }
281
282 /**
283  * aa_may_ptrace - test if tracer task can trace the tracee
284  * @tracer: label of the task doing the tracing  (NOT NULL)
285  * @tracee: task label to be traced
286  * @request: permission request
287  *
288  * Returns: %0 else error code if permission denied or error
289  */
290 int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
291                   const struct cred *tracee_cred, struct aa_label *tracee,
292                   u32 request)
293 {
294         struct aa_profile *profile;
295         u32 xrequest = request << PTRACE_PERM_SHIFT;
296         DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
297
298         return xcheck_labels(tracer, tracee, profile,
299                         profile_tracer_perm(tracer_cred, profile, tracee,
300                                             request, &sa),
301                         profile_tracee_perm(tracee_cred, profile, tracer,
302                                             xrequest, &sa));
303 }