~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/apparmor/task.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 }
344 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php