1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/ctype.h>
16#include <linux/mm.h>
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/vmalloc.h>
20
21#include "include/audit.h"
22#include "include/apparmor.h"
23#include "include/lib.h"
24#include "include/perms.h"
25#include "include/policy.h"
26
27struct aa_perms nullperms;
28struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
29 .quiet = ALL_PERMS_MASK,
30 .hide = ALL_PERMS_MASK };
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46char *aa_split_fqname(char *fqname, char **ns_name)
47{
48 char *name = strim(fqname);
49
50 *ns_name = NULL;
51 if (name[0] == ':') {
52 char *split = strchr(&name[1], ':');
53 *ns_name = skip_spaces(&name[1]);
54 if (split) {
55
56 *split++ = 0;
57 if (strncmp(split, "//", 2) == 0)
58 split += 2;
59 name = skip_spaces(split);
60 } else
61
62 name = NULL;
63 }
64 if (name && *name == 0)
65 name = NULL;
66
67 return name;
68}
69
70
71
72
73
74
75
76
77
78const char *skipn_spaces(const char *str, size_t n)
79{
80 for (; n && isspace(*str); --n)
81 ++str;
82 if (n)
83 return (char *)str;
84 return NULL;
85}
86
87const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
88 size_t *ns_len)
89{
90 const char *end = fqname + n;
91 const char *name = skipn_spaces(fqname, n);
92
93 if (!name)
94 return NULL;
95 *ns_name = NULL;
96 *ns_len = 0;
97 if (name[0] == ':') {
98 char *split = strnchr(&name[1], end - &name[1], ':');
99 *ns_name = skipn_spaces(&name[1], end - &name[1]);
100 if (!*ns_name)
101 return NULL;
102 if (split) {
103 *ns_len = split - *ns_name;
104 if (*ns_len == 0)
105 *ns_name = NULL;
106 split++;
107 if (end - split > 1 && strncmp(split, "//", 2) == 0)
108 split += 2;
109 name = skipn_spaces(split, end - split);
110 } else {
111
112 name = NULL;
113 *ns_len = end - *ns_name;
114 }
115 }
116 if (name && *name == 0)
117 name = NULL;
118
119 return name;
120}
121
122
123
124
125
126void aa_info_message(const char *str)
127{
128 if (audit_enabled) {
129 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
130
131 aad(&sa)->info = str;
132 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
133 }
134 printk(KERN_INFO "AppArmor: %s\n", str);
135}
136
137__counted char *aa_str_alloc(int size, gfp_t gfp)
138{
139 struct counted_str *str;
140
141 str = kmalloc(sizeof(struct counted_str) + size, gfp);
142 if (!str)
143 return NULL;
144
145 kref_init(&str->count);
146 return str->name;
147}
148
149void aa_str_kref(struct kref *kref)
150{
151 kfree(container_of(kref, struct counted_str, count));
152}
153
154
155const char aa_file_perm_chrs[] = "xwracd km l ";
156const char *aa_file_perm_names[] = {
157 "exec",
158 "write",
159 "read",
160 "append",
161
162 "create",
163 "delete",
164 "open",
165 "rename",
166
167 "setattr",
168 "getattr",
169 "setcred",
170 "getcred",
171
172 "chmod",
173 "chown",
174 "chgrp",
175 "lock",
176
177 "mmap",
178 "mprot",
179 "link",
180 "snapshot",
181
182 "unknown",
183 "unknown",
184 "unknown",
185 "unknown",
186
187 "unknown",
188 "unknown",
189 "unknown",
190 "unknown",
191
192 "stack",
193 "change_onexec",
194 "change_profile",
195 "change_hat",
196};
197
198
199
200
201
202
203void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
204{
205 unsigned int i, perm = 1;
206
207 for (i = 0; i < 32; perm <<= 1, i++) {
208 if (mask & perm)
209 *str++ = chrs[i];
210 }
211 *str = '\0';
212}
213
214void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
215 u32 mask)
216{
217 const char *fmt = "%s";
218 unsigned int i, perm = 1;
219 bool prev = false;
220
221 for (i = 0; i < 32; perm <<= 1, i++) {
222 if (mask & perm) {
223 audit_log_format(ab, fmt, names[i]);
224 if (!prev) {
225 prev = true;
226 fmt = " %s";
227 }
228 }
229 }
230}
231
232void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
233 u32 chrsmask, const char * const *names, u32 namesmask)
234{
235 char str[33];
236
237 audit_log_format(ab, "\"");
238 if ((mask & chrsmask) && chrs) {
239 aa_perm_mask_to_str(str, chrs, mask & chrsmask);
240 mask &= ~chrsmask;
241 audit_log_format(ab, "%s", str);
242 if (mask & namesmask)
243 audit_log_format(ab, " ");
244 }
245 if ((mask & namesmask) && names)
246 aa_audit_perm_names(ab, names, mask & namesmask);
247 audit_log_format(ab, "\"");
248}
249
250
251
252
253
254
255static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
256{
257 struct common_audit_data *sa = va;
258
259 if (aad(sa)->request) {
260 audit_log_format(ab, " requested_mask=");
261 aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
262 PERMS_CHRS_MASK, aa_file_perm_names,
263 PERMS_NAMES_MASK);
264 }
265 if (aad(sa)->denied) {
266 audit_log_format(ab, "denied_mask=");
267 aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
268 PERMS_CHRS_MASK, aa_file_perm_names,
269 PERMS_NAMES_MASK);
270 }
271 audit_log_format(ab, " peer=");
272 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
273 FLAGS_NONE, GFP_ATOMIC);
274}
275
276
277
278
279
280
281
282
283void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
284{
285 switch (AUDIT_MODE(profile)) {
286 case AUDIT_ALL:
287 perms->audit = ALL_PERMS_MASK;
288
289 case AUDIT_NOQUIET:
290 perms->quiet = 0;
291 break;
292 case AUDIT_QUIET:
293 perms->audit = 0;
294
295 case AUDIT_QUIET_DENIED:
296 perms->quiet = ALL_PERMS_MASK;
297 break;
298 }
299
300 if (KILL_MODE(profile))
301 perms->kill = ALL_PERMS_MASK;
302 else if (COMPLAIN_MODE(profile))
303 perms->complain = ALL_PERMS_MASK;
304
305
306
307
308
309}
310
311static u32 map_other(u32 x)
312{
313 return ((x & 0x3) << 8) |
314 ((x & 0x1c) << 18) |
315 ((x & 0x60) << 19);
316}
317
318void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
319 struct aa_perms *perms)
320{
321 *perms = (struct aa_perms) {
322 .allow = dfa_user_allow(dfa, state),
323 .audit = dfa_user_audit(dfa, state),
324 .quiet = dfa_user_quiet(dfa, state),
325 };
326
327
328
329
330 perms->allow |= map_other(dfa_other_allow(dfa, state));
331 perms->audit |= map_other(dfa_other_audit(dfa, state));
332 perms->quiet |= map_other(dfa_other_quiet(dfa, state));
333
334}
335
336
337
338
339
340
341void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
342{
343 accum->deny |= addend->deny;
344 accum->allow &= addend->allow & ~addend->deny;
345 accum->audit |= addend->audit & addend->allow;
346 accum->quiet &= addend->quiet & ~addend->allow;
347 accum->kill |= addend->kill & ~addend->allow;
348 accum->stop |= addend->stop & ~addend->allow;
349 accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
350 accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
351 accum->hide &= addend->hide & ~addend->allow;
352 accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
353}
354
355
356
357
358
359
360void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
361{
362 accum->deny |= addend->deny;
363 accum->allow &= addend->allow & ~accum->deny;
364 accum->audit |= addend->audit & accum->allow;
365 accum->quiet &= addend->quiet & ~accum->allow;
366 accum->kill |= addend->kill & ~accum->allow;
367 accum->stop |= addend->stop & ~accum->allow;
368 accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
369 accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
370 accum->hide &= addend->hide & ~accum->allow;
371 accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
372}
373
374void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
375 int type, u32 request, struct aa_perms *perms)
376{
377
378 unsigned int state;
379
380 state = aa_dfa_next(profile->policy.dfa,
381 profile->policy.start[AA_CLASS_LABEL],
382 type);
383 aa_label_match(profile, label, state, false, request, perms);
384}
385
386
387
388int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
389 u32 request, int type, u32 *deny,
390 struct common_audit_data *sa)
391{
392 struct aa_perms perms;
393
394 aad(sa)->label = &profile->label;
395 aad(sa)->peer = &target->label;
396 aad(sa)->request = request;
397
398 aa_profile_match_label(profile, &target->label, type, request, &perms);
399 aa_apply_modes_to_perms(profile, &perms);
400 *deny |= request & perms.deny;
401 return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
402}
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
423 u32 request, struct common_audit_data *sa,
424 void (*cb)(struct audit_buffer *, void *))
425{
426 int type, error;
427 u32 denied = request & (~perms->allow | perms->deny);
428
429 if (likely(!denied)) {
430
431 request &= perms->audit;
432 if (!request || !sa)
433 return 0;
434
435 type = AUDIT_APPARMOR_AUDIT;
436 error = 0;
437 } else {
438 error = -EACCES;
439
440 if (denied & perms->kill)
441 type = AUDIT_APPARMOR_KILL;
442 else if (denied == (denied & perms->complain))
443 type = AUDIT_APPARMOR_ALLOWED;
444 else
445 type = AUDIT_APPARMOR_DENIED;
446
447 if (denied == (denied & perms->hide))
448 error = -ENOENT;
449
450 denied &= ~perms->quiet;
451 if (!sa || !denied)
452 return error;
453 }
454
455 if (sa) {
456 aad(sa)->label = &profile->label;
457 aad(sa)->request = request;
458 aad(sa)->denied = denied;
459 aad(sa)->error = error;
460 aa_audit_msg(type, sa, cb);
461 }
462
463 if (type == AUDIT_APPARMOR_ALLOWED)
464 error = 0;
465
466 return error;
467}
468
469
470
471
472
473
474
475
476
477
478
479
480
481bool aa_policy_init(struct aa_policy *policy, const char *prefix,
482 const char *name, gfp_t gfp)
483{
484 char *hname;
485
486
487 if (prefix) {
488 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
489 if (hname)
490 sprintf(hname, "%s//%s", prefix, name);
491 } else {
492 hname = aa_str_alloc(strlen(name) + 1, gfp);
493 if (hname)
494 strcpy(hname, name);
495 }
496 if (!hname)
497 return false;
498 policy->hname = hname;
499
500 policy->name = basename(policy->hname);
501 INIT_LIST_HEAD(&policy->list);
502 INIT_LIST_HEAD(&policy->profiles);
503
504 return true;
505}
506
507
508
509
510
511void aa_policy_destroy(struct aa_policy *policy)
512{
513 AA_BUG(on_list_rcu(&policy->profiles));
514 AA_BUG(on_list_rcu(&policy->list));
515
516
517 aa_put_str(policy->hname);
518}
519