Branch data Line data Source code
1 : : /*
2 : : * AppArmor security module
3 : : *
4 : : * This file contains AppArmor /sys/kernel/security/apparmor interface functions
5 : : *
6 : : * Copyright (C) 1998-2008 Novell/SUSE
7 : : * Copyright 2009-2010 Canonical Ltd.
8 : : *
9 : : * This program is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU General Public License as
11 : : * published by the Free Software Foundation, version 2 of the
12 : : * License.
13 : : */
14 : :
15 : : #include <linux/ctype.h>
16 : : #include <linux/security.h>
17 : : #include <linux/vmalloc.h>
18 : : #include <linux/module.h>
19 : : #include <linux/seq_file.h>
20 : : #include <linux/uaccess.h>
21 : : #include <linux/namei.h>
22 : : #include <linux/capability.h>
23 : : #include <linux/rcupdate.h>
24 : :
25 : : #include "include/apparmor.h"
26 : : #include "include/apparmorfs.h"
27 : : #include "include/audit.h"
28 : : #include "include/context.h"
29 : : #include "include/crypto.h"
30 : : #include "include/policy.h"
31 : : #include "include/resource.h"
32 : :
33 : : /**
34 : : * aa_mangle_name - mangle a profile name to std profile layout form
35 : : * @name: profile name to mangle (NOT NULL)
36 : : * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
37 : : *
38 : : * Returns: length of mangled name
39 : : */
40 : 0 : static int mangle_name(char *name, char *target)
41 : : {
42 : : char *t = target;
43 : :
44 [ # # ]: 0 : while (*name == '/' || *name == '.')
45 : 0 : name++;
46 : :
47 [ # # ]: 0 : if (target) {
48 [ # # ]: 0 : for (; *name; name++) {
49 [ # # ]: 0 : if (*name == '/')
50 : 0 : *(t)++ = '.';
51 [ # # ]: 0 : else if (isspace(*name))
52 : 0 : *(t)++ = '_';
53 [ # # ][ # # ]: 0 : else if (isalnum(*name) || strchr("._-", *name))
54 : 0 : *(t)++ = *name;
55 : : }
56 : :
57 : 0 : *t = 0;
58 : : } else {
59 : : int len = 0;
60 [ # # ]: 0 : for (; *name; name++) {
61 [ # # ][ # # ]: 0 : if (isalnum(*name) || isspace(*name) ||
62 : 0 : strchr("/._-", *name))
63 : 0 : len++;
64 : : }
65 : :
66 : : return len;
67 : : }
68 : :
69 : 0 : return t - target;
70 : : }
71 : :
72 : : /**
73 : : * aa_simple_write_to_buffer - common routine for getting policy from user
74 : : * @op: operation doing the user buffer copy
75 : : * @userbuf: user buffer to copy data from (NOT NULL)
76 : : * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
77 : : * @copy_size: size of data to copy from user buffer
78 : : * @pos: position write is at in the file (NOT NULL)
79 : : *
80 : : * Returns: kernel buffer containing copy of user buffer data or an
81 : : * ERR_PTR on failure.
82 : : */
83 : 0 : static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
84 : : size_t alloc_size, size_t copy_size,
85 : : loff_t *pos)
86 : : {
87 : : char *data;
88 : :
89 [ # # ]: 0 : BUG_ON(copy_size > alloc_size);
90 : :
91 [ # # ]: 0 : if (*pos != 0)
92 : : /* only writes from pos 0, that is complete writes */
93 : : return ERR_PTR(-ESPIPE);
94 : :
95 : : /*
96 : : * Don't allow profile load/replace/remove from profiles that don't
97 : : * have CAP_MAC_ADMIN
98 : : */
99 [ # # ]: 0 : if (!aa_may_manage_policy(op))
100 : : return ERR_PTR(-EACCES);
101 : :
102 : : /* freed by caller to simple_write_to_buffer */
103 : : data = kvmalloc(alloc_size);
104 [ # # ]: 0 : if (data == NULL)
105 : : return ERR_PTR(-ENOMEM);
106 : :
107 [ # # ]: 0 : if (copy_from_user(data, userbuf, copy_size)) {
108 : 0 : kvfree(data);
109 : 0 : return ERR_PTR(-EFAULT);
110 : : }
111 : :
112 : : return data;
113 : : }
114 : :
115 : :
116 : : /* .load file hook fn to load policy */
117 : 0 : static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
118 : : loff_t *pos)
119 : : {
120 : : char *data;
121 : : ssize_t error;
122 : :
123 : 0 : data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
124 : :
125 : : error = PTR_ERR(data);
126 [ # # ]: 0 : if (!IS_ERR(data)) {
127 : 0 : error = aa_replace_profiles(data, size, PROF_ADD);
128 : 0 : kvfree(data);
129 : : }
130 : :
131 : 0 : return error;
132 : : }
133 : :
134 : : static const struct file_operations aa_fs_profile_load = {
135 : : .write = profile_load,
136 : : .llseek = default_llseek,
137 : : };
138 : :
139 : : /* .replace file hook fn to load and/or replace policy */
140 : 0 : static ssize_t profile_replace(struct file *f, const char __user *buf,
141 : : size_t size, loff_t *pos)
142 : : {
143 : : char *data;
144 : : ssize_t error;
145 : :
146 : 0 : data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
147 : : error = PTR_ERR(data);
148 [ # # ]: 0 : if (!IS_ERR(data)) {
149 : 0 : error = aa_replace_profiles(data, size, PROF_REPLACE);
150 : 0 : kvfree(data);
151 : : }
152 : :
153 : 0 : return error;
154 : : }
155 : :
156 : : static const struct file_operations aa_fs_profile_replace = {
157 : : .write = profile_replace,
158 : : .llseek = default_llseek,
159 : : };
160 : :
161 : : /* .remove file hook fn to remove loaded policy */
162 : 0 : static ssize_t profile_remove(struct file *f, const char __user *buf,
163 : : size_t size, loff_t *pos)
164 : : {
165 : : char *data;
166 : : ssize_t error;
167 : :
168 : : /*
169 : : * aa_remove_profile needs a null terminated string so 1 extra
170 : : * byte is allocated and the copied data is null terminated.
171 : : */
172 : 0 : data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
173 : :
174 : : error = PTR_ERR(data);
175 [ # # ]: 0 : if (!IS_ERR(data)) {
176 : 0 : data[size] = 0;
177 : 0 : error = aa_remove_profiles(data, size);
178 : 0 : kvfree(data);
179 : : }
180 : :
181 : 0 : return error;
182 : : }
183 : :
184 : : static const struct file_operations aa_fs_profile_remove = {
185 : : .write = profile_remove,
186 : : .llseek = default_llseek,
187 : : };
188 : :
189 : 0 : static int aa_fs_seq_show(struct seq_file *seq, void *v)
190 : : {
191 : 0 : struct aa_fs_entry *fs_file = seq->private;
192 : :
193 [ # # ]: 0 : if (!fs_file)
194 : : return 0;
195 : :
196 [ # # # # ]: 0 : switch (fs_file->v_type) {
197 : : case AA_FS_TYPE_BOOLEAN:
198 [ # # ]: 0 : seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
199 : 0 : break;
200 : : case AA_FS_TYPE_STRING:
201 : 0 : seq_printf(seq, "%s\n", fs_file->v.string);
202 : 0 : break;
203 : : case AA_FS_TYPE_U64:
204 : 0 : seq_printf(seq, "%#08lx\n", fs_file->v.u64);
205 : 0 : break;
206 : : default:
207 : : /* Ignore unpritable entry types. */
208 : : break;
209 : : }
210 : :
211 : : return 0;
212 : : }
213 : :
214 : 0 : static int aa_fs_seq_open(struct inode *inode, struct file *file)
215 : : {
216 : 0 : return single_open(file, aa_fs_seq_show, inode->i_private);
217 : : }
218 : :
219 : : const struct file_operations aa_fs_seq_file_ops = {
220 : : .owner = THIS_MODULE,
221 : : .open = aa_fs_seq_open,
222 : : .read = seq_read,
223 : : .llseek = seq_lseek,
224 : : .release = single_release,
225 : : };
226 : :
227 : 0 : static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
228 : : int (*show)(struct seq_file *, void *))
229 : : {
230 : 0 : struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
231 : 0 : int error = single_open(file, show, r);
232 : :
233 [ # # ]: 0 : if (error) {
234 : 0 : file->private_data = NULL;
235 : : aa_put_replacedby(r);
236 : : }
237 : :
238 : 0 : return error;
239 : : }
240 : :
241 : 0 : static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
242 : : {
243 : 0 : struct seq_file *seq = (struct seq_file *) file->private_data;
244 [ # # ]: 0 : if (seq)
245 : 0 : aa_put_replacedby(seq->private);
246 : 0 : return single_release(inode, file);
247 : : }
248 : :
249 : 0 : static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
250 : : {
251 : 0 : struct aa_replacedby *r = seq->private;
252 : : struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
253 : 0 : seq_printf(seq, "%s\n", profile->base.name);
254 : : aa_put_profile(profile);
255 : :
256 : 0 : return 0;
257 : : }
258 : :
259 : 0 : static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
260 : : {
261 : 0 : return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
262 : : }
263 : :
264 : : static const struct file_operations aa_fs_profname_fops = {
265 : : .owner = THIS_MODULE,
266 : : .open = aa_fs_seq_profname_open,
267 : : .read = seq_read,
268 : : .llseek = seq_lseek,
269 : : .release = aa_fs_seq_profile_release,
270 : : };
271 : :
272 : 0 : static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
273 : : {
274 : 0 : struct aa_replacedby *r = seq->private;
275 : : struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
276 : 0 : seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
277 : : aa_put_profile(profile);
278 : :
279 : 0 : return 0;
280 : : }
281 : :
282 : 0 : static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
283 : : {
284 : 0 : return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
285 : : }
286 : :
287 : : static const struct file_operations aa_fs_profmode_fops = {
288 : : .owner = THIS_MODULE,
289 : : .open = aa_fs_seq_profmode_open,
290 : : .read = seq_read,
291 : : .llseek = seq_lseek,
292 : : .release = aa_fs_seq_profile_release,
293 : : };
294 : :
295 : 0 : static int aa_fs_seq_profattach_show(struct seq_file *seq, void *v)
296 : : {
297 : 0 : struct aa_replacedby *r = seq->private;
298 : : struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
299 [ # # ]: 0 : if (profile->attach)
300 : 0 : seq_printf(seq, "%s\n", profile->attach);
301 [ # # ]: 0 : else if (profile->xmatch)
302 : 0 : seq_puts(seq, "<unknown>\n");
303 : : else
304 : 0 : seq_printf(seq, "%s\n", profile->base.name);
305 : : aa_put_profile(profile);
306 : :
307 : 0 : return 0;
308 : : }
309 : :
310 : 0 : static int aa_fs_seq_profattach_open(struct inode *inode, struct file *file)
311 : : {
312 : 0 : return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profattach_show);
313 : : }
314 : :
315 : : static const struct file_operations aa_fs_profattach_fops = {
316 : : .owner = THIS_MODULE,
317 : : .open = aa_fs_seq_profattach_open,
318 : : .read = seq_read,
319 : : .llseek = seq_lseek,
320 : : .release = aa_fs_seq_profile_release,
321 : : };
322 : :
323 : 0 : static int aa_fs_seq_hash_show(struct seq_file *seq, void *v)
324 : : {
325 : 0 : struct aa_replacedby *r = seq->private;
326 : : struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
327 : 0 : unsigned int i, size = aa_hash_size();
328 : :
329 [ # # ]: 0 : if (profile->hash) {
330 [ # # ]: 0 : for (i = 0; i < size; i++)
331 : 0 : seq_printf(seq, "%.2x", profile->hash[i]);
332 : 0 : seq_puts(seq, "\n");
333 : : }
334 : :
335 : 0 : return 0;
336 : : }
337 : :
338 : 0 : static int aa_fs_seq_hash_open(struct inode *inode, struct file *file)
339 : : {
340 : 0 : return single_open(file, aa_fs_seq_hash_show, inode->i_private);
341 : : }
342 : :
343 : : static const struct file_operations aa_fs_seq_hash_fops = {
344 : : .owner = THIS_MODULE,
345 : : .open = aa_fs_seq_hash_open,
346 : : .read = seq_read,
347 : : .llseek = seq_lseek,
348 : : .release = single_release,
349 : : };
350 : :
351 : : /** fns to setup dynamic per profile/namespace files **/
352 : 0 : void __aa_fs_profile_rmdir(struct aa_profile *profile)
353 : : {
354 : : struct aa_profile *child;
355 : : int i;
356 : :
357 [ # # ]: 0 : if (!profile)
358 : 0 : return;
359 : :
360 [ # # ]: 0 : list_for_each_entry(child, &profile->base.profiles, base.list)
361 : 0 : __aa_fs_profile_rmdir(child);
362 : :
363 [ # # ]: 0 : for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
364 : : struct aa_replacedby *r;
365 [ # # ]: 0 : if (!profile->dents[i])
366 : 0 : continue;
367 : :
368 : 0 : r = profile->dents[i]->d_inode->i_private;
369 : 0 : securityfs_remove(profile->dents[i]);
370 : : aa_put_replacedby(r);
371 : 0 : profile->dents[i] = NULL;
372 : : }
373 : : }
374 : :
375 : 0 : void __aa_fs_profile_migrate_dents(struct aa_profile *old,
376 : : struct aa_profile *new)
377 : : {
378 : : int i;
379 : :
380 [ # # ]: 0 : for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
381 : 0 : new->dents[i] = old->dents[i];
382 : 0 : old->dents[i] = NULL;
383 : : }
384 : 0 : }
385 : :
386 : 0 : static struct dentry *create_profile_file(struct dentry *dir, const char *name,
387 : : struct aa_profile *profile,
388 : : const struct file_operations *fops)
389 : : {
390 : 0 : struct aa_replacedby *r = aa_get_replacedby(profile->replacedby);
391 : : struct dentry *dent;
392 : :
393 : 0 : dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops);
394 [ # # ]: 0 : if (IS_ERR(dent))
395 : : aa_put_replacedby(r);
396 : :
397 : 0 : return dent;
398 : : }
399 : :
400 : : /* requires lock be held */
401 : 0 : int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
402 : : {
403 : : struct aa_profile *child;
404 : : struct dentry *dent = NULL, *dir;
405 : : int error;
406 : :
407 [ # # ]: 0 : if (!parent) {
408 : : struct aa_profile *p;
409 : : p = aa_deref_parent(profile);
410 : 0 : dent = prof_dir(p);
411 : : /* adding to parent that previously didn't have children */
412 : 0 : dent = securityfs_create_dir("profiles", dent);
413 [ # # ]: 0 : if (IS_ERR(dent))
414 : : goto fail;
415 : 0 : prof_child_dir(p) = parent = dent;
416 : : }
417 : :
418 [ # # ]: 0 : if (!profile->dirname) {
419 : : int len, id_len;
420 : 0 : len = mangle_name(profile->base.name, NULL);
421 : 0 : id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
422 : :
423 : 0 : profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
424 [ # # ]: 0 : if (!profile->dirname)
425 : : goto fail;
426 : :
427 : 0 : mangle_name(profile->base.name, profile->dirname);
428 : 0 : sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
429 : : }
430 : :
431 : 0 : dent = securityfs_create_dir(profile->dirname, parent);
432 [ # # ]: 0 : if (IS_ERR(dent))
433 : : goto fail;
434 : 0 : prof_dir(profile) = dir = dent;
435 : :
436 : 0 : dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
437 [ # # ]: 0 : if (IS_ERR(dent))
438 : : goto fail;
439 : 0 : profile->dents[AAFS_PROF_NAME] = dent;
440 : :
441 : 0 : dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
442 [ # # ]: 0 : if (IS_ERR(dent))
443 : : goto fail;
444 : 0 : profile->dents[AAFS_PROF_MODE] = dent;
445 : :
446 : 0 : dent = create_profile_file(dir, "attach", profile,
447 : : &aa_fs_profattach_fops);
448 [ # # ]: 0 : if (IS_ERR(dent))
449 : : goto fail;
450 : 0 : profile->dents[AAFS_PROF_ATTACH] = dent;
451 : :
452 [ # # ]: 0 : if (profile->hash) {
453 : 0 : dent = create_profile_file(dir, "sha1", profile,
454 : : &aa_fs_seq_hash_fops);
455 [ # # ]: 0 : if (IS_ERR(dent))
456 : : goto fail;
457 : 0 : profile->dents[AAFS_PROF_HASH] = dent;
458 : : }
459 : :
460 [ # # ]: 0 : list_for_each_entry(child, &profile->base.profiles, base.list) {
461 : 0 : error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
462 [ # # ]: 0 : if (error)
463 : : goto fail2;
464 : : }
465 : :
466 : : return 0;
467 : :
468 : : fail:
469 : : error = PTR_ERR(dent);
470 : :
471 : : fail2:
472 : 0 : __aa_fs_profile_rmdir(profile);
473 : :
474 : 0 : return error;
475 : : }
476 : :
477 : 0 : void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
478 : : {
479 : : struct aa_namespace *sub;
480 : : struct aa_profile *child;
481 : : int i;
482 : :
483 [ # # ]: 0 : if (!ns)
484 : 0 : return;
485 : :
486 [ # # ]: 0 : list_for_each_entry(child, &ns->base.profiles, base.list)
487 : 0 : __aa_fs_profile_rmdir(child);
488 : :
489 [ # # ]: 0 : list_for_each_entry(sub, &ns->sub_ns, base.list) {
490 : 0 : mutex_lock(&sub->lock);
491 : 0 : __aa_fs_namespace_rmdir(sub);
492 : 0 : mutex_unlock(&sub->lock);
493 : : }
494 : :
495 [ # # ]: 0 : for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
496 : 0 : securityfs_remove(ns->dents[i]);
497 : 0 : ns->dents[i] = NULL;
498 : : }
499 : : }
500 : :
501 : 0 : int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
502 : : const char *name)
503 : : {
504 : : struct aa_namespace *sub;
505 : : struct aa_profile *child;
506 : : struct dentry *dent, *dir;
507 : : int error;
508 : :
509 [ # # ]: 0 : if (!name)
510 : 0 : name = ns->base.name;
511 : :
512 : 0 : dent = securityfs_create_dir(name, parent);
513 [ # # ]: 0 : if (IS_ERR(dent))
514 : : goto fail;
515 : 0 : ns_dir(ns) = dir = dent;
516 : :
517 : 0 : dent = securityfs_create_dir("profiles", dir);
518 [ # # ]: 0 : if (IS_ERR(dent))
519 : : goto fail;
520 : 0 : ns_subprofs_dir(ns) = dent;
521 : :
522 : 0 : dent = securityfs_create_dir("namespaces", dir);
523 [ # # ]: 0 : if (IS_ERR(dent))
524 : : goto fail;
525 : 0 : ns_subns_dir(ns) = dent;
526 : :
527 [ # # ]: 0 : list_for_each_entry(child, &ns->base.profiles, base.list) {
528 : 0 : error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
529 [ # # ]: 0 : if (error)
530 : : goto fail2;
531 : : }
532 : :
533 [ # # ]: 0 : list_for_each_entry(sub, &ns->sub_ns, base.list) {
534 : 0 : mutex_lock(&sub->lock);
535 : 0 : error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL);
536 : 0 : mutex_unlock(&sub->lock);
537 [ # # ]: 0 : if (error)
538 : : goto fail2;
539 : : }
540 : :
541 : : return 0;
542 : :
543 : : fail:
544 : : error = PTR_ERR(dent);
545 : :
546 : : fail2:
547 : 0 : __aa_fs_namespace_rmdir(ns);
548 : :
549 : 0 : return error;
550 : : }
551 : :
552 : :
553 : : #define list_entry_next(pos, member) \
554 : : list_entry(pos->member.next, typeof(*pos), member)
555 : : #define list_entry_is_head(pos, head, member) (&pos->member == (head))
556 : :
557 : : /**
558 : : * __next_namespace - find the next namespace to list
559 : : * @root: root namespace to stop search at (NOT NULL)
560 : : * @ns: current ns position (NOT NULL)
561 : : *
562 : : * Find the next namespace from @ns under @root and handle all locking needed
563 : : * while switching current namespace.
564 : : *
565 : : * Returns: next namespace or NULL if at last namespace under @root
566 : : * Requires: ns->parent->lock to be held
567 : : * NOTE: will not unlock root->lock
568 : : */
569 : 0 : static struct aa_namespace *__next_namespace(struct aa_namespace *root,
570 : : struct aa_namespace *ns)
571 : : {
572 : : struct aa_namespace *parent, *next;
573 : :
574 : : /* is next namespace a child */
575 [ # # ]: 0 : if (!list_empty(&ns->sub_ns)) {
576 : 0 : next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list);
577 : 0 : mutex_lock(&next->lock);
578 : 0 : return next;
579 : : }
580 : :
581 : : /* check if the next ns is a sibling, parent, gp, .. */
582 : 0 : parent = ns->parent;
583 [ # # ]: 0 : while (ns != root) {
584 : 0 : mutex_unlock(&ns->lock);
585 : 0 : next = list_entry_next(ns, base.list);
586 [ # # ]: 0 : if (!list_entry_is_head(next, &parent->sub_ns, base.list)) {
587 : 0 : mutex_lock(&next->lock);
588 : 0 : return next;
589 : : }
590 : : ns = parent;
591 : 0 : parent = parent->parent;
592 : : }
593 : :
594 : : return NULL;
595 : : }
596 : :
597 : : /**
598 : : * __first_profile - find the first profile in a namespace
599 : : * @root: namespace that is root of profiles being displayed (NOT NULL)
600 : : * @ns: namespace to start in (NOT NULL)
601 : : *
602 : : * Returns: unrefcounted profile or NULL if no profile
603 : : * Requires: profile->ns.lock to be held
604 : : */
605 : : static struct aa_profile *__first_profile(struct aa_namespace *root,
606 : : struct aa_namespace *ns)
607 : : {
608 [ # # ][ # # ]: 0 : for (; ns; ns = __next_namespace(root, ns)) {
609 [ # # ][ # # ]: 0 : if (!list_empty(&ns->base.profiles))
610 : 0 : return list_first_entry(&ns->base.profiles,
611 : : struct aa_profile, base.list);
612 : : }
613 : : return NULL;
614 : : }
615 : :
616 : : /**
617 : : * __next_profile - step to the next profile in a profile tree
618 : : * @profile: current profile in tree (NOT NULL)
619 : : *
620 : : * Perform a depth first traversal on the profile tree in a namespace
621 : : *
622 : : * Returns: next profile or NULL if done
623 : : * Requires: profile->ns.lock to be held
624 : : */
625 : : static struct aa_profile *__next_profile(struct aa_profile *p)
626 : : {
627 : : struct aa_profile *parent;
628 : 0 : struct aa_namespace *ns = p->ns;
629 : :
630 : : /* is next profile a child */
631 [ # # ]: 0 : if (!list_empty(&p->base.profiles))
632 : 0 : return list_first_entry(&p->base.profiles, typeof(*p),
633 : : base.list);
634 : :
635 : : /* is next profile a sibling, parent sibling, gp, sibling, .. */
636 : 0 : parent = rcu_dereference_protected(p->parent,
637 : : mutex_is_locked(&p->ns->lock));
638 [ # # ]: 0 : while (parent) {
639 : 0 : p = list_entry_next(p, base.list);
640 [ # # ]: 0 : if (!list_entry_is_head(p, &parent->base.profiles, base.list))
641 : : return p;
642 : : p = parent;
643 : 0 : parent = rcu_dereference_protected(parent->parent,
644 : : mutex_is_locked(&parent->ns->lock));
645 : : }
646 : :
647 : : /* is next another profile in the namespace */
648 : 0 : p = list_entry_next(p, base.list);
649 [ # # ]: 0 : if (!list_entry_is_head(p, &ns->base.profiles, base.list))
650 : : return p;
651 : :
652 : : return NULL;
653 : : }
654 : :
655 : : /**
656 : : * next_profile - step to the next profile in where ever it may be
657 : : * @root: root namespace (NOT NULL)
658 : : * @profile: current profile (NOT NULL)
659 : : *
660 : : * Returns: next profile or NULL if there isn't one
661 : : */
662 : 0 : static struct aa_profile *next_profile(struct aa_namespace *root,
663 : : struct aa_profile *profile)
664 : : {
665 : : struct aa_profile *next = __next_profile(profile);
666 [ # # ]: 0 : if (next)
667 : : return next;
668 : :
669 : : /* finished all profiles in namespace move to next namespace */
670 : 0 : return __first_profile(root, __next_namespace(root, profile->ns));
671 : : }
672 : :
673 : : /**
674 : : * p_start - start a depth first traversal of profile tree
675 : : * @f: seq_file to fill
676 : : * @pos: current position
677 : : *
678 : : * Returns: first profile under current namespace or NULL if none found
679 : : *
680 : : * acquires first ns->lock
681 : : */
682 : 0 : static void *p_start(struct seq_file *f, loff_t *pos)
683 : : {
684 : : struct aa_profile *profile = NULL;
685 : 0 : struct aa_namespace *root = aa_current_profile()->ns;
686 : 0 : loff_t l = *pos;
687 : 0 : f->private = aa_get_namespace(root);
688 : :
689 : :
690 : : /* find the first profile */
691 : 0 : mutex_lock(&root->lock);
692 : : profile = __first_profile(root, root);
693 : :
694 : : /* skip to position */
695 [ # # ]: 0 : for (; profile && l > 0; l--)
696 : 0 : profile = next_profile(root, profile);
697 : :
698 : 0 : return profile;
699 : : }
700 : :
701 : : /**
702 : : * p_next - read the next profile entry
703 : : * @f: seq_file to fill
704 : : * @p: profile previously returned
705 : : * @pos: current position
706 : : *
707 : : * Returns: next profile after @p or NULL if none
708 : : *
709 : : * may acquire/release locks in namespace tree as necessary
710 : : */
711 : 0 : static void *p_next(struct seq_file *f, void *p, loff_t *pos)
712 : : {
713 : : struct aa_profile *profile = p;
714 : 0 : struct aa_namespace *ns = f->private;
715 : 0 : (*pos)++;
716 : :
717 : 0 : return next_profile(ns, profile);
718 : : }
719 : :
720 : : /**
721 : : * p_stop - stop depth first traversal
722 : : * @f: seq_file we are filling
723 : : * @p: the last profile writen
724 : : *
725 : : * Release all locking done by p_start/p_next on namespace tree
726 : : */
727 : 0 : static void p_stop(struct seq_file *f, void *p)
728 : : {
729 : : struct aa_profile *profile = p;
730 : 0 : struct aa_namespace *root = f->private, *ns;
731 : :
732 [ # # ]: 0 : if (profile) {
733 [ # # ]: 0 : for (ns = profile->ns; ns && ns != root; ns = ns->parent)
734 : 0 : mutex_unlock(&ns->lock);
735 : : }
736 : 0 : mutex_unlock(&root->lock);
737 : : aa_put_namespace(root);
738 : 0 : }
739 : :
740 : : /**
741 : : * seq_show_profile - show a profile entry
742 : : * @f: seq_file to file
743 : : * @p: current position (profile) (NOT NULL)
744 : : *
745 : : * Returns: error on failure
746 : : */
747 : 0 : static int seq_show_profile(struct seq_file *f, void *p)
748 : : {
749 : : struct aa_profile *profile = (struct aa_profile *)p;
750 : 0 : struct aa_namespace *root = f->private;
751 : :
752 [ # # ]: 0 : if (profile->ns != root)
753 : 0 : seq_printf(f, ":%s://", aa_ns_name(root, profile->ns));
754 : 0 : seq_printf(f, "%s (%s)\n", profile->base.hname,
755 : 0 : aa_profile_mode_names[profile->mode]);
756 : :
757 : 0 : return 0;
758 : : }
759 : :
760 : : static const struct seq_operations aa_fs_profiles_op = {
761 : : .start = p_start,
762 : : .next = p_next,
763 : : .stop = p_stop,
764 : : .show = seq_show_profile,
765 : : };
766 : :
767 : 0 : static int profiles_open(struct inode *inode, struct file *file)
768 : : {
769 : 0 : return seq_open(file, &aa_fs_profiles_op);
770 : : }
771 : :
772 : 0 : static int profiles_release(struct inode *inode, struct file *file)
773 : : {
774 : 0 : return seq_release(inode, file);
775 : : }
776 : :
777 : : static const struct file_operations aa_fs_profiles_fops = {
778 : : .open = profiles_open,
779 : : .read = seq_read,
780 : : .llseek = seq_lseek,
781 : : .release = profiles_release,
782 : : };
783 : :
784 : :
785 : : /** Base file system setup **/
786 : : static struct aa_fs_entry aa_fs_entry_file[] = {
787 : : AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
788 : : "link lock"),
789 : : { }
790 : : };
791 : :
792 : : static struct aa_fs_entry aa_fs_entry_domain[] = {
793 : : AA_FS_FILE_BOOLEAN("change_hat", 1),
794 : : AA_FS_FILE_BOOLEAN("change_hatv", 1),
795 : : AA_FS_FILE_BOOLEAN("change_onexec", 1),
796 : : AA_FS_FILE_BOOLEAN("change_profile", 1),
797 : : { }
798 : : };
799 : :
800 : : static struct aa_fs_entry aa_fs_entry_policy[] = {
801 : : AA_FS_FILE_BOOLEAN("set_load", 1),
802 : : {}
803 : : };
804 : :
805 : : static struct aa_fs_entry aa_fs_entry_features[] = {
806 : : AA_FS_DIR("policy", aa_fs_entry_policy),
807 : : AA_FS_DIR("domain", aa_fs_entry_domain),
808 : : AA_FS_DIR("file", aa_fs_entry_file),
809 : : AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
810 : : AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
811 : : AA_FS_DIR("caps", aa_fs_entry_caps),
812 : : { }
813 : : };
814 : :
815 : : static struct aa_fs_entry aa_fs_entry_apparmor[] = {
816 : : AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
817 : : AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
818 : : AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
819 : : AA_FS_FILE_FOPS("profiles", 0640, &aa_fs_profiles_fops),
820 : : AA_FS_DIR("features", aa_fs_entry_features),
821 : : { }
822 : : };
823 : :
824 : : static struct aa_fs_entry aa_fs_entry =
825 : : AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
826 : :
827 : : /**
828 : : * aafs_create_file - create a file entry in the apparmor securityfs
829 : : * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
830 : : * @parent: the parent dentry in the securityfs
831 : : *
832 : : * Use aafs_remove_file to remove entries created with this fn.
833 : : */
834 : 0 : static int __init aafs_create_file(struct aa_fs_entry *fs_file,
835 : : struct dentry *parent)
836 : : {
837 : : int error = 0;
838 : :
839 : 0 : fs_file->dentry = securityfs_create_file(fs_file->name,
840 : 0 : S_IFREG | fs_file->mode,
841 : : parent, fs_file,
842 : : fs_file->file_ops);
843 [ # # ]: 0 : if (IS_ERR(fs_file->dentry)) {
844 : : error = PTR_ERR(fs_file->dentry);
845 : 0 : fs_file->dentry = NULL;
846 : : }
847 : 0 : return error;
848 : : }
849 : :
850 : : static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
851 : : /**
852 : : * aafs_create_dir - recursively create a directory entry in the securityfs
853 : : * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
854 : : * @parent: the parent dentry in the securityfs
855 : : *
856 : : * Use aafs_remove_dir to remove entries created with this fn.
857 : : */
858 : 0 : static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
859 : : struct dentry *parent)
860 : : {
861 : : struct aa_fs_entry *fs_file;
862 : : struct dentry *dir;
863 : : int error;
864 : :
865 : 0 : dir = securityfs_create_dir(fs_dir->name, parent);
866 [ # # ]: 0 : if (IS_ERR(dir))
867 : 0 : return PTR_ERR(dir);
868 : 0 : fs_dir->dentry = dir;
869 : :
870 [ # # ][ # # ]: 0 : for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
871 [ # # ]: 0 : if (fs_file->v_type == AA_FS_TYPE_DIR)
872 : 0 : error = aafs_create_dir(fs_file, fs_dir->dentry);
873 : : else
874 : 0 : error = aafs_create_file(fs_file, fs_dir->dentry);
875 [ # # ]: 0 : if (error)
876 : : goto failed;
877 : : }
878 : :
879 : : return 0;
880 : :
881 : : failed:
882 : 0 : aafs_remove_dir(fs_dir);
883 : :
884 : 0 : return error;
885 : : }
886 : :
887 : : /**
888 : : * aafs_remove_file - drop a single file entry in the apparmor securityfs
889 : : * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
890 : : */
891 : 0 : static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
892 : : {
893 [ # # ]: 0 : if (!fs_file->dentry)
894 : 0 : return;
895 : :
896 : 0 : securityfs_remove(fs_file->dentry);
897 : 0 : fs_file->dentry = NULL;
898 : : }
899 : :
900 : : /**
901 : : * aafs_remove_dir - recursively drop a directory entry from the securityfs
902 : : * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
903 : : */
904 : 0 : static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
905 : : {
906 : : struct aa_fs_entry *fs_file;
907 : :
908 [ # # ][ # # ]: 0 : for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
909 [ # # ]: 0 : if (fs_file->v_type == AA_FS_TYPE_DIR)
910 : 0 : aafs_remove_dir(fs_file);
911 : : else
912 : 0 : aafs_remove_file(fs_file);
913 : : }
914 : :
915 : 0 : aafs_remove_file(fs_dir);
916 : 0 : }
917 : :
918 : : /**
919 : : * aa_destroy_aafs - cleanup and free aafs
920 : : *
921 : : * releases dentries allocated by aa_create_aafs
922 : : */
923 : 0 : void __init aa_destroy_aafs(void)
924 : : {
925 : 0 : aafs_remove_dir(&aa_fs_entry);
926 : 0 : }
927 : :
928 : : /**
929 : : * aa_create_aafs - create the apparmor security filesystem
930 : : *
931 : : * dentries created here are released by aa_destroy_aafs
932 : : *
933 : : * Returns: error on failure
934 : : */
935 : 0 : static int __init aa_create_aafs(void)
936 : : {
937 : : int error;
938 : :
939 [ # # ]: 0 : if (!apparmor_initialized)
940 : : return 0;
941 : :
942 [ # # ]: 0 : if (aa_fs_entry.dentry) {
943 [ # # ]: 0 : AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
944 : : return -EEXIST;
945 : : }
946 : :
947 : : /* Populate fs tree. */
948 : 0 : error = aafs_create_dir(&aa_fs_entry, NULL);
949 [ # # ]: 0 : if (error)
950 : : goto error;
951 : :
952 : 0 : error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry,
953 : : "policy");
954 [ # # ]: 0 : if (error)
955 : : goto error;
956 : :
957 : : /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
958 : :
959 : : /* Report that AppArmor fs is enabled */
960 : 0 : aa_info_message("AppArmor Filesystem Enabled");
961 : 0 : return 0;
962 : :
963 : : error:
964 : 0 : aa_destroy_aafs();
965 [ # # ]: 0 : AA_ERROR("Error creating AppArmor securityfs\n");
966 : 0 : return error;
967 : : }
968 : :
969 : : fs_initcall(aa_create_aafs);
|