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