1
From: John Johansen <jjohansen@suse.de>
2
Subject: AppArmor: Module and LSM hooks
4
Module parameters, LSM hooks, initialization and teardown.
6
Signed-off-by: John Johansen <jjohansen@suse.de>
7
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
10
security/apparmor/lsm.c | 889 ++++++++++++++++++++++++++++++++++++++++++++++++
11
1 file changed, 889 insertions(+)
14
+++ b/security/apparmor/lsm.c
17
+ * Copyright (C) 1998-2007 Novell/SUSE
19
+ * This program is free software; you can redistribute it and/or
20
+ * modify it under the terms of the GNU General Public License as
21
+ * published by the Free Software Foundation, version 2 of the
24
+ * AppArmor LSM interface
27
+#include <linux/security.h>
28
+#include <linux/module.h>
29
+#include <linux/mm.h>
30
+#include <linux/mman.h>
31
+#include <linux/mount.h>
32
+#include <linux/namei.h>
33
+#include <linux/ctype.h>
34
+#include <linux/sysctl.h>
35
+#include <linux/audit.h>
37
+#include "apparmor.h"
40
+/* Flag indicating whether initialization completed */
41
+int apparmor_initialized = 0;
43
+static int param_set_aabool(const char *val, struct kernel_param *kp);
44
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
45
+#define param_check_aabool(name, p) __param_check(name, p, int)
47
+static int param_set_aauint(const char *val, struct kernel_param *kp);
48
+static int param_get_aauint(char *buffer, struct kernel_param *kp);
49
+#define param_check_aauint(name, p) __param_check(name, p, int)
51
+/* Flag values, also controllable via /sys/module/apparmor/parameters
52
+ * We define special types as we want to do additional mediation.
54
+ * Complain mode -- in complain mode access failures result in auditing only
55
+ * and task is allowed access. audit events are processed by userspace to
56
+ * generate policy. Default is 'enforce' (0).
57
+ * Value is also togglable per profile and referenced when global value is
60
+int apparmor_complain = 0;
61
+module_param_named(complain, apparmor_complain, aabool, S_IRUSR | S_IWUSR);
62
+MODULE_PARM_DESC(apparmor_complain, "Toggle AppArmor complain mode");
65
+int apparmor_debug = 0;
66
+module_param_named(debug, apparmor_debug, aabool, S_IRUSR | S_IWUSR);
67
+MODULE_PARM_DESC(apparmor_debug, "Toggle AppArmor debug mode");
70
+int apparmor_audit = 0;
71
+module_param_named(audit, apparmor_audit, aabool, S_IRUSR | S_IWUSR);
72
+MODULE_PARM_DESC(apparmor_audit, "Toggle AppArmor audit mode");
74
+/* Syscall logging mode */
75
+int apparmor_logsyscall = 0;
76
+module_param_named(logsyscall, apparmor_logsyscall, aabool, S_IRUSR | S_IWUSR);
77
+MODULE_PARM_DESC(apparmor_logsyscall, "Toggle AppArmor logsyscall mode");
79
+/* Maximum pathname length before accesses will start getting rejected */
80
+unsigned int apparmor_path_max = 2 * PATH_MAX;
81
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
82
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
84
+/* Boot time disable flag */
85
+#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
86
+#define AA_ENABLED_PERMS 0600
88
+#define AA_ENABLED_PERMS 0400
90
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
91
+unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
92
+module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
93
+ &apparmor_enabled, AA_ENABLED_PERMS);
94
+MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
96
+static int __init apparmor_enabled_setup(char *str)
98
+ apparmor_enabled = simple_strtol(str, NULL, 0);
101
+__setup("apparmor=", apparmor_enabled_setup);
103
+static int param_set_aabool(const char *val, struct kernel_param *kp)
105
+ if (aa_task_context(current))
107
+ return param_set_bool(val, kp);
110
+static int param_get_aabool(char *buffer, struct kernel_param *kp)
112
+ if (aa_task_context(current))
114
+ return param_get_bool(buffer, kp);
117
+static int param_set_aauint(const char *val, struct kernel_param *kp)
119
+ if (aa_task_context(current))
121
+ return param_set_uint(val, kp);
124
+static int param_get_aauint(char *buffer, struct kernel_param *kp)
126
+ if (aa_task_context(current))
128
+ return param_get_uint(buffer, kp);
131
+/* allow run time disabling of apparmor */
132
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
137
+ if (!apparmor_initialized) {
138
+ apparmor_enabled = 0;
142
+ if (aa_task_context(current))
145
+ if (!apparmor_enabled)
151
+ l = simple_strtoul(val, &endp, 0);
152
+ if (endp == val || l != 0)
155
+ apparmor_enabled = 0;
156
+ apparmor_disable();
160
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
163
+ struct aa_profile *profile = aa_get_profile(task);
167
+ error = aa_audit_syscallreject(profile, flags, name);
168
+ aa_put_profile(profile);
174
+static int apparmor_ptrace(struct task_struct *parent,
175
+ struct task_struct *child)
177
+ struct aa_task_context *cxt;
181
+ * parent can ptrace child when
182
+ * - parent is unconfined
183
+ * - parent & child are in the same namespace &&
184
+ * - parent is in complain mode
185
+ * - parent and child are confined by the same profile
186
+ * - parent profile has CAP_SYS_PTRACE
190
+ cxt = aa_task_context(parent);
192
+ if (parent->nsproxy != child->nsproxy) {
193
+ struct aa_audit sa;
194
+ memset(&sa, 0, sizeof(sa));
195
+ sa.operation = "ptrace";
196
+ sa.gfp_mask = GFP_ATOMIC;
197
+ sa.parent = parent->pid;
198
+ sa.task = child->pid;
199
+ sa.info = "different namespaces";
200
+ aa_audit_reject(cxt->profile, &sa);
203
+ struct aa_task_context *child_cxt =
204
+ aa_task_context(child);
206
+ error = aa_may_ptrace(cxt, child_cxt ?
207
+ child_cxt->profile : NULL);
208
+ if (PROFILE_COMPLAIN(cxt->profile)) {
209
+ struct aa_audit sa;
210
+ memset(&sa, 0, sizeof(sa));
211
+ sa.operation = "ptrace";
212
+ sa.gfp_mask = GFP_ATOMIC;
213
+ sa.parent = parent->pid;
214
+ sa.task = child->pid;
215
+ aa_audit_hint(cxt->profile, &sa);
224
+static int apparmor_capable(struct task_struct *task, int cap)
227
+ struct aa_task_context *cxt;
229
+ /* cap_capable returns 0 on success, else -EPERM */
230
+ error = cap_capable(task, cap);
233
+ cxt = aa_task_context(task);
234
+ if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
235
+ error = aa_capability(cxt, cap);
241
+static int apparmor_sysctl(struct ctl_table *table, int op)
243
+ struct aa_profile *profile = aa_get_profile(current);
247
+ char *buffer, *name;
257
+ buffer = (char*)__get_free_page(GFP_KERNEL);
260
+ name = sysctl_pathname(table, buffer, PAGE_SIZE);
261
+ if (name && name - buffer >= 5) {
263
+ memcpy(name, "/proc", 5);
264
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
266
+ free_page((unsigned long)buffer);
270
+ aa_put_profile(profile);
274
+static int apparmor_bprm_set_security(struct linux_binprm *bprm)
276
+ /* handle capability bits with setuid, etc */
277
+ cap_bprm_set_security(bprm);
278
+ /* already set based on script name */
281
+ return aa_register(bprm);
284
+static int apparmor_bprm_secureexec(struct linux_binprm *bprm)
286
+ int ret = cap_bprm_secureexec(bprm);
288
+ if (!ret && (unsigned long)bprm->security & AA_SECURE_EXEC_NEEDED) {
289
+ AA_DEBUG("%s: secureexec required for %s\n",
290
+ __FUNCTION__, bprm->filename);
297
+static int apparmor_sb_mount(char *dev_name, struct nameidata *nd, char *type,
298
+ unsigned long flags, void *data)
300
+ return aa_reject_syscall(current, GFP_KERNEL, "mount");
303
+static int apparmor_umount(struct vfsmount *mnt, int flags)
305
+ return aa_reject_syscall(current, GFP_KERNEL, "umount");
308
+static int apparmor_inode_mkdir(struct inode *dir, struct dentry *dentry,
309
+ struct vfsmount *mnt, int mask)
311
+ struct aa_profile *profile;
314
+ if (!mnt || !mediated_filesystem(dir))
317
+ profile = aa_get_profile(current);
320
+ error = aa_perm_dir(profile, "inode_mkdir", dentry, mnt,
323
+ aa_put_profile(profile);
329
+static int apparmor_inode_rmdir(struct inode *dir, struct dentry *dentry,
330
+ struct vfsmount *mnt)
332
+ struct aa_profile *profile;
335
+ if (!mnt || !mediated_filesystem(dir))
338
+ profile = aa_get_profile(current);
341
+ error = aa_perm_dir(profile, "inode_rmdir", dentry, mnt,
344
+ aa_put_profile(profile);
350
+static int aa_permission(const char *operation, struct inode *inode,
351
+ struct dentry *dentry, struct vfsmount *mnt,
352
+ int mask, int check)
356
+ if (mnt && mediated_filesystem(inode)) {
357
+ struct aa_profile *profile;
359
+ profile = aa_get_profile(current);
361
+ error = aa_perm(profile, operation, dentry, mnt, mask,
363
+ aa_put_profile(profile);
368
+static inline int aa_mask_permissions(int mask)
370
+ if (mask & MAY_APPEND)
371
+ mask &= (MAY_READ | MAY_APPEND | MAY_EXEC);
373
+ mask &= (MAY_READ | MAY_WRITE | MAY_EXEC);
377
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
378
+ struct vfsmount *mnt, int mask)
380
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
383
+static int apparmor_inode_link(struct dentry *old_dentry,
384
+ struct vfsmount *old_mnt, struct inode *dir,
385
+ struct dentry *new_dentry,
386
+ struct vfsmount *new_mnt)
389
+ struct aa_profile *profile;
391
+ if (!old_mnt || !new_mnt || !mediated_filesystem(dir))
394
+ profile = aa_get_profile(current);
397
+ error = aa_link(profile, new_dentry, new_mnt,
398
+ old_dentry, old_mnt);
400
+ aa_put_profile(profile);
406
+static int apparmor_inode_unlink(struct inode *dir, struct dentry *dentry,
407
+ struct vfsmount *mnt)
411
+ if (S_ISDIR(dentry->d_inode->i_mode))
412
+ check |= AA_CHECK_DIR;
413
+ return aa_permission("inode_unlink", dir, dentry, mnt, MAY_WRITE,
417
+static int apparmor_inode_symlink(struct inode *dir, struct dentry *dentry,
418
+ struct vfsmount *mnt, const char *old_name)
420
+ return aa_permission("inode_symlink", dir, dentry, mnt, MAY_WRITE, 0);
423
+static int apparmor_inode_mknod(struct inode *dir, struct dentry *dentry,
424
+ struct vfsmount *mnt, int mode, dev_t dev)
426
+ return aa_permission("inode_mknod", dir, dentry, mnt, MAY_WRITE, 0);
429
+static int apparmor_inode_rename(struct inode *old_dir,
430
+ struct dentry *old_dentry,
431
+ struct vfsmount *old_mnt,
432
+ struct inode *new_dir,
433
+ struct dentry *new_dentry,
434
+ struct vfsmount *new_mnt)
436
+ struct aa_profile *profile;
439
+ if ((!old_mnt && !new_mnt) || !mediated_filesystem(old_dir))
442
+ profile = aa_get_profile(current);
445
+ struct inode *inode = old_dentry->d_inode;
448
+ if (inode && S_ISDIR(inode->i_mode))
449
+ check |= AA_CHECK_DIR;
451
+ error = aa_perm(profile, "inode_rename", old_dentry,
452
+ old_mnt, MAY_READ | MAY_WRITE, check);
454
+ if (!error && new_mnt) {
455
+ error = aa_perm(profile, "inode_rename", new_dentry,
456
+ new_mnt, MAY_WRITE, check);
460
+ aa_put_profile(profile);
466
+static int apparmor_inode_permission(struct inode *inode, int mask,
467
+ struct nameidata *nd)
471
+ if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE))
473
+ mask = aa_mask_permissions(mask);
474
+ if (S_ISDIR(inode->i_mode)) {
475
+ check |= AA_CHECK_DIR;
476
+ /* allow traverse accesses to directories */
479
+ return aa_permission("inode_permission", inode, nd->dentry, nd->mnt,
483
+static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt,
484
+ struct iattr *iattr)
491
+ if (mediated_filesystem(dentry->d_inode)) {
492
+ struct aa_profile *profile;
494
+ profile = aa_get_profile(current);
496
+ * Mediate any attempt to change attributes of a file
497
+ * (chmod, chown, chgrp, etc)
500
+ error = aa_attr(profile, dentry, mnt, iattr);
502
+ aa_put_profile(profile);
509
+static int aa_xattr_permission(struct dentry *dentry, struct vfsmount *mnt,
510
+ const char *operation, int mask,
515
+ if (mnt && mediated_filesystem(dentry->d_inode)) {
516
+ struct aa_profile *profile = aa_get_profile(current);
517
+ int check = file ? AA_CHECK_FD : 0;
520
+ error = aa_perm_xattr(profile, operation, dentry, mnt,
522
+ aa_put_profile(profile);
528
+static int apparmor_inode_setxattr(struct dentry *dentry, struct vfsmount *mnt,
529
+ char *name, void *value, size_t size,
530
+ int flags, struct file *file)
532
+ return aa_xattr_permission(dentry, mnt, "xattr set", MAY_WRITE, file);
535
+static int apparmor_inode_getxattr(struct dentry *dentry, struct vfsmount *mnt,
536
+ char *name, struct file *file)
538
+ return aa_xattr_permission(dentry, mnt, "xattr get", MAY_READ, file);
541
+static int apparmor_inode_listxattr(struct dentry *dentry, struct vfsmount *mnt,
544
+ return aa_xattr_permission(dentry, mnt, "xattr list", MAY_READ, file);
547
+static int apparmor_inode_removexattr(struct dentry *dentry,
548
+ struct vfsmount *mnt, char *name,
551
+ return aa_xattr_permission(dentry, mnt, "xattr remove", MAY_WRITE,
555
+static int aa_file_permission(const char *op, struct file *file, int mask)
557
+ struct aa_profile *profile;
558
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
565
+ * If this file was opened under a different profile, we
566
+ * revalidate the access against the current profile.
568
+ profile = aa_get_profile(current);
569
+ if (profile && (file_profile != profile || mask & AA_MAY_LOCK)) {
570
+ struct dentry *dentry = file->f_dentry;
571
+ struct vfsmount *mnt = file->f_vfsmnt;
572
+ struct inode *inode = dentry->d_inode;
573
+ int check = AA_CHECK_FD;
576
+ * FIXME: We should remember which profiles we revalidated
579
+ if (S_ISDIR(inode->i_mode))
580
+ check |= AA_CHECK_DIR;
581
+ error = aa_permission(op, inode, dentry, mnt, mask, check);
583
+ aa_put_profile(profile);
589
+static int apparmor_file_permission(struct file *file, int mask)
591
+ return aa_file_permission("file_permission", file,
592
+ aa_mask_permissions(mask));
595
+static inline int apparmor_file_lock (struct file *file, unsigned int cmd)
597
+ int mask = AA_MAY_LOCK;
598
+ if (cmd == F_WRLCK)
600
+ return aa_file_permission("file_lock", file, mask);
603
+static int apparmor_file_alloc_security(struct file *file)
605
+ struct aa_profile *profile;
607
+ profile = aa_get_profile(current);
609
+ file->f_security = profile;
614
+static void apparmor_file_free_security(struct file *file)
616
+ struct aa_profile *file_profile = (struct aa_profile*)file->f_security;
618
+ aa_put_profile(file_profile);
621
+static inline int aa_mmap(struct file *file, const char *operation,
622
+ unsigned long prot, unsigned long flags)
624
+ struct dentry *dentry;
627
+ if (!file || !file->f_security)
630
+ if (prot & PROT_READ)
632
+ /* Private mappings don't require write perms since they don't
633
+ * write back to the files */
634
+ if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
636
+ if (prot & PROT_EXEC)
637
+ mask |= AA_EXEC_MMAP;
639
+ dentry = file->f_dentry;
640
+ return aa_permission(operation, dentry->d_inode, dentry,
641
+ file->f_vfsmnt, mask, AA_CHECK_FD);
644
+static int apparmor_file_mmap(struct file *file, unsigned long reqprot,
645
+ unsigned long prot, unsigned long flags,
646
+ unsigned long addr, unsigned long addr_only)
648
+ if ((addr < mmap_min_addr) && !capable(CAP_SYS_RAWIO)) {
649
+ struct aa_profile *profile = aa_get_profile(current);
651
+ /* future control check here */
655
+ aa_put_profile(profile);
658
+ return aa_mmap(file, "file_mmap", prot, flags);
661
+static int apparmor_file_mprotect(struct vm_area_struct *vma,
662
+ unsigned long reqprot, unsigned long prot)
664
+ return aa_mmap(vma->vm_file, "file_mprotect", prot,
665
+ !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
668
+static int apparmor_task_alloc_security(struct task_struct *task)
670
+ return aa_clone(task);
674
+ * Called from IRQ context from RCU callback.
676
+static void apparmor_task_free_security(struct task_struct *task)
681
+static int apparmor_getprocattr(struct task_struct *task, char *name,
686
+ struct aa_profile *profile;
688
+ /* AppArmor only supports the "current" process attribute */
689
+ if (strcmp(name, "current") != 0)
692
+ /* must be task querying itself or admin */
693
+ if (current != task && !capable(CAP_SYS_ADMIN))
696
+ profile = aa_get_profile(task);
697
+ error = aa_getprocattr(profile, value, &len);
698
+ aa_put_profile(profile);
705
+static int apparmor_setprocattr(struct task_struct *task, char *name,
706
+ void *value, size_t size)
708
+ char *command, *args;
711
+ if (strcmp(name, "current") != 0 || size == 0 || size >= PAGE_SIZE)
715
+ args = strstrip(args);
716
+ command = strsep(&args, " ");
719
+ while (isspace(*args))
724
+ if (strcmp(command, "changehat") == 0) {
725
+ if (current != task)
727
+ error = aa_setprocattr_changehat(args);
728
+ } else if (strcmp(command, "changeprofile") == 0) {
729
+ if (current != task)
731
+ error = aa_setprocattr_changeprofile(args);
732
+ } else if (strcmp(command, "setprofile") == 0) {
733
+ struct aa_profile *profile;
735
+ /* Only an unconfined process with admin capabilities
736
+ * may change the profile of another task.
739
+ if (!capable(CAP_SYS_ADMIN))
742
+ profile = aa_get_profile(current);
744
+ struct aa_audit sa;
745
+ memset(&sa, 0, sizeof(sa));
746
+ sa.operation = "profile_set";
747
+ sa.gfp_mask = GFP_KERNEL;
748
+ sa.task = task->pid;
749
+ sa.info = "from confined process";
750
+ aa_audit_reject(profile, &sa);
751
+ aa_put_profile(profile);
754
+ error = aa_setprocattr_setprofile(task, args);
756
+ struct aa_audit sa;
757
+ memset(&sa, 0, sizeof(sa));
758
+ sa.operation = "setprocattr";
759
+ sa.gfp_mask = GFP_KERNEL;
760
+ sa.info = "invalid command";
762
+ sa.task = task->pid;
763
+ aa_audit_reject(NULL, &sa);
772
+struct security_operations apparmor_ops = {
773
+ .ptrace = apparmor_ptrace,
774
+ .capget = cap_capget,
775
+ .capset_check = cap_capset_check,
776
+ .capset_set = cap_capset_set,
777
+ .sysctl = apparmor_sysctl,
778
+ .capable = apparmor_capable,
779
+ .syslog = cap_syslog,
781
+ .netlink_send = cap_netlink_send,
782
+ .netlink_recv = cap_netlink_recv,
784
+ .bprm_apply_creds = cap_bprm_apply_creds,
785
+ .bprm_set_security = apparmor_bprm_set_security,
786
+ .bprm_secureexec = apparmor_bprm_secureexec,
788
+ .sb_mount = apparmor_sb_mount,
789
+ .sb_umount = apparmor_umount,
791
+ .inode_mkdir = apparmor_inode_mkdir,
792
+ .inode_rmdir = apparmor_inode_rmdir,
793
+ .inode_create = apparmor_inode_create,
794
+ .inode_link = apparmor_inode_link,
795
+ .inode_unlink = apparmor_inode_unlink,
796
+ .inode_symlink = apparmor_inode_symlink,
797
+ .inode_mknod = apparmor_inode_mknod,
798
+ .inode_rename = apparmor_inode_rename,
799
+ .inode_permission = apparmor_inode_permission,
800
+ .inode_setattr = apparmor_inode_setattr,
801
+ .inode_setxattr = apparmor_inode_setxattr,
802
+ .inode_getxattr = apparmor_inode_getxattr,
803
+ .inode_listxattr = apparmor_inode_listxattr,
804
+ .inode_removexattr = apparmor_inode_removexattr,
805
+ .file_permission = apparmor_file_permission,
806
+ .file_alloc_security = apparmor_file_alloc_security,
807
+ .file_free_security = apparmor_file_free_security,
808
+ .file_mmap = apparmor_file_mmap,
809
+ .file_mprotect = apparmor_file_mprotect,
810
+ .file_lock = apparmor_file_lock,
812
+ .task_alloc_security = apparmor_task_alloc_security,
813
+ .task_free_security = apparmor_task_free_security,
814
+ .task_post_setuid = cap_task_post_setuid,
815
+ .task_reparent_to_init = cap_task_reparent_to_init,
817
+ .getprocattr = apparmor_getprocattr,
818
+ .setprocattr = apparmor_setprocattr,
821
+void info_message(const char *str)
823
+ struct aa_audit sa;
824
+ memset(&sa, 0, sizeof(sa));
825
+ sa.gfp_mask = GFP_KERNEL;
827
+ printk(KERN_INFO "AppArmor: %s\n", str);
829
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
832
+static int __init apparmor_init(void)
836
+ if (!apparmor_enabled) {
837
+ info_message("AppArmor disabled by boottime parameter\n");
841
+ if ((error = create_apparmorfs())) {
842
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
846
+ if ((error = alloc_default_namespace())){
847
+ AA_ERROR("Unable to allocate default profile namespace\n");
851
+ if ((error = register_security(&apparmor_ops))) {
852
+ AA_ERROR("Unable to register AppArmor\n");
853
+ goto register_security_out;
856
+ /* Report that AppArmor successfully initialized */
857
+ apparmor_initialized = 1;
858
+ if (apparmor_complain)
859
+ info_message("AppArmor initialized: complainmode enabled");
861
+ info_message("AppArmor initialized");
865
+register_security_out:
866
+ free_default_namespace();
869
+ destroy_apparmorfs();
876
+security_initcall(apparmor_init);
878
+void apparmor_disable(void)
880
+ /* Remove and release all the profiles on the profile list. */
881
+ mutex_lock(&aa_interface_lock);
882
+ aa_profile_ns_list_release();
884
+ /* FIXME: cleanup profiles references on files */
885
+ free_default_namespace();
888
+ * Delay for an rcu cycle to make sure that all active task
889
+ * context readers have finished, and all profiles have been
890
+ * freed by their rcu callbacks.
894
+ destroy_apparmorfs();
895
+ mutex_unlock(&aa_interface_lock);
897
+ apparmor_initialized = 0;
899
+ info_message("AppArmor protection removed");
902
+MODULE_DESCRIPTION("AppArmor process confinement");
903
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
904
+MODULE_LICENSE("GPL");