blob: 0fdd08c6ea5920e9e7e1524b3a80107464565776 [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 Johansen63e2b422010-07-29 14:48:03 -070023
24#include "include/apparmor.h"
25#include "include/apparmorfs.h"
26#include "include/audit.h"
27#include "include/context.h"
28#include "include/policy.h"
Kees Cookd384b0a2012-01-26 16:29:23 -080029#include "include/resource.h"
John Johansen63e2b422010-07-29 14:48:03 -070030
31/**
John Johansen0d259f02013-07-10 21:13:43 -070032 * aa_mangle_name - mangle a profile name to std profile layout form
33 * @name: profile name to mangle (NOT NULL)
34 * @target: buffer to store mangled name, same length as @name (MAYBE NULL)
35 *
36 * Returns: length of mangled name
37 */
38static int mangle_name(char *name, char *target)
39{
40 char *t = target;
41
42 while (*name == '/' || *name == '.')
43 name++;
44
45 if (target) {
46 for (; *name; name++) {
47 if (*name == '/')
48 *(t)++ = '.';
49 else if (isspace(*name))
50 *(t)++ = '_';
51 else if (isalnum(*name) || strchr("._-", *name))
52 *(t)++ = *name;
53 }
54
55 *t = 0;
56 } else {
57 int len = 0;
58 for (; *name; name++) {
59 if (isalnum(*name) || isspace(*name) ||
60 strchr("/._-", *name))
61 len++;
62 }
63
64 return len;
65 }
66
67 return t - target;
68}
69
70/**
John Johansen63e2b422010-07-29 14:48:03 -070071 * aa_simple_write_to_buffer - common routine for getting policy from user
72 * @op: operation doing the user buffer copy
73 * @userbuf: user buffer to copy data from (NOT NULL)
John Johansen3ed02ad2010-10-09 00:47:53 -070074 * @alloc_size: size of user buffer (REQUIRES: @alloc_size >= @copy_size)
John Johansen63e2b422010-07-29 14:48:03 -070075 * @copy_size: size of data to copy from user buffer
76 * @pos: position write is at in the file (NOT NULL)
77 *
78 * Returns: kernel buffer containing copy of user buffer data or an
79 * ERR_PTR on failure.
80 */
81static char *aa_simple_write_to_buffer(int op, const char __user *userbuf,
82 size_t alloc_size, size_t copy_size,
83 loff_t *pos)
84{
85 char *data;
86
John Johansen3ed02ad2010-10-09 00:47:53 -070087 BUG_ON(copy_size > alloc_size);
88
John Johansen63e2b422010-07-29 14:48:03 -070089 if (*pos != 0)
90 /* only writes from pos 0, that is complete writes */
91 return ERR_PTR(-ESPIPE);
92
93 /*
94 * Don't allow profile load/replace/remove from profiles that don't
95 * have CAP_MAC_ADMIN
96 */
97 if (!aa_may_manage_policy(op))
98 return ERR_PTR(-EACCES);
99
100 /* freed by caller to simple_write_to_buffer */
101 data = kvmalloc(alloc_size);
102 if (data == NULL)
103 return ERR_PTR(-ENOMEM);
104
105 if (copy_from_user(data, userbuf, copy_size)) {
106 kvfree(data);
107 return ERR_PTR(-EFAULT);
108 }
109
110 return data;
111}
112
113
114/* .load file hook fn to load policy */
115static ssize_t profile_load(struct file *f, const char __user *buf, size_t size,
116 loff_t *pos)
117{
118 char *data;
119 ssize_t error;
120
121 data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos);
122
123 error = PTR_ERR(data);
124 if (!IS_ERR(data)) {
125 error = aa_replace_profiles(data, size, PROF_ADD);
126 kvfree(data);
127 }
128
129 return error;
130}
131
132static const struct file_operations aa_fs_profile_load = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200133 .write = profile_load,
134 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700135};
136
137/* .replace file hook fn to load and/or replace policy */
138static ssize_t profile_replace(struct file *f, const char __user *buf,
139 size_t size, loff_t *pos)
140{
141 char *data;
142 ssize_t error;
143
144 data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos);
145 error = PTR_ERR(data);
146 if (!IS_ERR(data)) {
147 error = aa_replace_profiles(data, size, PROF_REPLACE);
148 kvfree(data);
149 }
150
151 return error;
152}
153
154static const struct file_operations aa_fs_profile_replace = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200155 .write = profile_replace,
156 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700157};
158
159/* .remove file hook fn to remove loaded policy */
160static ssize_t profile_remove(struct file *f, const char __user *buf,
161 size_t size, loff_t *pos)
162{
163 char *data;
164 ssize_t error;
165
166 /*
167 * aa_remove_profile needs a null terminated string so 1 extra
168 * byte is allocated and the copied data is null terminated.
169 */
170 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos);
171
172 error = PTR_ERR(data);
173 if (!IS_ERR(data)) {
174 data[size] = 0;
175 error = aa_remove_profiles(data, size);
176 kvfree(data);
177 }
178
179 return error;
180}
181
182static const struct file_operations aa_fs_profile_remove = {
Arnd Bergmann6038f372010-08-15 18:52:59 +0200183 .write = profile_remove,
184 .llseek = default_llseek,
John Johansen63e2b422010-07-29 14:48:03 -0700185};
186
Kees Cooke74abcf2012-01-26 16:29:21 -0800187static int aa_fs_seq_show(struct seq_file *seq, void *v)
188{
189 struct aa_fs_entry *fs_file = seq->private;
190
191 if (!fs_file)
192 return 0;
193
194 switch (fs_file->v_type) {
195 case AA_FS_TYPE_BOOLEAN:
196 seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no");
197 break;
Kees Cooka9bf8e92012-01-26 16:29:22 -0800198 case AA_FS_TYPE_STRING:
199 seq_printf(seq, "%s\n", fs_file->v.string);
200 break;
Kees Cooke74abcf2012-01-26 16:29:21 -0800201 case AA_FS_TYPE_U64:
202 seq_printf(seq, "%#08lx\n", fs_file->v.u64);
203 break;
204 default:
205 /* Ignore unpritable entry types. */
206 break;
207 }
208
209 return 0;
210}
211
212static int aa_fs_seq_open(struct inode *inode, struct file *file)
213{
214 return single_open(file, aa_fs_seq_show, inode->i_private);
215}
216
217const struct file_operations aa_fs_seq_file_ops = {
218 .owner = THIS_MODULE,
219 .open = aa_fs_seq_open,
220 .read = seq_read,
221 .llseek = seq_lseek,
222 .release = single_release,
223};
224
John Johansen0d259f02013-07-10 21:13:43 -0700225static int aa_fs_seq_profile_open(struct inode *inode, struct file *file,
226 int (*show)(struct seq_file *, void *))
227{
228 struct aa_replacedby *r = aa_get_replacedby(inode->i_private);
229 int error = single_open(file, show, r);
John Johansen63e2b422010-07-29 14:48:03 -0700230
John Johansen0d259f02013-07-10 21:13:43 -0700231 if (error) {
232 file->private_data = NULL;
233 aa_put_replacedby(r);
234 }
235
236 return error;
237}
238
239static int aa_fs_seq_profile_release(struct inode *inode, struct file *file)
240{
241 struct seq_file *seq = (struct seq_file *) file->private_data;
242 if (seq)
243 aa_put_replacedby(seq->private);
244 return single_release(inode, file);
245}
246
247static int aa_fs_seq_profname_show(struct seq_file *seq, void *v)
248{
249 struct aa_replacedby *r = seq->private;
250 struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
251 seq_printf(seq, "%s\n", profile->base.name);
252 aa_put_profile(profile);
253
254 return 0;
255}
256
257static int aa_fs_seq_profname_open(struct inode *inode, struct file *file)
258{
259 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profname_show);
260}
261
262static const struct file_operations aa_fs_profname_fops = {
263 .owner = THIS_MODULE,
264 .open = aa_fs_seq_profname_open,
265 .read = seq_read,
266 .llseek = seq_lseek,
267 .release = aa_fs_seq_profile_release,
268};
269
270static int aa_fs_seq_profmode_show(struct seq_file *seq, void *v)
271{
272 struct aa_replacedby *r = seq->private;
273 struct aa_profile *profile = aa_get_profile_rcu(&r->profile);
274 seq_printf(seq, "%s\n", aa_profile_mode_names[profile->mode]);
275 aa_put_profile(profile);
276
277 return 0;
278}
279
280static int aa_fs_seq_profmode_open(struct inode *inode, struct file *file)
281{
282 return aa_fs_seq_profile_open(inode, file, aa_fs_seq_profmode_show);
283}
284
285static const struct file_operations aa_fs_profmode_fops = {
286 .owner = THIS_MODULE,
287 .open = aa_fs_seq_profmode_open,
288 .read = seq_read,
289 .llseek = seq_lseek,
290 .release = aa_fs_seq_profile_release,
291};
292
293/** fns to setup dynamic per profile/namespace files **/
294void __aa_fs_profile_rmdir(struct aa_profile *profile)
295{
296 struct aa_profile *child;
297 int i;
298
299 if (!profile)
300 return;
301
302 list_for_each_entry(child, &profile->base.profiles, base.list)
303 __aa_fs_profile_rmdir(child);
304
305 for (i = AAFS_PROF_SIZEOF - 1; i >= 0; --i) {
306 struct aa_replacedby *r;
307 if (!profile->dents[i])
308 continue;
309
310 r = profile->dents[i]->d_inode->i_private;
311 securityfs_remove(profile->dents[i]);
312 aa_put_replacedby(r);
313 profile->dents[i] = NULL;
314 }
315}
316
317void __aa_fs_profile_migrate_dents(struct aa_profile *old,
318 struct aa_profile *new)
319{
320 int i;
321
322 for (i = 0; i < AAFS_PROF_SIZEOF; i++) {
323 new->dents[i] = old->dents[i];
324 old->dents[i] = NULL;
325 }
326}
327
328static struct dentry *create_profile_file(struct dentry *dir, const char *name,
329 struct aa_profile *profile,
330 const struct file_operations *fops)
331{
332 struct aa_replacedby *r = aa_get_replacedby(profile->replacedby);
333 struct dentry *dent;
334
335 dent = securityfs_create_file(name, S_IFREG | 0444, dir, r, fops);
336 if (IS_ERR(dent))
337 aa_put_replacedby(r);
338
339 return dent;
340}
341
342/* requires lock be held */
343int __aa_fs_profile_mkdir(struct aa_profile *profile, struct dentry *parent)
344{
345 struct aa_profile *child;
346 struct dentry *dent = NULL, *dir;
347 int error;
348
349 if (!parent) {
350 struct aa_profile *p;
351 p = aa_deref_parent(profile);
352 dent = prof_dir(p);
353 /* adding to parent that previously didn't have children */
354 dent = securityfs_create_dir("profiles", dent);
355 if (IS_ERR(dent))
356 goto fail;
357 prof_child_dir(p) = parent = dent;
358 }
359
360 if (!profile->dirname) {
361 int len, id_len;
362 len = mangle_name(profile->base.name, NULL);
363 id_len = snprintf(NULL, 0, ".%ld", profile->ns->uniq_id);
364
365 profile->dirname = kmalloc(len + id_len + 1, GFP_KERNEL);
366 if (!profile->dirname)
367 goto fail;
368
369 mangle_name(profile->base.name, profile->dirname);
370 sprintf(profile->dirname + len, ".%ld", profile->ns->uniq_id++);
371 }
372
373 dent = securityfs_create_dir(profile->dirname, parent);
374 if (IS_ERR(dent))
375 goto fail;
376 prof_dir(profile) = dir = dent;
377
378 dent = create_profile_file(dir, "name", profile, &aa_fs_profname_fops);
379 if (IS_ERR(dent))
380 goto fail;
381 profile->dents[AAFS_PROF_NAME] = dent;
382
383 dent = create_profile_file(dir, "mode", profile, &aa_fs_profmode_fops);
384 if (IS_ERR(dent))
385 goto fail;
386 profile->dents[AAFS_PROF_MODE] = dent;
387
388 list_for_each_entry(child, &profile->base.profiles, base.list) {
389 error = __aa_fs_profile_mkdir(child, prof_child_dir(profile));
390 if (error)
391 goto fail2;
392 }
393
394 return 0;
395
396fail:
397 error = PTR_ERR(dent);
398
399fail2:
400 __aa_fs_profile_rmdir(profile);
401
402 return error;
403}
404
405void __aa_fs_namespace_rmdir(struct aa_namespace *ns)
406{
407 struct aa_namespace *sub;
408 struct aa_profile *child;
409 int i;
410
411 if (!ns)
412 return;
413
414 list_for_each_entry(child, &ns->base.profiles, base.list)
415 __aa_fs_profile_rmdir(child);
416
417 list_for_each_entry(sub, &ns->sub_ns, base.list) {
418 mutex_lock(&sub->lock);
419 __aa_fs_namespace_rmdir(sub);
420 mutex_unlock(&sub->lock);
421 }
422
423 for (i = AAFS_NS_SIZEOF - 1; i >= 0; --i) {
424 securityfs_remove(ns->dents[i]);
425 ns->dents[i] = NULL;
426 }
427}
428
429int __aa_fs_namespace_mkdir(struct aa_namespace *ns, struct dentry *parent,
430 const char *name)
431{
432 struct aa_namespace *sub;
433 struct aa_profile *child;
434 struct dentry *dent, *dir;
435 int error;
436
437 if (!name)
438 name = ns->base.name;
439
440 dent = securityfs_create_dir(name, parent);
441 if (IS_ERR(dent))
442 goto fail;
443 ns_dir(ns) = dir = dent;
444
445 dent = securityfs_create_dir("profiles", dir);
446 if (IS_ERR(dent))
447 goto fail;
448 ns_subprofs_dir(ns) = dent;
449
450 dent = securityfs_create_dir("namespaces", dir);
451 if (IS_ERR(dent))
452 goto fail;
453 ns_subns_dir(ns) = dent;
454
455 list_for_each_entry(child, &ns->base.profiles, base.list) {
456 error = __aa_fs_profile_mkdir(child, ns_subprofs_dir(ns));
457 if (error)
458 goto fail2;
459 }
460
461 list_for_each_entry(sub, &ns->sub_ns, base.list) {
462 mutex_lock(&sub->lock);
463 error = __aa_fs_namespace_mkdir(sub, ns_subns_dir(ns), NULL);
464 mutex_unlock(&sub->lock);
465 if (error)
466 goto fail2;
467 }
468
469 return 0;
470
471fail:
472 error = PTR_ERR(dent);
473
474fail2:
475 __aa_fs_namespace_rmdir(ns);
476
477 return error;
478}
479
480
481/** Base file system setup **/
Kees Cooka9bf8e92012-01-26 16:29:22 -0800482static struct aa_fs_entry aa_fs_entry_file[] = {
483 AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \
484 "link lock"),
485 { }
486};
487
Kees Cooke74abcf2012-01-26 16:29:21 -0800488static struct aa_fs_entry aa_fs_entry_domain[] = {
489 AA_FS_FILE_BOOLEAN("change_hat", 1),
490 AA_FS_FILE_BOOLEAN("change_hatv", 1),
491 AA_FS_FILE_BOOLEAN("change_onexec", 1),
492 AA_FS_FILE_BOOLEAN("change_profile", 1),
493 { }
494};
495
John Johansen9d910a32013-07-10 21:04:43 -0700496static struct aa_fs_entry aa_fs_entry_policy[] = {
John Johansendd51c8482013-07-10 21:05:43 -0700497 AA_FS_FILE_BOOLEAN("set_load", 1),
John Johansen9d910a32013-07-10 21:04:43 -0700498 {}
499};
500
Kees Cooke74abcf2012-01-26 16:29:21 -0800501static struct aa_fs_entry aa_fs_entry_features[] = {
John Johansen9d910a32013-07-10 21:04:43 -0700502 AA_FS_DIR("policy", aa_fs_entry_policy),
Kees Cooke74abcf2012-01-26 16:29:21 -0800503 AA_FS_DIR("domain", aa_fs_entry_domain),
Kees Cooka9bf8e92012-01-26 16:29:22 -0800504 AA_FS_DIR("file", aa_fs_entry_file),
Kees Cooke74abcf2012-01-26 16:29:21 -0800505 AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK),
Kees Cookd384b0a2012-01-26 16:29:23 -0800506 AA_FS_DIR("rlimit", aa_fs_entry_rlimit),
Kees Cooke74abcf2012-01-26 16:29:21 -0800507 { }
508};
509
Kees Cook9acd4942012-01-26 16:29:20 -0800510static struct aa_fs_entry aa_fs_entry_apparmor[] = {
511 AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load),
512 AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace),
513 AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove),
Kees Cooke74abcf2012-01-26 16:29:21 -0800514 AA_FS_DIR("features", aa_fs_entry_features),
Kees Cook9acd4942012-01-26 16:29:20 -0800515 { }
516};
John Johansen63e2b422010-07-29 14:48:03 -0700517
Kees Cook9acd4942012-01-26 16:29:20 -0800518static struct aa_fs_entry aa_fs_entry =
519 AA_FS_DIR("apparmor", aa_fs_entry_apparmor);
520
521/**
522 * aafs_create_file - create a file entry in the apparmor securityfs
523 * @fs_file: aa_fs_entry to build an entry for (NOT NULL)
524 * @parent: the parent dentry in the securityfs
525 *
526 * Use aafs_remove_file to remove entries created with this fn.
527 */
528static int __init aafs_create_file(struct aa_fs_entry *fs_file,
529 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -0700530{
Kees Cook9acd4942012-01-26 16:29:20 -0800531 int error = 0;
John Johansen63e2b422010-07-29 14:48:03 -0700532
Kees Cook9acd4942012-01-26 16:29:20 -0800533 fs_file->dentry = securityfs_create_file(fs_file->name,
534 S_IFREG | fs_file->mode,
535 parent, fs_file,
536 fs_file->file_ops);
537 if (IS_ERR(fs_file->dentry)) {
538 error = PTR_ERR(fs_file->dentry);
539 fs_file->dentry = NULL;
John Johansen63e2b422010-07-29 14:48:03 -0700540 }
Kees Cook9acd4942012-01-26 16:29:20 -0800541 return error;
John Johansen63e2b422010-07-29 14:48:03 -0700542}
543
John Johansen0d259f02013-07-10 21:13:43 -0700544static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -0700545/**
Kees Cook9acd4942012-01-26 16:29:20 -0800546 * aafs_create_dir - recursively create a directory entry in the securityfs
547 * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL)
548 * @parent: the parent dentry in the securityfs
John Johansen63e2b422010-07-29 14:48:03 -0700549 *
Kees Cook9acd4942012-01-26 16:29:20 -0800550 * Use aafs_remove_dir to remove entries created with this fn.
John Johansen63e2b422010-07-29 14:48:03 -0700551 */
Kees Cook9acd4942012-01-26 16:29:20 -0800552static int __init aafs_create_dir(struct aa_fs_entry *fs_dir,
553 struct dentry *parent)
John Johansen63e2b422010-07-29 14:48:03 -0700554{
Kees Cook9acd4942012-01-26 16:29:20 -0800555 struct aa_fs_entry *fs_file;
John Johansen0d259f02013-07-10 21:13:43 -0700556 struct dentry *dir;
557 int error;
John Johansen63e2b422010-07-29 14:48:03 -0700558
John Johansen0d259f02013-07-10 21:13:43 -0700559 dir = securityfs_create_dir(fs_dir->name, parent);
560 if (IS_ERR(dir))
561 return PTR_ERR(dir);
562 fs_dir->dentry = dir;
John Johansen63e2b422010-07-29 14:48:03 -0700563
John Johansen0d259f02013-07-10 21:13:43 -0700564 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -0800565 if (fs_file->v_type == AA_FS_TYPE_DIR)
566 error = aafs_create_dir(fs_file, fs_dir->dentry);
567 else
568 error = aafs_create_file(fs_file, fs_dir->dentry);
569 if (error)
570 goto failed;
571 }
572
573 return 0;
574
575failed:
John Johansen0d259f02013-07-10 21:13:43 -0700576 aafs_remove_dir(fs_dir);
577
Kees Cook9acd4942012-01-26 16:29:20 -0800578 return error;
579}
580
581/**
582 * aafs_remove_file - drop a single file entry in the apparmor securityfs
583 * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL)
584 */
585static void __init aafs_remove_file(struct aa_fs_entry *fs_file)
586{
587 if (!fs_file->dentry)
588 return;
589
590 securityfs_remove(fs_file->dentry);
591 fs_file->dentry = NULL;
592}
593
594/**
595 * aafs_remove_dir - recursively drop a directory entry from the securityfs
596 * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL)
597 */
598static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir)
599{
600 struct aa_fs_entry *fs_file;
601
John Johansen0d259f02013-07-10 21:13:43 -0700602 for (fs_file = fs_dir->v.files; fs_file && fs_file->name; ++fs_file) {
Kees Cook9acd4942012-01-26 16:29:20 -0800603 if (fs_file->v_type == AA_FS_TYPE_DIR)
604 aafs_remove_dir(fs_file);
605 else
606 aafs_remove_file(fs_file);
607 }
608
609 aafs_remove_file(fs_dir);
John Johansen63e2b422010-07-29 14:48:03 -0700610}
611
612/**
613 * aa_destroy_aafs - cleanup and free aafs
614 *
615 * releases dentries allocated by aa_create_aafs
616 */
617void __init aa_destroy_aafs(void)
618{
Kees Cook9acd4942012-01-26 16:29:20 -0800619 aafs_remove_dir(&aa_fs_entry);
John Johansen63e2b422010-07-29 14:48:03 -0700620}
621
622/**
623 * aa_create_aafs - create the apparmor security filesystem
624 *
625 * dentries created here are released by aa_destroy_aafs
626 *
627 * Returns: error on failure
628 */
James Morris3417d8d2011-08-17 11:05:21 +1000629static int __init aa_create_aafs(void)
John Johansen63e2b422010-07-29 14:48:03 -0700630{
631 int error;
632
633 if (!apparmor_initialized)
634 return 0;
635
Kees Cook9acd4942012-01-26 16:29:20 -0800636 if (aa_fs_entry.dentry) {
John Johansen63e2b422010-07-29 14:48:03 -0700637 AA_ERROR("%s: AppArmor securityfs already exists\n", __func__);
638 return -EEXIST;
639 }
640
Kees Cook9acd4942012-01-26 16:29:20 -0800641 /* Populate fs tree. */
642 error = aafs_create_dir(&aa_fs_entry, NULL);
John Johansen63e2b422010-07-29 14:48:03 -0700643 if (error)
644 goto error;
645
John Johansen0d259f02013-07-10 21:13:43 -0700646 error = __aa_fs_namespace_mkdir(root_ns, aa_fs_entry.dentry,
647 "policy");
648 if (error)
649 goto error;
650
John Johansen63e2b422010-07-29 14:48:03 -0700651 /* TODO: add support for apparmorfs_null and apparmorfs_mnt */
652
653 /* Report that AppArmor fs is enabled */
654 aa_info_message("AppArmor Filesystem Enabled");
655 return 0;
656
657error:
658 aa_destroy_aafs();
659 AA_ERROR("Error creating AppArmor securityfs\n");
660 return error;
661}
662
663fs_initcall(aa_create_aafs);