mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
merge patches down to start cleaning up
This commit is contained in:
parent
1daeaa9308
commit
2ed2bc67f0
6 changed files with 1393 additions and 587 deletions
|
@ -7,12 +7,12 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
|
|
||||||
---
|
---
|
||||||
security/apparmor/lsm.c | 841 ++++++++++++++++++++++++++++++++++++++++++++++++
|
security/apparmor/lsm.c | 879 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
1 file changed, 841 insertions(+)
|
1 file changed, 879 insertions(+)
|
||||||
|
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/lsm.c
|
+++ b/security/apparmor/lsm.c
|
||||||
@@ -0,0 +1,841 @@
|
@@ -0,0 +1,879 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -37,6 +37,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#include "apparmor.h"
|
+#include "apparmor.h"
|
||||||
+#include "inline.h"
|
+#include "inline.h"
|
||||||
+
|
+
|
||||||
|
+/* Flag indicating whether initialization completed */
|
||||||
|
+int apparmor_initialized = 0;
|
||||||
|
+
|
||||||
+static int param_set_aabool(const char *val, struct kernel_param *kp);
|
+static int param_set_aabool(const char *val, struct kernel_param *kp);
|
||||||
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
|
+static int param_get_aabool(char *buffer, struct kernel_param *kp);
|
||||||
+#define param_check_aabool(name, p) __param_check(name, p, int)
|
+#define param_check_aabool(name, p) __param_check(name, p, int)
|
||||||
|
@ -78,6 +81,25 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
|
+module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR);
|
||||||
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
|
+MODULE_PARM_DESC(apparmor_path_max, "Maximum pathname length allowed");
|
||||||
+
|
+
|
||||||
|
+/* Boot time disable flag */
|
||||||
|
+#ifdef CONFIG_SECURITY_APPARMOR_DISABLE
|
||||||
|
+#define AA_ENABLED_PERMS 0600
|
||||||
|
+#else
|
||||||
|
+#define AA_ENABLED_PERMS 0400
|
||||||
|
+#endif
|
||||||
|
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp);
|
||||||
|
+unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE;
|
||||||
|
+module_param_call(enabled, param_set_aa_enabled, param_get_aauint,
|
||||||
|
+ &apparmor_enabled, AA_ENABLED_PERMS);
|
||||||
|
+MODULE_PARM_DESC(apparmor_enabled, "Enable/Disable Apparmor on boot");
|
||||||
|
+
|
||||||
|
+static int __init apparmor_enabled_setup(char *str)
|
||||||
|
+{
|
||||||
|
+ apparmor_enabled = simple_strtol(str, NULL, 0);
|
||||||
|
+ return 1;
|
||||||
|
+}
|
||||||
|
+__setup("apparmor=", apparmor_enabled_setup);
|
||||||
|
+
|
||||||
+static int param_set_aabool(const char *val, struct kernel_param *kp)
|
+static int param_set_aabool(const char *val, struct kernel_param *kp)
|
||||||
+{
|
+{
|
||||||
+ if (aa_task_context(current))
|
+ if (aa_task_context(current))
|
||||||
|
@ -106,6 +128,35 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return param_get_uint(buffer, kp);
|
+ return param_get_uint(buffer, kp);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
+/* allow run time disabling of apparmor */
|
||||||
|
+static int param_set_aa_enabled(const char *val, struct kernel_param *kp)
|
||||||
|
+{
|
||||||
|
+ char *endp;
|
||||||
|
+ unsigned long l;
|
||||||
|
+
|
||||||
|
+ if (!apparmor_initialized) {
|
||||||
|
+ apparmor_enabled = 0;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (aa_task_context(current))
|
||||||
|
+ return -EPERM;
|
||||||
|
+
|
||||||
|
+ if (!apparmor_enabled)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ if (!val)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ l = simple_strtoul(val, &endp, 0);
|
||||||
|
+ if (endp == val || l != 0)
|
||||||
|
+ return -EINVAL;
|
||||||
|
+
|
||||||
|
+ apparmor_enabled = 0;
|
||||||
|
+ apparmor_disable();
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
|
+static int aa_reject_syscall(struct task_struct *task, gfp_t flags,
|
||||||
+ const char *name)
|
+ const char *name)
|
||||||
+{
|
+{
|
||||||
|
@ -173,19 +224,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+static int apparmor_capable(struct task_struct *task, int cap)
|
+static int apparmor_capable(struct task_struct *task, int cap)
|
||||||
+{
|
+{
|
||||||
+ int error;
|
+ int error;
|
||||||
|
+ struct aa_task_context *cxt;
|
||||||
+
|
+
|
||||||
+ /* cap_capable returns 0 on success, else -EPERM */
|
+ /* cap_capable returns 0 on success, else -EPERM */
|
||||||
+ error = cap_capable(task, cap);
|
+ error = cap_capable(task, cap);
|
||||||
+
|
+
|
||||||
+ if (!error) {
|
|
||||||
+ struct aa_task_context *cxt;
|
|
||||||
+
|
|
||||||
+ rcu_read_lock();
|
+ rcu_read_lock();
|
||||||
+ cxt = aa_task_context(task);
|
+ cxt = aa_task_context(task);
|
||||||
+ if (cxt)
|
+ if (cxt && (!error || cap_raised(cxt->profile->set_caps, cap)))
|
||||||
+ error = aa_capability(cxt, cap);
|
+ error = aa_capability(cxt, cap);
|
||||||
+ rcu_read_unlock();
|
+ rcu_read_unlock();
|
||||||
+ }
|
|
||||||
+
|
+
|
||||||
+ return error;
|
+ return error;
|
||||||
+}
|
+}
|
||||||
|
@ -213,12 +261,13 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ if (name && name - buffer >= 5) {
|
+ if (name && name - buffer >= 5) {
|
||||||
+ name -= 5;
|
+ name -= 5;
|
||||||
+ memcpy(name, "/proc", 5);
|
+ memcpy(name, "/proc", 5);
|
||||||
+ error = aa_perm_path(profile, "sysctl", name, mask);
|
+ error = aa_perm_path(profile, "sysctl", name, mask, 0);
|
||||||
+ }
|
+ }
|
||||||
+ free_page((unsigned long)buffer);
|
+ free_page((unsigned long)buffer);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+out:
|
+out:
|
||||||
|
+ aa_put_profile(profile);
|
||||||
+ return error;
|
+ return error;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -328,8 +377,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
|
+static int apparmor_inode_create(struct inode *dir, struct dentry *dentry,
|
||||||
+ struct vfsmount *mnt, int mask)
|
+ struct vfsmount *mnt, int mask)
|
||||||
+{
|
+{
|
||||||
+ /* FIXME: may move to MAY_APPEND later */
|
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_APPEND, 0);
|
||||||
+ return aa_permission("inode_create", dir, dentry, mnt, MAY_WRITE, 0);
|
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int apparmor_inode_link(struct dentry *old_dentry,
|
+static int apparmor_inode_link(struct dentry *old_dentry,
|
||||||
|
@ -760,13 +808,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ .setprocattr = apparmor_setprocattr,
|
+ .setprocattr = apparmor_setprocattr,
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+static void info_message(const char *str)
|
+void info_message(const char *str)
|
||||||
+{
|
+{
|
||||||
+ struct aa_audit sa;
|
+ struct aa_audit sa;
|
||||||
+ memset(&sa, 0, sizeof(sa));
|
+ memset(&sa, 0, sizeof(sa));
|
||||||
+ sa.gfp_mask = GFP_KERNEL;
|
+ sa.gfp_mask = GFP_KERNEL;
|
||||||
+ sa.info = str;
|
+ sa.info = str;
|
||||||
+ printk(KERN_INFO "AppArmor: %s", str);
|
+ printk(KERN_INFO "AppArmor: %s\n", str);
|
||||||
|
+ if (audit_enabled)
|
||||||
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
|
+ aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -774,13 +823,18 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+{
|
+{
|
||||||
+ int error;
|
+ int error;
|
||||||
+
|
+
|
||||||
|
+ if (!apparmor_enabled) {
|
||||||
|
+ info_message("AppArmor disabled by boottime parameter\n");
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ if ((error = create_apparmorfs())) {
|
+ if ((error = create_apparmorfs())) {
|
||||||
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
|
+ AA_ERROR("Unable to activate AppArmor filesystem\n");
|
||||||
+ goto createfs_out;
|
+ goto createfs_out;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if ((error = alloc_null_complain_profile())){
|
+ if ((error = alloc_default_namespace())){
|
||||||
+ AA_ERROR("Unable to allocate null complain profile\n");
|
+ AA_ERROR("Unable to allocate default profile namespace\n");
|
||||||
+ goto alloc_out;
|
+ goto alloc_out;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
@ -789,6 +843,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ goto register_security_out;
|
+ goto register_security_out;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ /* Report that AppArmor successfully initialized */
|
||||||
|
+ apparmor_initialized = 1;
|
||||||
+ if (apparmor_complain)
|
+ if (apparmor_complain)
|
||||||
+ info_message("AppArmor initialized: complainmode enabled");
|
+ info_message("AppArmor initialized: complainmode enabled");
|
||||||
+ else
|
+ else
|
||||||
|
@ -797,7 +853,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return error;
|
+ return error;
|
||||||
+
|
+
|
||||||
+register_security_out:
|
+register_security_out:
|
||||||
+ free_null_complain_profile();
|
+ free_default_namespace();
|
||||||
+
|
+
|
||||||
+alloc_out:
|
+alloc_out:
|
||||||
+ destroy_apparmorfs();
|
+ destroy_apparmorfs();
|
||||||
|
@ -807,30 +863,16 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static void __exit apparmor_exit(void)
|
+security_initcall(apparmor_init);
|
||||||
|
+
|
||||||
|
+void apparmor_disable(void)
|
||||||
+{
|
+{
|
||||||
+ /* Remove and release all the profiles on the profile list. */
|
+ /* Remove and release all the profiles on the profile list. */
|
||||||
+ mutex_lock(&aa_interface_lock);
|
+ mutex_lock(&aa_interface_lock);
|
||||||
+ write_lock(&profile_list_lock);
|
+ aa_profile_ns_list_release();
|
||||||
+ while (!list_empty(&profile_list)) {
|
|
||||||
+ struct aa_profile *profile =
|
|
||||||
+ list_entry(profile_list.next, struct aa_profile, list);
|
|
||||||
+
|
|
||||||
+ /* Remove the profile from each task context it is on. */
|
|
||||||
+ lock_profile(profile);
|
|
||||||
+ profile->isstale = 1;
|
|
||||||
+ aa_unconfine_tasks(profile);
|
|
||||||
+ unlock_profile(profile);
|
|
||||||
+
|
|
||||||
+ /* Release the profile itself. */
|
|
||||||
+ list_del_init(&profile->list);
|
|
||||||
+ aa_put_profile(profile);
|
|
||||||
+ }
|
|
||||||
+ write_unlock(&profile_list_lock);
|
|
||||||
+
|
+
|
||||||
+ /* FIXME: cleanup profiles references on files */
|
+ /* FIXME: cleanup profiles references on files */
|
||||||
+
|
+ free_default_namespace();
|
||||||
+ free_null_complain_profile();
|
|
||||||
+
|
+
|
||||||
+ /*
|
+ /*
|
||||||
+ * Delay for an rcu cycle to make sure that all active task
|
+ * Delay for an rcu cycle to make sure that all active task
|
||||||
|
@ -842,15 +884,11 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ destroy_apparmorfs();
|
+ destroy_apparmorfs();
|
||||||
+ mutex_unlock(&aa_interface_lock);
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
+
|
+
|
||||||
+ if (unregister_security(&apparmor_ops))
|
+ apparmor_initialized = 0;
|
||||||
+ info_message("Unable to properly unregister AppArmor");
|
|
||||||
+
|
+
|
||||||
+ info_message("AppArmor protection removed");
|
+ info_message("AppArmor protection removed");
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+module_init(apparmor_init);
|
|
||||||
+module_exit(apparmor_exit);
|
|
||||||
+
|
|
||||||
+MODULE_DESCRIPTION("AppArmor process confinement");
|
+MODULE_DESCRIPTION("AppArmor process confinement");
|
||||||
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
|
+MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");
|
||||||
+MODULE_LICENSE("GPL");
|
+MODULE_LICENSE("GPL");
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,21 +11,21 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
|
|
||||||
---
|
---
|
||||||
security/apparmor/Kconfig | 10 +
|
security/apparmor/Kconfig | 42 ++++
|
||||||
security/apparmor/Makefile | 13 ++
|
security/apparmor/Makefile | 13 +
|
||||||
security/apparmor/apparmor.h | 257 +++++++++++++++++++++++++++++++++++++++++
|
security/apparmor/apparmor.h | 358 +++++++++++++++++++++++++++++++++++++++++
|
||||||
security/apparmor/apparmorfs.c | 252 ++++++++++++++++++++++++++++++++++++++++
|
security/apparmor/apparmorfs.c | 280 ++++++++++++++++++++++++++++++++
|
||||||
security/apparmor/inline.h | 211 +++++++++++++++++++++++++++++++++
|
security/apparmor/inline.h | 250 ++++++++++++++++++++++++++++
|
||||||
security/apparmor/list.c | 94 ++++++++++++++
|
security/apparmor/list.c | 156 +++++++++++++++++
|
||||||
security/apparmor/locking.txt | 68 ++++++++++
|
security/apparmor/locking.txt | 68 +++++++
|
||||||
security/apparmor/procattr.c | 155 ++++++++++++++++++++++++
|
security/apparmor/procattr.c | 195 ++++++++++++++++++++++
|
||||||
8 files changed, 1060 insertions(+)
|
8 files changed, 1362 insertions(+)
|
||||||
|
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/Kconfig
|
+++ b/security/apparmor/Kconfig
|
||||||
@@ -0,0 +1,10 @@
|
@@ -0,0 +1,42 @@
|
||||||
+config SECURITY_APPARMOR
|
+config SECURITY_APPARMOR
|
||||||
+ tristate "AppArmor support"
|
+ bool "AppArmor support"
|
||||||
+ depends on SECURITY
|
+ depends on SECURITY
|
||||||
+ select AUDIT
|
+ select AUDIT
|
||||||
+ help
|
+ help
|
||||||
|
@ -33,6 +33,38 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ Required userspace tools (if they are not included in your
|
+ Required userspace tools (if they are not included in your
|
||||||
+ distribution) and further information may be found at
|
+ distribution) and further information may be found at
|
||||||
+ <http://forge.novell.com/modules/xfmod/project/?apparmor>
|
+ <http://forge.novell.com/modules/xfmod/project/?apparmor>
|
||||||
|
+
|
||||||
|
+ If you are unsure how to answer this question, answer N.
|
||||||
|
+
|
||||||
|
+config SECURITY_APPARMOR_BOOTPARAM_VALUE
|
||||||
|
+ int "AppArmor boot parameter default value"
|
||||||
|
+ depends on SECURITY_APPARMOR
|
||||||
|
+ range 0 1
|
||||||
|
+ default 1
|
||||||
|
+ help
|
||||||
|
+ This option sets the default value for the kernel parameter
|
||||||
|
+ 'apparmor', which allows AppArmor to be enabled or disabled
|
||||||
|
+ at boot. If this option is set to 0 (zero), the AppArmor
|
||||||
|
+ kernel parameter will default to 0, disabling AppArmor at
|
||||||
|
+ bootup. If this option is set to 1 (one), the AppArmor
|
||||||
|
+ kernel parameter will default to 1, enabling AppArmor at
|
||||||
|
+ bootup.
|
||||||
|
+
|
||||||
|
+ If you are unsure how to answer this question, answer 1.
|
||||||
|
+
|
||||||
|
+config SECURITY_APPARMOR_DISABLE
|
||||||
|
+ bool "AppArmor runtime disable"
|
||||||
|
+ depends on SECURITY_APPARMOR
|
||||||
|
+ default n
|
||||||
|
+ help
|
||||||
|
+ This option enables writing to a apparmorfs node 'disable', which
|
||||||
|
+ allows AppArmor to be disabled at runtime prior to the policy load.
|
||||||
|
+ AppArmor will then remain disabled until the next boot.
|
||||||
|
+ This option is similar to the apparmor.enabled=0 boot parameter,
|
||||||
|
+ but is to support runtime disabling of AppArmor, e.g. from
|
||||||
|
+ /sbin/init, for portability across platforms where boot
|
||||||
|
+ parameters are difficult to employ.
|
||||||
|
+
|
||||||
+ If you are unsure how to answer this question, answer N.
|
+ If you are unsure how to answer this question, answer N.
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/Makefile
|
+++ b/security/apparmor/Makefile
|
||||||
|
@ -52,7 +84,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ $(call cmd,make-caps)
|
+ $(call cmd,make-caps)
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/apparmor.h
|
+++ b/security/apparmor/apparmor.h
|
||||||
@@ -0,0 +1,257 @@
|
@@ -0,0 +1,358 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -79,26 +111,74 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#define AA_MAY_LINK 0x0010
|
+#define AA_MAY_LINK 0x0010
|
||||||
+#define AA_MAY_LOCK 0x0020
|
+#define AA_MAY_LOCK 0x0020
|
||||||
+#define AA_EXEC_MMAP 0x0040
|
+#define AA_EXEC_MMAP 0x0040
|
||||||
|
+#define AA_MAY_MOUNT 0x0080 /* no direct audit mapping */
|
||||||
|
+#define AA_EXEC_UNSAFE 0x0100
|
||||||
|
+#define AA_EXEC_MOD_0 0x0200
|
||||||
|
+#define AA_EXEC_MOD_1 0x0400
|
||||||
|
+#define AA_EXEC_MOD_2 0x0800
|
||||||
|
+#define AA_EXEC_MOD_3 0x1000
|
||||||
|
+#define AA_EXEC_MOD_4 0x2000
|
||||||
+
|
+
|
||||||
+#define AA_CHANGE_PROFILE 0x04000000
|
+#define AA_BASE_PERMS (MAY_READ | MAY_WRITE | MAY_EXEC | \
|
||||||
+#define AA_EXEC_INHERIT 0x08000000
|
|
||||||
+#define AA_EXEC_UNCONFINED 0x10000000
|
|
||||||
+#define AA_EXEC_PROFILE 0x20000000
|
|
||||||
+#define AA_EXEC_UNSAFE 0x40000000
|
|
||||||
+
|
|
||||||
+#define AA_EXEC_MODIFIERS (AA_EXEC_INHERIT | \
|
|
||||||
+ AA_EXEC_UNCONFINED | \
|
|
||||||
+ AA_EXEC_PROFILE)
|
|
||||||
+
|
|
||||||
+#define AA_VALID_PERM_MASK (MAY_READ | MAY_WRITE | MAY_EXEC | \
|
|
||||||
+ MAY_APPEND | AA_MAY_LINK | \
|
+ MAY_APPEND | AA_MAY_LINK | \
|
||||||
+ AA_MAY_LOCK | \
|
+ AA_MAY_LOCK | AA_EXEC_MMAP | \
|
||||||
+ AA_EXEC_MODIFIERS | AA_EXEC_MMAP | \
|
+ AA_MAY_MOUNT | AA_EXEC_UNSAFE | \
|
||||||
+ AA_EXEC_UNSAFE | AA_CHANGE_PROFILE)
|
+ AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
|
||||||
|
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
|
||||||
|
+ AA_EXEC_MOD_4)
|
||||||
|
+
|
||||||
|
+#define AA_EXEC_MODIFIERS (AA_EXEC_MOD_0 | AA_EXEC_MOD_1 | \
|
||||||
|
+ AA_EXEC_MOD_2 | AA_EXEC_MOD_3 | \
|
||||||
|
+ AA_EXEC_MOD_4)
|
||||||
|
+
|
||||||
|
+#define AA_EXEC_TYPE (AA_EXEC_UNSAFE | AA_EXEC_MODIFIERS)
|
||||||
|
+
|
||||||
|
+#define AA_EXEC_UNCONFINED AA_EXEC_MOD_0
|
||||||
|
+#define AA_EXEC_INHERIT AA_EXEC_MOD_1
|
||||||
|
+#define AA_EXEC_PROFILE (AA_EXEC_MOD_0 | AA_EXEC_MOD_1)
|
||||||
|
+#define AA_EXEC_PIX AA_EXEC_MOD_2
|
||||||
|
+
|
||||||
|
+#define AA_USER_SHIFT 0
|
||||||
|
+#define AA_OTHER_SHIFT 14
|
||||||
|
+
|
||||||
|
+#define AA_USER_PERMS (AA_BASE_PERMS << AA_USER_SHIFT)
|
||||||
|
+#define AA_OTHER_PERMS (AA_BASE_PERMS << AA_OTHER_SHIFT)
|
||||||
|
+
|
||||||
|
+#define AA_FILE_PERMS (AA_USER_PERMS | AA_OTHER_PERMS)
|
||||||
|
+
|
||||||
|
+#define AA_LINK_BITS ((AA_MAY_LINK << AA_USER_SHIFT) | \
|
||||||
|
+ (AA_MAY_LINK << AA_OTHER_SHIFT))
|
||||||
|
+
|
||||||
|
+#define AA_USER_EXEC (MAY_EXEC << AA_USER_SHIFT)
|
||||||
|
+#define AA_OTHER_EXEC (MAY_EXEC << AA_OTHER_SHIFT)
|
||||||
|
+
|
||||||
|
+#define AA_USER_EXEC_TYPE (AA_EXEC_TYPE << AA_USER_SHIFT)
|
||||||
|
+#define AA_OTHER_EXEC_TYPE (AA_EXEC_TYPE << AA_OTHER_SHIFT)
|
||||||
|
+
|
||||||
|
+#define AA_EXEC_BITS (AA_USER_EXEC | AA_OTHER_EXEC)
|
||||||
|
+
|
||||||
|
+#define ALL_AA_EXEC_TYPE (AA_USER_EXEC_TYPE | AA_OTHER_EXEC_TYPE)
|
||||||
|
+
|
||||||
|
+/* overloaded permissions for link pairs */
|
||||||
|
+#define AA_LINK_SUBSET_TEST 0x0020
|
||||||
|
+
|
||||||
|
+/* shared permissions that are not duplicated in user::other */
|
||||||
|
+#define AA_AUDIT_FIELD 0x10000000
|
||||||
|
+#define AA_CHANGE_HAT 0x20000000
|
||||||
|
+#define AA_CHANGE_PROFILE 0x40000000
|
||||||
|
+
|
||||||
|
+#define AA_SHARED_PERMS (AA_CHANGE_HAT | AA_CHANGE_PROFILE | \
|
||||||
|
+ AA_AUDIT_FIELD)
|
||||||
|
+
|
||||||
|
+#define AA_VALID_PERM_MASK (AA_FILE_PERMS | AA_SHARED_PERMS)
|
||||||
|
+
|
||||||
|
+/* audit bits for the second accept field */
|
||||||
|
+#define AUDIT_FILE_MASK 0x1fc07f
|
||||||
|
+#define AUDIT_QUIET_MASK(mask) ((mask >> 7) & AUDIT_FILE_MASK)
|
||||||
|
+#define AA_VALID_PERM2_MASK 0x0fffffff
|
||||||
+
|
+
|
||||||
+#define AA_SECURE_EXEC_NEEDED 1
|
+#define AA_SECURE_EXEC_NEEDED 1
|
||||||
+
|
+
|
||||||
+
|
|
||||||
+/* Control parameters (0 or 1), settable thru module/boot flags or
|
+/* Control parameters (0 or 1), settable thru module/boot flags or
|
||||||
+ * via /sys/kernel/security/apparmor/control */
|
+ * via /sys/kernel/security/apparmor/control */
|
||||||
+extern int apparmor_complain;
|
+extern int apparmor_complain;
|
||||||
|
@ -134,18 +214,49 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
|
+#define AA_ERROR(fmt, args...) printk(KERN_ERR "AppArmor: " fmt, ##args)
|
||||||
+
|
+
|
||||||
|
+struct aa_profile;
|
||||||
|
+
|
||||||
|
+/* struct aa_namespace - namespace for a set of profiles
|
||||||
|
+ * @name: the name of the namespace
|
||||||
|
+ * @list: list the namespace is on
|
||||||
|
+ * @profiles: list of profile in the namespace
|
||||||
|
+ * @profile_count: the number of profiles in the namespace
|
||||||
|
+ * @null_complain_profile: special profile used for learning in this namespace
|
||||||
|
+ * @count: reference count on the namespace
|
||||||
|
+ * @lock: lock for adding/removing profile to the namespace
|
||||||
|
+ */
|
||||||
|
+struct aa_namespace {
|
||||||
|
+ char *name;
|
||||||
|
+ struct list_head list;
|
||||||
|
+ struct list_head profiles;
|
||||||
|
+ int profile_count;
|
||||||
|
+ struct aa_profile *null_complain_profile;
|
||||||
|
+
|
||||||
|
+ struct kref count;
|
||||||
|
+ rwlock_t lock;
|
||||||
|
+};
|
||||||
|
+
|
||||||
+/* struct aa_profile - basic confinement data
|
+/* struct aa_profile - basic confinement data
|
||||||
+ * @name: the profiles name
|
+ * @name: the profiles name
|
||||||
+ * @file_rules: dfa containing the profiles file rules
|
|
||||||
+ * @list: list this profile is on
|
+ * @list: list this profile is on
|
||||||
|
+ * @ns: namespace the profile is in
|
||||||
|
+ * @file_rules: dfa containing the profiles file rules
|
||||||
+ * @flags: flags controlling profile behavior
|
+ * @flags: flags controlling profile behavior
|
||||||
+ * @isstale: flag indicating if profile is stale
|
+ * @isstale: flag indicating if profile is stale
|
||||||
|
+ * @set_caps: capabilities that are being set
|
||||||
|
+ * @capabilities: capabilities mask
|
||||||
|
+ * @audit_caps: caps that are to be audited
|
||||||
|
+ * @quiet_caps: caps that should not be audited
|
||||||
+ * @capabilities: capabilities granted by the process
|
+ * @capabilities: capabilities granted by the process
|
||||||
+ * @count: reference count of the profile
|
+ * @count: reference count of the profile
|
||||||
|
+ * @task_contexts: list of tasks confined by profile
|
||||||
|
+ * @lock: lock for the task_contexts list
|
||||||
|
+ * @network_families: basic network permissions
|
||||||
|
+ * @audit_network: which network permissions to force audit
|
||||||
|
+ * @quiet_network: which network permissions to quiet rejects
|
||||||
+ *
|
+ *
|
||||||
+ * The AppArmor profile contains the basic confinement data. Each profile
|
+ * The AppArmor profile contains the basic confinement data. Each profile
|
||||||
+ * has a name and potentially a list of sub profile entries. All non stale
|
+ * has a name, and all nonstale profile are in a profile namespace.
|
||||||
+ * profiles are on the profile_list.
|
|
||||||
+ *
|
+ *
|
||||||
+ * The task_contexts list and the isstale flag are protected by the
|
+ * The task_contexts list and the isstale flag are protected by the
|
||||||
+ * profile lock.
|
+ * profile lock.
|
||||||
|
@ -156,23 +267,29 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ */
|
+ */
|
||||||
+struct aa_profile {
|
+struct aa_profile {
|
||||||
+ char *name;
|
+ char *name;
|
||||||
+ struct aa_dfa *file_rules;
|
|
||||||
+ struct list_head list;
|
+ struct list_head list;
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
|
+
|
||||||
|
+ struct aa_dfa *file_rules;
|
||||||
+ struct {
|
+ struct {
|
||||||
+ int complain;
|
+ int complain;
|
||||||
+ int audit;
|
+ int audit;
|
||||||
+ } flags;
|
+ } flags;
|
||||||
+ int isstale;
|
+ int isstale;
|
||||||
+
|
+
|
||||||
|
+ kernel_cap_t set_caps;
|
||||||
+ kernel_cap_t capabilities;
|
+ kernel_cap_t capabilities;
|
||||||
|
+ kernel_cap_t audit_caps;
|
||||||
|
+ kernel_cap_t quiet_caps;
|
||||||
|
+
|
||||||
+ struct kref count;
|
+ struct kref count;
|
||||||
+ struct list_head task_contexts;
|
+ struct list_head task_contexts;
|
||||||
+ spinlock_t lock;
|
+ spinlock_t lock;
|
||||||
+ unsigned long int_flags;
|
+ unsigned long int_flags;
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+extern struct list_head profile_list;
|
+extern struct list_head profile_ns_list;
|
||||||
+extern rwlock_t profile_list_lock;
|
+extern rwlock_t profile_ns_list_lock;
|
||||||
+extern struct mutex aa_interface_lock;
|
+extern struct mutex aa_interface_lock;
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
|
@ -198,7 +315,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ kernel_cap_t caps_logged;
|
+ kernel_cap_t caps_logged;
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+extern struct aa_profile *null_complain_profile;
|
+extern struct aa_namespace *default_namespace;
|
||||||
+
|
+
|
||||||
+/* aa_audit - AppArmor auditing structure
|
+/* aa_audit - AppArmor auditing structure
|
||||||
+ * Structure is populated by access control code and passed to aa_audit which
|
+ * Structure is populated by access control code and passed to aa_audit which
|
||||||
|
@ -211,7 +328,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ const char *info;
|
+ const char *info;
|
||||||
+ const char *name;
|
+ const char *name;
|
||||||
+ const char *name2;
|
+ const char *name2;
|
||||||
+ int requested_mask, denied_mask;
|
+ const char *name3;
|
||||||
|
+ int request_mask, denied_mask, audit_mask;
|
||||||
+ struct iattr *iattr;
|
+ struct iattr *iattr;
|
||||||
+ pid_t task, parent;
|
+ pid_t task, parent;
|
||||||
+ int error_code;
|
+ int error_code;
|
||||||
|
@ -229,9 +347,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+/* main.c */
|
+/* main.c */
|
||||||
+extern int alloc_null_complain_profile(void);
|
+extern int alloc_default_namespace(void);
|
||||||
+extern void free_null_complain_profile(void);
|
+extern void free_default_namespace(void);
|
||||||
+extern int attach_nullprofile(struct aa_profile *profile);
|
|
||||||
+extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa,
|
+extern int aa_audit_message(struct aa_profile *profile, struct aa_audit *sa,
|
||||||
+ int type);
|
+ int type);
|
||||||
+void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa);
|
+void aa_audit_hint(struct aa_profile *profile, struct aa_audit *sa);
|
||||||
|
@ -254,7 +371,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ struct dentry *dentry, struct vfsmount *mnt,
|
+ struct dentry *dentry, struct vfsmount *mnt,
|
||||||
+ int mask);
|
+ int mask);
|
||||||
+extern int aa_perm_path(struct aa_profile *, const char *operation,
|
+extern int aa_perm_path(struct aa_profile *, const char *operation,
|
||||||
+ const char *name, int);
|
+ const char *name, int mask, uid_t uid);
|
||||||
+extern int aa_link(struct aa_profile *profile,
|
+extern int aa_link(struct aa_profile *profile,
|
||||||
+ struct dentry *link, struct vfsmount *link_mnt,
|
+ struct dentry *link, struct vfsmount *link_mnt,
|
||||||
+ struct dentry *target, struct vfsmount *target_mnt);
|
+ struct dentry *target, struct vfsmount *target_mnt);
|
||||||
|
@ -262,9 +379,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+extern int aa_register(struct linux_binprm *bprm);
|
+extern int aa_register(struct linux_binprm *bprm);
|
||||||
+extern void aa_release(struct task_struct *task);
|
+extern void aa_release(struct task_struct *task);
|
||||||
+extern int aa_change_hat(const char *id, u64 hat_magic);
|
+extern int aa_change_hat(const char *id, u64 hat_magic);
|
||||||
+extern int aa_change_profile(const char *name, u64 cookie);
|
+extern int aa_change_profile(const char *ns_name, const char *name);
|
||||||
+extern struct aa_profile *__aa_find_profile(const char *name,
|
|
||||||
+ struct list_head *list);
|
|
||||||
+extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
|
+extern struct aa_profile *__aa_replace_profile(struct task_struct *task,
|
||||||
+ struct aa_profile *profile);
|
+ struct aa_profile *profile);
|
||||||
+extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
|
+extern struct aa_task_context *lock_task_and_profiles(struct task_struct *task,
|
||||||
|
@ -279,13 +394,25 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+extern int aa_may_ptrace(struct aa_task_context *cxt,
|
+extern int aa_may_ptrace(struct aa_task_context *cxt,
|
||||||
+ struct aa_profile *tracee);
|
+ struct aa_profile *tracee);
|
||||||
+
|
+
|
||||||
|
+/* lsm.c */
|
||||||
|
+extern int apparmor_initialized;
|
||||||
|
+extern void info_message(const char *str);
|
||||||
|
+extern void apparmor_disable(void);
|
||||||
|
+
|
||||||
+/* list.c */
|
+/* list.c */
|
||||||
+extern void aa_profilelist_release(void);
|
+extern struct aa_namespace *__aa_find_namespace(const char *name,
|
||||||
|
+ struct list_head *list);
|
||||||
|
+extern struct aa_profile *__aa_find_profile(const char *name,
|
||||||
|
+ struct list_head *list);
|
||||||
|
+extern void aa_profile_ns_list_release(void);
|
||||||
+
|
+
|
||||||
+/* module_interface.c */
|
+/* module_interface.c */
|
||||||
+extern ssize_t aa_add_profile(void *, size_t);
|
+extern ssize_t aa_add_profile(void *, size_t);
|
||||||
+extern ssize_t aa_replace_profile(void *, size_t);
|
+extern ssize_t aa_replace_profile(void *, size_t);
|
||||||
+extern ssize_t aa_remove_profile(const char *, size_t);
|
+extern ssize_t aa_remove_profile(char *, size_t);
|
||||||
|
+extern struct aa_namespace *alloc_aa_namespace(char *name);
|
||||||
|
+extern void free_aa_namespace(struct aa_namespace *ns);
|
||||||
|
+extern void free_aa_namespace_kref(struct kref *kref);
|
||||||
+extern struct aa_profile *alloc_aa_profile(void);
|
+extern struct aa_profile *alloc_aa_profile(void);
|
||||||
+extern void free_aa_profile(struct aa_profile *profile);
|
+extern void free_aa_profile(struct aa_profile *profile);
|
||||||
+extern void free_aa_profile_kref(struct kref *kref);
|
+extern void free_aa_profile_kref(struct kref *kref);
|
||||||
|
@ -307,12 +434,18 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+extern void aa_match_free(struct aa_dfa *dfa);
|
+extern void aa_match_free(struct aa_dfa *dfa);
|
||||||
+extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
|
+extern int unpack_dfa(struct aa_dfa *dfa, void *blob, size_t size);
|
||||||
+extern int verify_dfa(struct aa_dfa *dfa);
|
+extern int verify_dfa(struct aa_dfa *dfa);
|
||||||
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str);
|
+extern unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *);
|
||||||
|
+extern unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
|
||||||
|
+ const char *str);
|
||||||
|
+extern unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
|
||||||
|
+ const char *str, unsigned int *final);
|
||||||
|
+extern unsigned int aa_dfa_null_transition(struct aa_dfa *dfa,
|
||||||
|
+ unsigned int start);
|
||||||
+
|
+
|
||||||
+#endif /* __APPARMOR_H */
|
+#endif /* __APPARMOR_H */
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/apparmorfs.c
|
+++ b/security/apparmor/apparmorfs.c
|
||||||
@@ -0,0 +1,252 @@
|
@@ -0,0 +1,280 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -404,7 +537,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
|
+static ssize_t aa_matching_read(struct file *file, char __user *buf,
|
||||||
+ size_t size, loff_t *ppos)
|
+ size_t size, loff_t *ppos)
|
||||||
+{
|
+{
|
||||||
+ const char *matching = "pattern=aadfa perms=rwxamlz";
|
+ const char *matching = "pattern=aadfa audit perms=rwxamlk/ user::other";
|
||||||
+
|
+
|
||||||
+ return simple_read_from_buffer(buf, size, ppos, matching,
|
+ return simple_read_from_buffer(buf, size, ppos, matching,
|
||||||
+ strlen(matching));
|
+ strlen(matching));
|
||||||
|
@ -414,6 +547,22 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ .read = aa_matching_read,
|
+ .read = aa_matching_read,
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
|
+/* apparmor/features */
|
||||||
|
+static ssize_t aa_features_read(struct file *file, char __user *buf,
|
||||||
|
+ size_t size, loff_t *ppos)
|
||||||
|
+{
|
||||||
|
+ const char *features = "file=3.0 capability=2.0 network=1.0 "
|
||||||
|
+ "change_hat=1.4 change_profile=1.0 "
|
||||||
|
+ "aanamespaces=1.0";
|
||||||
|
+
|
||||||
|
+ return simple_read_from_buffer(buf, size, ppos, features,
|
||||||
|
+ strlen(features));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static struct file_operations apparmorfs_features_fops = {
|
||||||
|
+ .read = aa_features_read,
|
||||||
|
+};
|
||||||
|
+
|
||||||
+/* apparmor/.load */
|
+/* apparmor/.load */
|
||||||
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
|
+static ssize_t aa_profile_load(struct file *f, const char __user *buf,
|
||||||
+ size_t size, loff_t *pos)
|
+ size_t size, loff_t *pos)
|
||||||
|
@ -519,6 +668,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ aafs_remove(".replace");
|
+ aafs_remove(".replace");
|
||||||
+ aafs_remove(".load");
|
+ aafs_remove(".load");
|
||||||
+ aafs_remove("matching");
|
+ aafs_remove("matching");
|
||||||
|
+ aafs_remove("features");
|
||||||
+ aafs_remove("profiles");
|
+ aafs_remove("profiles");
|
||||||
+ securityfs_remove(apparmor_dentry);
|
+ securityfs_remove(apparmor_dentry);
|
||||||
+ apparmor_dentry = NULL;
|
+ apparmor_dentry = NULL;
|
||||||
|
@ -529,6 +679,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+{
|
+{
|
||||||
+ int error;
|
+ int error;
|
||||||
+
|
+
|
||||||
|
+ if (!apparmor_initialized)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
+ if (apparmor_dentry) {
|
+ if (apparmor_dentry) {
|
||||||
+ AA_ERROR("%s: AppArmor securityfs already exists\n",
|
+ AA_ERROR("%s: AppArmor securityfs already exists\n",
|
||||||
+ __FUNCTION__);
|
+ __FUNCTION__);
|
||||||
|
@ -547,6 +700,9 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ error = aafs_create("matching", 0444, &apparmorfs_matching_fops);
|
+ error = aafs_create("matching", 0444, &apparmorfs_matching_fops);
|
||||||
+ if (error)
|
+ if (error)
|
||||||
+ goto error;
|
+ goto error;
|
||||||
|
+ error = aafs_create("features", 0444, &apparmorfs_features_fops);
|
||||||
|
+ if (error)
|
||||||
|
+ goto error;
|
||||||
+ error = aafs_create(".load", 0640, &apparmorfs_profile_load);
|
+ error = aafs_create(".load", 0640, &apparmorfs_profile_load);
|
||||||
+ if (error)
|
+ if (error)
|
||||||
+ goto error;
|
+ goto error;
|
||||||
|
@ -557,17 +713,22 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ if (error)
|
+ if (error)
|
||||||
+ goto error;
|
+ goto error;
|
||||||
+
|
+
|
||||||
|
+ /* Report that AppArmor fs is enabled */
|
||||||
|
+ info_message("AppArmor Filesystem Enabled");
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+
|
+
|
||||||
+error:
|
+error:
|
||||||
+ destroy_apparmorfs();
|
+ destroy_apparmorfs();
|
||||||
+ AA_ERROR("Error creating AppArmor securityfs\n");
|
+ AA_ERROR("Error creating AppArmor securityfs\n");
|
||||||
|
+ apparmor_disable();
|
||||||
+ return error;
|
+ return error;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
+fs_initcall(create_apparmorfs);
|
||||||
|
+
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/inline.h
|
+++ b/security/apparmor/inline.h
|
||||||
@@ -0,0 +1,211 @@
|
@@ -0,0 +1,250 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -582,6 +743,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+#include <linux/sched.h>
|
+#include <linux/sched.h>
|
||||||
+
|
+
|
||||||
|
+#include "match.h"
|
||||||
|
+
|
||||||
+static inline int mediated_filesystem(struct inode *inode)
|
+static inline int mediated_filesystem(struct inode *inode)
|
||||||
+{
|
+{
|
||||||
+ return !(inode->i_sb->s_flags & MS_NOUSER);
|
+ return !(inode->i_sb->s_flags & MS_NOUSER);
|
||||||
|
@ -589,7 +752,33 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+static inline struct aa_task_context *aa_task_context(struct task_struct *task)
|
+static inline struct aa_task_context *aa_task_context(struct task_struct *task)
|
||||||
+{
|
+{
|
||||||
+ return rcu_dereference((struct aa_task_context *)task->security);
|
+ return (struct aa_task_context *) rcu_dereference(task->security);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline struct aa_namespace *aa_get_namespace(struct aa_namespace *ns)
|
||||||
|
+{
|
||||||
|
+ if (ns)
|
||||||
|
+ kref_get(&(ns->count));
|
||||||
|
+
|
||||||
|
+ return ns;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void aa_put_namespace(struct aa_namespace *ns)
|
||||||
|
+{
|
||||||
|
+ if (ns)
|
||||||
|
+ kref_put(&ns->count, free_aa_namespace_kref);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+static inline struct aa_namespace *aa_find_namespace(const char *name)
|
||||||
|
+{
|
||||||
|
+ struct aa_namespace *ns = NULL;
|
||||||
|
+
|
||||||
|
+ read_lock(&profile_ns_list_lock);
|
||||||
|
+ ns = aa_get_namespace(__aa_find_namespace(name, &profile_ns_list));
|
||||||
|
+ read_unlock(&profile_ns_list_lock);
|
||||||
|
+
|
||||||
|
+ return ns;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
|
@ -630,13 +819,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return profile;
|
+ return profile;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static inline struct aa_profile *aa_find_profile(const char *name)
|
+static inline struct aa_profile *aa_find_profile(struct aa_namespace *ns,
|
||||||
|
+ const char *name)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *profile = NULL;
|
+ struct aa_profile *profile = NULL;
|
||||||
+
|
+
|
||||||
+ read_lock(&profile_list_lock);
|
+ read_lock(&ns->lock);
|
||||||
+ profile = aa_dup_profile(__aa_find_profile(name, &profile_list));
|
+ profile = aa_dup_profile(__aa_find_profile(name, &ns->profiles));
|
||||||
+ read_unlock(&profile_list_lock);
|
+ read_unlock(&ns->lock);
|
||||||
+
|
+
|
||||||
+ return profile;
|
+ return profile;
|
||||||
+}
|
+}
|
||||||
|
@ -773,15 +963,25 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ }
|
+ }
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname)
|
+static inline unsigned int aa_match(struct aa_dfa *dfa, const char *pathname,
|
||||||
|
+ int *audit_mask)
|
||||||
+{
|
+{
|
||||||
+ return dfa ? aa_dfa_match(dfa, pathname) : 0;
|
+ if (dfa)
|
||||||
|
+ return aa_dfa_match(dfa, pathname, audit_mask);
|
||||||
|
+ if (audit_mask)
|
||||||
|
+ *audit_mask = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline int dfa_audit_mask(struct aa_dfa *dfa, unsigned int state)
|
||||||
|
+{
|
||||||
|
+ return ACCEPT_TABLE2(dfa)[state];
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+#endif /* __INLINE_H__ */
|
+#endif /* __INLINE_H__ */
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/list.c
|
+++ b/security/apparmor/list.c
|
||||||
@@ -0,0 +1,94 @@
|
@@ -0,0 +1,156 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -797,9 +997,30 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#include "apparmor.h"
|
+#include "apparmor.h"
|
||||||
+#include "inline.h"
|
+#include "inline.h"
|
||||||
+
|
+
|
||||||
+/* list of all profiles and lock */
|
+/* list of profile namespaces and lock */
|
||||||
+LIST_HEAD(profile_list);
|
+LIST_HEAD(profile_ns_list);
|
||||||
+rwlock_t profile_list_lock = RW_LOCK_UNLOCKED;
|
+rwlock_t profile_ns_list_lock = RW_LOCK_UNLOCKED;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * __aa_find_namespace - look up a profile namespace on the namespace list
|
||||||
|
+ * @name: name of namespace to find
|
||||||
|
+ * @head: list to search
|
||||||
|
+ *
|
||||||
|
+ * Returns a pointer to the namespace on the list, or NULL if no namespace
|
||||||
|
+ * called @name exists. The caller must hold the profile_ns_list_lock.
|
||||||
|
+ */
|
||||||
|
+struct aa_namespace *__aa_find_namespace(const char *name,
|
||||||
|
+ struct list_head *head)
|
||||||
|
+{
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
|
+
|
||||||
|
+ list_for_each_entry(ns, head, list) {
|
||||||
|
+ if (!strcmp(ns->name, name))
|
||||||
|
+ return ns;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
+ * __aa_find_profile - look up a profile on the profile list
|
+ * __aa_find_profile - look up a profile on the profile list
|
||||||
|
@ -821,51 +1042,92 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return NULL;
|
+ return NULL;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
+static void aa_profile_list_release(struct list_head *head)
|
||||||
|
+{
|
||||||
|
+ struct aa_profile *profile, *tmp;
|
||||||
|
+ list_for_each_entry_safe(profile, tmp, head, list) {
|
||||||
|
+ /* Remove the profile from each task context it is on. */
|
||||||
|
+ lock_profile(profile);
|
||||||
|
+ profile->isstale = 1;
|
||||||
|
+ aa_unconfine_tasks(profile);
|
||||||
|
+ list_del_init(&profile->list);
|
||||||
|
+ unlock_profile(profile);
|
||||||
|
+ aa_put_profile(profile);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
+/**
|
+/**
|
||||||
+ * aa_profilelist_release - Remove all profiles from profile_list
|
+ * aa_profilelist_release - Remove all profiles from profile_list
|
||||||
+ */
|
+ */
|
||||||
+void aa_profilelist_release(void)
|
+void aa_profile_ns_list_release(void)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *p, *tmp;
|
+ struct aa_namespace *ns, *tmp;
|
||||||
+
|
+
|
||||||
+ write_lock(&profile_list_lock);
|
+ /* Remove and release all the profiles on namespace profile lists. */
|
||||||
+ list_for_each_entry_safe(p, tmp, &profile_list, list) {
|
+ write_lock(&profile_ns_list_lock);
|
||||||
+ list_del_init(&p->list);
|
+ list_for_each_entry_safe(ns, tmp, &profile_ns_list, list) {
|
||||||
+ aa_put_profile(p);
|
+ write_lock(&ns->lock);
|
||||||
|
+ aa_profile_list_release(&ns->profiles);
|
||||||
|
+ list_del_init(&ns->list);
|
||||||
|
+ write_unlock(&ns->lock);
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
+ }
|
+ }
|
||||||
+ write_unlock(&profile_list_lock);
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static void *p_start(struct seq_file *f, loff_t *pos)
|
+static void *p_start(struct seq_file *f, loff_t *pos)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *node;
|
+ struct aa_namespace *ns;
|
||||||
|
+ struct aa_profile *profile;
|
||||||
+ loff_t l = *pos;
|
+ loff_t l = *pos;
|
||||||
+
|
+ read_lock(&profile_ns_list_lock);
|
||||||
+ read_lock(&profile_list_lock);
|
+ if (l--)
|
||||||
+ list_for_each_entry(node, &profile_list, list)
|
+ return NULL;
|
||||||
+ if (!l--)
|
+ list_for_each_entry(ns, &profile_ns_list, list) {
|
||||||
+ return node;
|
+ read_lock(&ns->lock);
|
||||||
|
+ list_for_each_entry(profile, &ns->profiles, list)
|
||||||
|
+ return profile;
|
||||||
|
+ read_unlock(&ns->lock);
|
||||||
|
+ }
|
||||||
+ return NULL;
|
+ return NULL;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
|
+static void *p_next(struct seq_file *f, void *p, loff_t *pos)
|
||||||
+{
|
+{
|
||||||
+ struct list_head *lh = ((struct aa_profile *)p)->list.next;
|
+ struct aa_profile *profile = (struct aa_profile *) p;
|
||||||
|
+ struct list_head *lh = profile->list.next;
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
+ (*pos)++;
|
+ (*pos)++;
|
||||||
+ return lh == &profile_list ?
|
+ if (lh != &profile->ns->profiles)
|
||||||
+ NULL : list_entry(lh, struct aa_profile, list);
|
+ return list_entry(lh, struct aa_profile, list);
|
||||||
|
+
|
||||||
|
+ lh = profile->ns->list.next;
|
||||||
|
+ read_unlock(&profile->ns->lock);
|
||||||
|
+ while (lh != &profile_ns_list) {
|
||||||
|
+ ns = list_entry(lh, struct aa_namespace, list);
|
||||||
|
+ read_lock(&ns->lock);
|
||||||
|
+ list_for_each_entry(profile, &ns->profiles, list)
|
||||||
|
+ return profile;
|
||||||
|
+ read_unlock(&ns->lock);
|
||||||
|
+ lh = ns->list.next;
|
||||||
|
+ }
|
||||||
|
+ return NULL;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static void p_stop(struct seq_file *f, void *v)
|
+static void p_stop(struct seq_file *f, void *v)
|
||||||
+{
|
+{
|
||||||
+ read_unlock(&profile_list_lock);
|
+ read_unlock(&profile_ns_list_lock);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+static int seq_show_profile(struct seq_file *f, void *v)
|
+static int seq_show_profile(struct seq_file *f, void *v)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *profile = (struct aa_profile *)v;
|
+ struct aa_profile *profile = (struct aa_profile *)v;
|
||||||
|
+ if (profile->ns == default_namespace)
|
||||||
+ seq_printf(f, "%s (%s)\n", profile->name,
|
+ seq_printf(f, "%s (%s)\n", profile->name,
|
||||||
+ PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
|
+ PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
|
||||||
|
+ else
|
||||||
|
+ seq_printf(f, ":%s:%s (%s)\n", profile->ns->name, profile->name,
|
||||||
|
+ PROFILE_COMPLAIN(profile) ? "complain" : "enforce");
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -949,7 +1211,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+the task would not be out of its quiescent period.
|
+the task would not be out of its quiescent period.
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/procattr.c
|
+++ b/security/apparmor/procattr.c
|
||||||
@@ -0,0 +1,155 @@
|
@@ -0,0 +1,195 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -971,15 +1233,23 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ if (profile) {
|
+ if (profile) {
|
||||||
+ const char *mode_str = PROFILE_COMPLAIN(profile) ?
|
+ const char *mode_str = PROFILE_COMPLAIN(profile) ?
|
||||||
+ " (complain)" : " (enforce)";
|
+ " (complain)" : " (enforce)";
|
||||||
+ int mode_len, name_len;
|
+ int mode_len, name_len, ns_len = 0;
|
||||||
+
|
+
|
||||||
+ mode_len = strlen(mode_str);
|
+ mode_len = strlen(mode_str);
|
||||||
+ name_len = strlen(profile->name);
|
+ name_len = strlen(profile->name);
|
||||||
+ *len = mode_len + name_len + 1;
|
+ if (profile->ns != default_namespace)
|
||||||
|
+ ns_len = strlen(profile->ns->name) + 2;
|
||||||
|
+ *len = mode_len + ns_len + name_len + 1;
|
||||||
+ str = kmalloc(*len, GFP_ATOMIC);
|
+ str = kmalloc(*len, GFP_ATOMIC);
|
||||||
+ if (!str)
|
+ if (!str)
|
||||||
+ return -ENOMEM;
|
+ return -ENOMEM;
|
||||||
+
|
+
|
||||||
|
+ if (ns_len) {
|
||||||
|
+ *str++ = ':';
|
||||||
|
+ memcpy(str, profile->ns->name, ns_len - 2);
|
||||||
|
+ str += ns_len - 2;
|
||||||
|
+ *str++ = ':';
|
||||||
|
+ }
|
||||||
+ memcpy(str, profile->name, name_len);
|
+ memcpy(str, profile->name, name_len);
|
||||||
+ str += name_len;
|
+ str += name_len;
|
||||||
+ memcpy(str, mode_str, mode_len);
|
+ memcpy(str, mode_str, mode_len);
|
||||||
|
@ -1039,20 +1309,26 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+int aa_setprocattr_changeprofile(char *args)
|
+int aa_setprocattr_changeprofile(char *args)
|
||||||
+{
|
+{
|
||||||
+ char *name;
|
+ char *name = args, *ns_name = NULL;
|
||||||
+ u64 cookie;
|
|
||||||
+
|
+
|
||||||
+ name = split_token_from_name("change_profile", args, &cookie);
|
+ if (name[0] == ':') {
|
||||||
+ if (IS_ERR(name))
|
+ char *split = strchr(&name[1], ':');
|
||||||
+ return PTR_ERR(name);
|
+ if (split) {
|
||||||
|
+ *split = 0;
|
||||||
|
+ ns_name = &name[1];
|
||||||
|
+ name = split + 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
+
|
+
|
||||||
+ return aa_change_profile(name, cookie);
|
+ return aa_change_profile(ns_name, name);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+int aa_setprocattr_setprofile(struct task_struct *task, char *args)
|
+int aa_setprocattr_setprofile(struct task_struct *task, char *args)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *old_profile, *new_profile;
|
+ struct aa_profile *old_profile, *new_profile;
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
+ struct aa_audit sa;
|
+ struct aa_audit sa;
|
||||||
|
+ char *name, *ns_name = NULL;
|
||||||
+
|
+
|
||||||
+ memset(&sa, 0, sizeof(sa));
|
+ memset(&sa, 0, sizeof(sa));
|
||||||
+ sa.operation = "profile_set";
|
+ sa.operation = "profile_set";
|
||||||
|
@ -1062,15 +1338,38 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ AA_DEBUG("%s: current %d\n",
|
+ AA_DEBUG("%s: current %d\n",
|
||||||
+ __FUNCTION__, current->pid);
|
+ __FUNCTION__, current->pid);
|
||||||
+
|
+
|
||||||
|
+ name = args;
|
||||||
|
+ if (args[0] != '/') {
|
||||||
|
+ char *split = strchr(args, ':');
|
||||||
|
+ if (split) {
|
||||||
|
+ *split = 0;
|
||||||
|
+ ns_name = args;
|
||||||
|
+ name = split + 1;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (ns_name)
|
||||||
|
+ ns = aa_find_namespace(ns_name);
|
||||||
|
+ else
|
||||||
|
+ ns = aa_get_namespace(default_namespace);
|
||||||
|
+ if (!ns) {
|
||||||
|
+ sa.name = ns_name;
|
||||||
|
+ sa.info = "unknown namespace";
|
||||||
|
+ aa_audit_reject(NULL, &sa);
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
|
+ return -EINVAL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+repeat:
|
+repeat:
|
||||||
+ if (strcmp(args, "unconfined") == 0)
|
+ if (strcmp(name, "unconfined") == 0)
|
||||||
+ new_profile = NULL;
|
+ new_profile = NULL;
|
||||||
+ else {
|
+ else {
|
||||||
+ new_profile = aa_find_profile(args);
|
+ new_profile = aa_find_profile(ns, name);
|
||||||
+ if (!new_profile) {
|
+ if (!new_profile) {
|
||||||
+ sa.name = args;
|
+ sa.name = ns_name;
|
||||||
|
+ sa.name2 = name;
|
||||||
+ sa.info = "unknown profile";
|
+ sa.info = "unknown profile";
|
||||||
+ aa_audit_reject(NULL, &sa);
|
+ aa_audit_reject(NULL, &sa);
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
+ return -EINVAL;
|
+ return -EINVAL;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
@ -1083,12 +1382,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ error = PTR_ERR(old_profile);
|
+ error = PTR_ERR(old_profile);
|
||||||
+ if (error == -ESTALE)
|
+ if (error == -ESTALE)
|
||||||
+ goto repeat;
|
+ goto repeat;
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
+ return error;
|
+ return error;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (new_profile) {
|
+ if (new_profile) {
|
||||||
+ sa.name = args;
|
+ sa.name = ns_name;
|
||||||
+ sa.name2 = old_profile ? old_profile->name :
|
+ sa.name2 = name;
|
||||||
|
+ sa.name3 = old_profile ? old_profile->name :
|
||||||
+ "unconfined";
|
+ "unconfined";
|
||||||
+ aa_audit_status(NULL, &sa);
|
+ aa_audit_status(NULL, &sa);
|
||||||
+ } else {
|
+ } else {
|
||||||
|
@ -1101,6 +1402,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ aa_audit_status(NULL, &sa);
|
+ aa_audit_status(NULL, &sa);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
+ aa_put_profile(old_profile);
|
+ aa_put_profile(old_profile);
|
||||||
+ aa_put_profile(new_profile);
|
+ aa_put_profile(new_profile);
|
||||||
+ return 0;
|
+ return 0;
|
||||||
|
|
|
@ -8,14 +8,14 @@ Signed-off-by: John Johansen <jjohansen@suse.de>
|
||||||
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
|
|
||||||
---
|
---
|
||||||
security/apparmor/match.c | 248 +++++++++++++
|
security/apparmor/match.c | 364 +++++++++++++++
|
||||||
security/apparmor/match.h | 83 ++++
|
security/apparmor/match.h | 87 +++
|
||||||
security/apparmor/module_interface.c | 623 +++++++++++++++++++++++++++++++++++
|
security/apparmor/module_interface.c | 815 +++++++++++++++++++++++++++++++++++
|
||||||
3 files changed, 954 insertions(+)
|
3 files changed, 1266 insertions(+)
|
||||||
|
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/match.c
|
+++ b/security/apparmor/match.c
|
||||||
@@ -0,0 +1,248 @@
|
@@ -0,0 +1,364 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 2007 Novell/SUSE
|
+ * Copyright (C) 2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -32,6 +32,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#include <linux/errno.h>
|
+#include <linux/errno.h>
|
||||||
+#include "apparmor.h"
|
+#include "apparmor.h"
|
||||||
+#include "match.h"
|
+#include "match.h"
|
||||||
|
+#include "inline.h"
|
||||||
+
|
+
|
||||||
+static struct table_header *unpack_table(void *blob, size_t bsize)
|
+static struct table_header *unpack_table(void *blob, size_t bsize)
|
||||||
+{
|
+{
|
||||||
|
@ -101,6 +102,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+ switch(table->td_id) {
|
+ switch(table->td_id) {
|
||||||
+ case YYTD_ID_ACCEPT:
|
+ case YYTD_ID_ACCEPT:
|
||||||
|
+ case YYTD_ID_ACCEPT2:
|
||||||
+ case YYTD_ID_BASE:
|
+ case YYTD_ID_BASE:
|
||||||
+ dfa->tables[table->td_id - 1] = table;
|
+ dfa->tables[table->td_id - 1] = table;
|
||||||
+ if (table->td_flags != YYTD_DATA32)
|
+ if (table->td_flags != YYTD_DATA32)
|
||||||
|
@ -153,6 +155,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+ /* check that required tables exist */
|
+ /* check that required tables exist */
|
||||||
+ if (!(dfa->tables[YYTD_ID_ACCEPT - 1] &&
|
+ if (!(dfa->tables[YYTD_ID_ACCEPT - 1] &&
|
||||||
|
+ dfa->tables[YYTD_ID_ACCEPT2 - 1] &&
|
||||||
+ dfa->tables[YYTD_ID_DEF - 1] &&
|
+ dfa->tables[YYTD_ID_DEF - 1] &&
|
||||||
+ dfa->tables[YYTD_ID_BASE - 1] &&
|
+ dfa->tables[YYTD_ID_BASE - 1] &&
|
||||||
+ dfa->tables[YYTD_ID_NXT - 1] &&
|
+ dfa->tables[YYTD_ID_NXT - 1] &&
|
||||||
|
@ -162,7 +165,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ /* accept.size == default.size == base.size */
|
+ /* accept.size == default.size == base.size */
|
||||||
+ state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
|
+ state_count = dfa->tables[YYTD_ID_BASE - 1]->td_lolen;
|
||||||
+ if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
|
+ if (!(state_count == dfa->tables[YYTD_ID_DEF - 1]->td_lolen &&
|
||||||
+ state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen))
|
+ state_count == dfa->tables[YYTD_ID_ACCEPT - 1]->td_lolen &&
|
||||||
|
+ state_count == dfa->tables[YYTD_ID_ACCEPT2 - 1]->td_lolen))
|
||||||
+ goto out;
|
+ goto out;
|
||||||
+
|
+
|
||||||
+ /* next.size == chk.size */
|
+ /* next.size == chk.size */
|
||||||
|
@ -195,13 +199,14 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+ if (mode & ~AA_VALID_PERM_MASK)
|
+ if (mode & ~AA_VALID_PERM_MASK)
|
||||||
+ goto out;
|
+ goto out;
|
||||||
+
|
+ if (ACCEPT_TABLE2(dfa)[i] & ~AA_VALID_PERM2_MASK)
|
||||||
+ /* if MAY_EXEC, exactly one exec modifier must be set */
|
+ goto out;
|
||||||
+ if (mode & MAY_EXEC) {
|
+
|
||||||
+ mode &= AA_EXEC_MODIFIERS;
|
+ /* if any exec modifier is set MAY_EXEC must be set */
|
||||||
+ if (mode & (mode - 1))
|
+ if ((mode & AA_USER_EXEC_TYPE) && !(mode & AA_USER_EXEC))
|
||||||
|
+ goto out;
|
||||||
|
+ if ((mode & AA_OTHER_EXEC_TYPE) && !(mode & AA_OTHER_EXEC))
|
||||||
+ goto out;
|
+ goto out;
|
||||||
+ }
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ error = 0;
|
+ error = 0;
|
||||||
|
@ -226,22 +231,76 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
+ * aa_dfa_match - match @path against @dfa starting in @state
|
+ * aa_dfa_next_state_len - traverse @dfa to find state @str stops at
|
||||||
+ * @dfa: the dfa to match @path against
|
+ * @dfa: the dfa to match @str against
|
||||||
+ * @state: the state to start matching in
|
+ * @start: the state of the dfa to start matching in
|
||||||
+ * @path: the path to match against the dfa
|
+ * @str: the string of bytes to match against the dfa
|
||||||
|
+ * @len: length of the string of bytes to match
|
||||||
+ *
|
+ *
|
||||||
+ * aa_dfa_match will match the full path length and return the state it
|
+ * aa_dfa_next_state will match @str against the dfa and return the state it
|
||||||
+ * finished matching in. The final state is used to look up the accepting
|
+ * finished matching in. The final state can be used to look up the accepting
|
||||||
+ * label.
|
+ * label, or as the start state of a continuing match.
|
||||||
|
+ *
|
||||||
|
+ * aa_dfa_next_state could be implement using this function by doing
|
||||||
|
+ * return aa_dfa_next_state_len(dfa, start, str, strlen(str));
|
||||||
|
+ * but that would require traversing the string twice and be slightly
|
||||||
|
+ * slower.
|
||||||
+ */
|
+ */
|
||||||
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str)
|
+unsigned int aa_dfa_next_state_len(struct aa_dfa *dfa, unsigned int start,
|
||||||
|
+ const char *str, int len)
|
||||||
+{
|
+{
|
||||||
+ u16 *def = DEFAULT_TABLE(dfa);
|
+ u16 *def = DEFAULT_TABLE(dfa);
|
||||||
+ u32 *base = BASE_TABLE(dfa);
|
+ u32 *base = BASE_TABLE(dfa);
|
||||||
+ u16 *next = NEXT_TABLE(dfa);
|
+ u16 *next = NEXT_TABLE(dfa);
|
||||||
+ u16 *check = CHECK_TABLE(dfa);
|
+ u16 *check = CHECK_TABLE(dfa);
|
||||||
+ unsigned int state = 1, pos;
|
+ unsigned int state = start, pos;
|
||||||
|
+
|
||||||
|
+ if (state == 0)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ /* current state is <state>, matching character *str */
|
||||||
|
+ if (dfa->tables[YYTD_ID_EC - 1]) {
|
||||||
|
+ u8 *equiv = EQUIV_TABLE(dfa);
|
||||||
|
+ for (; len; len--) {
|
||||||
|
+ pos = base[state] + equiv[(u8)*str++];
|
||||||
|
+ if (check[pos] == state)
|
||||||
|
+ state = next[pos];
|
||||||
|
+ else
|
||||||
|
+ state = def[state];
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ for (; len; len--) {
|
||||||
|
+ pos = base[state] + (u8)*str++;
|
||||||
|
+ if (check[pos] == state)
|
||||||
|
+ state = next[pos];
|
||||||
|
+ else
|
||||||
|
+ state = def[state];
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return state;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * aa_dfa_next_state - traverse @dfa to find state @str stops at
|
||||||
|
+ * @dfa: the dfa to match @str against
|
||||||
|
+ * @start: the state of the dfa to start matching in
|
||||||
|
+ * @str: the null terminated string of bytes to match against the dfa
|
||||||
|
+ *
|
||||||
|
+ * aa_dfa_next_state will match @str against the dfa and return the state it
|
||||||
|
+ * finished matching in. The final state can be used to look up the accepting
|
||||||
|
+ * label, or as the start state of a continuing match.
|
||||||
|
+ */
|
||||||
|
+unsigned int aa_dfa_next_state(struct aa_dfa *dfa, unsigned int start,
|
||||||
|
+ const char *str)
|
||||||
|
+{
|
||||||
|
+ u16 *def = DEFAULT_TABLE(dfa);
|
||||||
|
+ u32 *base = BASE_TABLE(dfa);
|
||||||
|
+ u16 *next = NEXT_TABLE(dfa);
|
||||||
|
+ u16 *check = CHECK_TABLE(dfa);
|
||||||
|
+ unsigned int state = start, pos;
|
||||||
|
+
|
||||||
|
+ if (state == 0)
|
||||||
|
+ return 0;
|
||||||
+
|
+
|
||||||
+ /* current state is <state>, matching character *str */
|
+ /* current state is <state>, matching character *str */
|
||||||
+ if (dfa->tables[YYTD_ID_EC - 1]) {
|
+ if (dfa->tables[YYTD_ID_EC - 1]) {
|
||||||
|
@ -262,11 +321,68 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ state = def[state];
|
+ state = def[state];
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
|
+ return state;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * aa_dfa_null_transition - step to next state after null character
|
||||||
|
+ * @dfa: the dfa to match against
|
||||||
|
+ * @start: the state of the dfa to start matching in
|
||||||
|
+ *
|
||||||
|
+ * aa_dfa_null_transition transitions to the next state after a null
|
||||||
|
+ * character which is not used in standard matching and is only
|
||||||
|
+ * used to seperate pairs.
|
||||||
|
+ */
|
||||||
|
+unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start)
|
||||||
|
+{
|
||||||
|
+ return aa_dfa_next_state_len(dfa, start, "", 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * aa_dfa_match - find accept perm for @str in @dfa
|
||||||
|
+ * @dfa: the dfa to match @str against
|
||||||
|
+ * @str: the string to match against the dfa
|
||||||
|
+ * @audit_mask: the audit_mask for the final state
|
||||||
|
+ *
|
||||||
|
+ * aa_dfa_match will match @str and return the accept perms for the
|
||||||
|
+ * final state.
|
||||||
|
+ */
|
||||||
|
+unsigned int aa_dfa_match(struct aa_dfa *dfa, const char *str, int *audit_mask)
|
||||||
|
+{
|
||||||
|
+ int state = aa_dfa_next_state(dfa, DFA_START, str);
|
||||||
|
+ if (audit_mask)
|
||||||
|
+ *audit_mask = dfa_audit_mask(dfa, state);
|
||||||
+ return ACCEPT_TABLE(dfa)[state];
|
+ return ACCEPT_TABLE(dfa)[state];
|
||||||
+}
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * aa_match_state - find accept perm and state for @str in @dfa
|
||||||
|
+ * @dfa: the dfa to match @str against
|
||||||
|
+ * @start: the state to start the match from
|
||||||
|
+ * @str: the string to match against the dfa
|
||||||
|
+ * @final: the state that the match finished in
|
||||||
|
+ *
|
||||||
|
+ * aa_match_state will match @str and return the accept perms, and @final
|
||||||
|
+ * state, the match occured in.
|
||||||
|
+ */
|
||||||
|
+unsigned int aa_match_state(struct aa_dfa *dfa, unsigned int start,
|
||||||
|
+ const char *str, unsigned int *final)
|
||||||
|
+{
|
||||||
|
+ unsigned int state;
|
||||||
|
+ if (dfa) {
|
||||||
|
+ state = aa_dfa_next_state(dfa, start, str);
|
||||||
|
+ if (final)
|
||||||
|
+ *final = state;
|
||||||
|
+ return ACCEPT_TABLE(dfa)[state];
|
||||||
|
+ }
|
||||||
|
+ if (final)
|
||||||
|
+ *final = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/match.h
|
+++ b/security/apparmor/match.h
|
||||||
@@ -0,0 +1,83 @@
|
@@ -0,0 +1,87 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 2007 Novell/SUSE
|
+ * Copyright (C) 2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -281,6 +397,8 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#ifndef __MATCH_H
|
+#ifndef __MATCH_H
|
||||||
+#define __MATCH_H
|
+#define __MATCH_H
|
||||||
+
|
+
|
||||||
|
+#define DFA_START 1
|
||||||
|
+
|
||||||
+/**
|
+/**
|
||||||
+ * The format used for transition tables is based on the GNU flex table
|
+ * The format used for transition tables is based on the GNU flex table
|
||||||
+ * file format (--tables-file option; see Table File Format in the flex
|
+ * file format (--tables-file option; see Table File Format in the flex
|
||||||
|
@ -306,6 +424,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#define YYTD_ID_DEF 4
|
+#define YYTD_ID_DEF 4
|
||||||
+#define YYTD_ID_EC 5
|
+#define YYTD_ID_EC 5
|
||||||
+#define YYTD_ID_META 6
|
+#define YYTD_ID_META 6
|
||||||
|
+#define YYTD_ID_ACCEPT2 7
|
||||||
+#define YYTD_ID_NXT 8
|
+#define YYTD_ID_NXT 8
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
|
@ -327,6 +446,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
|
+#define CHECK_TABLE(DFA) ((u16 *)((DFA)->tables[YYTD_ID_CHK - 1]->td_data))
|
||||||
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
|
+#define EQUIV_TABLE(DFA) ((u8 *)((DFA)->tables[YYTD_ID_EC - 1]->td_data))
|
||||||
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
|
+#define ACCEPT_TABLE(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT - 1]->td_data))
|
||||||
|
+#define ACCEPT_TABLE2(DFA) ((u32 *)((DFA)->tables[YYTD_ID_ACCEPT2 -1]->td_data))
|
||||||
+
|
+
|
||||||
+struct aa_dfa {
|
+struct aa_dfa {
|
||||||
+ struct table_header *tables[YYTD_ID_NXT];
|
+ struct table_header *tables[YYTD_ID_NXT];
|
||||||
|
@ -352,7 +472,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+#endif /* __MATCH_H */
|
+#endif /* __MATCH_H */
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/security/apparmor/module_interface.c
|
+++ b/security/apparmor/module_interface.c
|
||||||
@@ -0,0 +1,623 @@
|
@@ -0,0 +1,815 @@
|
||||||
+/*
|
+/*
|
||||||
+ * Copyright (C) 1998-2007 Novell/SUSE
|
+ * Copyright (C) 1998-2007 Novell/SUSE
|
||||||
+ *
|
+ *
|
||||||
|
@ -413,6 +533,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ void *end;
|
+ void *end;
|
||||||
+ void *pos; /* pointer to current position in the buffer */
|
+ void *pos; /* pointer to current position in the buffer */
|
||||||
+ u32 version;
|
+ u32 version;
|
||||||
|
+ char *ns_name;
|
||||||
+};
|
+};
|
||||||
+
|
+
|
||||||
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
|
+static inline int aa_inbounds(struct aa_ext *e, size_t size)
|
||||||
|
@ -664,6 +785,12 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+
|
+
|
||||||
+ if (!aa_is_u32(e, &(profile->capabilities), NULL))
|
+ if (!aa_is_u32(e, &(profile->capabilities), NULL))
|
||||||
+ goto fail;
|
+ goto fail;
|
||||||
|
+ if (!aa_is_u32(e, &(profile->audit_caps), NULL))
|
||||||
|
+ goto fail;
|
||||||
|
+ if (!aa_is_u32(e, &(profile->quiet_caps), NULL))
|
||||||
|
+ goto fail;
|
||||||
|
+ if (!aa_is_u32(e, &(profile->set_caps), NULL))
|
||||||
|
+ goto fail;
|
||||||
+
|
+
|
||||||
+ /* get file rules */
|
+ /* get file rules */
|
||||||
+ profile->file_rules = aa_unpack_dfa(e);
|
+ profile->file_rules = aa_unpack_dfa(e);
|
||||||
|
@ -671,6 +798,10 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ error = PTR_ERR(profile->file_rules);
|
+ error = PTR_ERR(profile->file_rules);
|
||||||
+ profile->file_rules = NULL;
|
+ profile->file_rules = NULL;
|
||||||
+ goto fail;
|
+ goto fail;
|
||||||
|
+ if (!aa_is_u16(e, &profile->audit_network[i], NULL))
|
||||||
|
+ goto fail;
|
||||||
|
+ if (!aa_is_u16(e, &profile->quiet_network[i], NULL))
|
||||||
|
+ goto fail;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
+ if (!aa_is_nameX(e, AA_STRUCTEND, NULL))
|
||||||
|
@ -683,6 +814,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ sa.operation = operation;
|
+ sa.operation = operation;
|
||||||
+ sa.gfp_mask = GFP_KERNEL;
|
+ sa.gfp_mask = GFP_KERNEL;
|
||||||
+ sa.name = profile && profile->name ? profile->name : "unknown";
|
+ sa.name = profile && profile->name ? profile->name : "unknown";
|
||||||
|
+ if (!sa.info)
|
||||||
+ sa.info = "failed to unpack profile";
|
+ sa.info = "failed to unpack profile";
|
||||||
+ aa_audit_status(NULL, &sa);
|
+ aa_audit_status(NULL, &sa);
|
||||||
+
|
+
|
||||||
|
@ -713,7 +845,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* check that the interface version is currently supported */
|
+ /* check that the interface version is currently supported */
|
||||||
+ if (e->version != 3) {
|
+ if (e->version != 4) {
|
||||||
+ struct aa_audit sa;
|
+ struct aa_audit sa;
|
||||||
+ memset(&sa, 0, sizeof(sa));
|
+ memset(&sa, 0, sizeof(sa));
|
||||||
+ sa.operation = operation;
|
+ sa.operation = operation;
|
||||||
|
@ -722,6 +854,12 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ aa_audit_status(NULL, &sa);
|
+ aa_audit_status(NULL, &sa);
|
||||||
+ return -EPROTONOSUPPORT;
|
+ return -EPROTONOSUPPORT;
|
||||||
+ }
|
+ }
|
||||||
|
+
|
||||||
|
+ /* read the namespace if present */
|
||||||
|
+ if (!aa_is_dynstring(e, &e->ns_name, "namespace")) {
|
||||||
|
+ e->ns_name = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -733,10 +871,12 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ssize_t aa_add_profile(void *data, size_t size)
|
+ssize_t aa_add_profile(void *data, size_t size)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *profile = NULL;
|
+ struct aa_profile *profile = NULL;
|
||||||
|
+ struct aa_namespace *ns = NULL;
|
||||||
+ struct aa_ext e = {
|
+ struct aa_ext e = {
|
||||||
+ .start = data,
|
+ .start = data,
|
||||||
+ .end = data + size,
|
+ .end = data + size,
|
||||||
+ .pos = data
|
+ .pos = data,
|
||||||
|
+ .ns_name = NULL
|
||||||
+ };
|
+ };
|
||||||
+ ssize_t error = aa_verify_header(&e, "profile_load");
|
+ ssize_t error = aa_verify_header(&e, "profile_load");
|
||||||
+ if (error)
|
+ if (error)
|
||||||
|
@ -747,16 +887,42 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return PTR_ERR(profile);
|
+ return PTR_ERR(profile);
|
||||||
+
|
+
|
||||||
+ mutex_lock(&aa_interface_lock);
|
+ mutex_lock(&aa_interface_lock);
|
||||||
+ write_lock(&profile_list_lock);
|
+ write_lock(&profile_ns_list_lock);
|
||||||
+ if (__aa_find_profile(profile->name, &profile_list)) {
|
+ if (e.ns_name)
|
||||||
|
+ ns = __aa_find_namespace(e.ns_name, &profile_ns_list);
|
||||||
|
+ else
|
||||||
|
+ ns = default_namespace;
|
||||||
|
+ if (!ns) {
|
||||||
|
+ struct aa_namespace *new_ns;
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
|
+ new_ns = alloc_aa_namespace(e.ns_name);
|
||||||
|
+ if (!new_ns) {
|
||||||
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+ write_lock(&profile_ns_list_lock);
|
||||||
|
+ ns = __aa_find_namespace(e.ns_name, &profile_ns_list);
|
||||||
|
+ if (!ns) {
|
||||||
|
+ list_add(&new_ns->list, &profile_ns_list);
|
||||||
|
+ ns = new_ns;
|
||||||
|
+ } else
|
||||||
|
+ free_aa_namespace(new_ns);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ write_lock(&ns->lock);
|
||||||
|
+ if (__aa_find_profile(profile->name, &ns->profiles)) {
|
||||||
+ /* A profile with this name exists already. */
|
+ /* A profile with this name exists already. */
|
||||||
+ write_unlock(&profile_list_lock);
|
+ write_unlock(&ns->lock);
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
+ mutex_unlock(&aa_interface_lock);
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
+ aa_put_profile(profile);
|
+ aa_put_profile(profile);
|
||||||
+ return -EEXIST;
|
+ return -EEXIST;
|
||||||
+ }
|
+ }
|
||||||
+ list_add(&profile->list, &profile_list);
|
+ profile->ns = aa_get_namespace(ns);
|
||||||
+ write_unlock(&profile_list_lock);
|
+ ns->profile_count++;
|
||||||
|
+ list_add(&profile->list, &ns->profiles);
|
||||||
|
+ write_unlock(&ns->lock);
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
+ mutex_unlock(&aa_interface_lock);
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
+
|
+
|
||||||
+ return size;
|
+ return size;
|
||||||
|
@ -796,12 +962,15 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ssize_t aa_replace_profile(void *udata, size_t size)
|
+ssize_t aa_replace_profile(void *udata, size_t size)
|
||||||
+{
|
+{
|
||||||
+ struct aa_profile *old_profile, *new_profile;
|
+ struct aa_profile *old_profile, *new_profile;
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
+ struct aa_task_context *new_cxt;
|
+ struct aa_task_context *new_cxt;
|
||||||
+ struct aa_ext e = {
|
+ struct aa_ext e = {
|
||||||
+ .start = udata,
|
+ .start = udata,
|
||||||
+ .end = udata + size,
|
+ .end = udata + size,
|
||||||
+ .pos = udata
|
+ .pos = udata,
|
||||||
|
+ .ns_name = NULL
|
||||||
+ };
|
+ };
|
||||||
|
+
|
||||||
+ ssize_t error = aa_verify_header(&e, "profile_replace");
|
+ ssize_t error = aa_verify_header(&e, "profile_replace");
|
||||||
+ if (error)
|
+ if (error)
|
||||||
+ return error;
|
+ return error;
|
||||||
|
@ -811,16 +980,42 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ return PTR_ERR(new_profile);
|
+ return PTR_ERR(new_profile);
|
||||||
+
|
+
|
||||||
+ mutex_lock(&aa_interface_lock);
|
+ mutex_lock(&aa_interface_lock);
|
||||||
+ write_lock(&profile_list_lock);
|
+ write_lock(&profile_ns_list_lock);
|
||||||
+ old_profile = __aa_find_profile(new_profile->name, &profile_list);
|
+ if (e.ns_name)
|
||||||
|
+ ns = __aa_find_namespace(e.ns_name, &profile_ns_list);
|
||||||
|
+ else
|
||||||
|
+ ns = default_namespace;
|
||||||
|
+ if (!ns) {
|
||||||
|
+ struct aa_namespace *new_ns;
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
|
+ new_ns = alloc_aa_namespace(e.ns_name);
|
||||||
|
+ if (!new_ns) {
|
||||||
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+ write_lock(&profile_ns_list_lock);
|
||||||
|
+ ns = __aa_find_namespace(e.ns_name, &profile_ns_list);
|
||||||
|
+ if (!ns) {
|
||||||
|
+ list_add(&new_ns->list, &profile_ns_list);
|
||||||
|
+ ns = new_ns;
|
||||||
|
+ } else
|
||||||
|
+ free_aa_namespace(new_ns);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ write_lock(&ns->lock);
|
||||||
|
+ old_profile = __aa_find_profile(new_profile->name, &ns->profiles);
|
||||||
+ if (old_profile) {
|
+ if (old_profile) {
|
||||||
+ lock_profile(old_profile);
|
+ lock_profile(old_profile);
|
||||||
+ old_profile->isstale = 1;
|
+ old_profile->isstale = 1;
|
||||||
+ unlock_profile(old_profile);
|
|
||||||
+ list_del_init(&old_profile->list);
|
+ list_del_init(&old_profile->list);
|
||||||
|
+ unlock_profile(old_profile);
|
||||||
|
+ ns->profile_count--;
|
||||||
+ }
|
+ }
|
||||||
+ list_add(&new_profile->list, &profile_list);
|
+ new_profile->ns = aa_get_namespace(ns);
|
||||||
+ write_unlock(&profile_list_lock);
|
+ ns->profile_count++;
|
||||||
|
+ list_add(&new_profile->list, &ns->profiles);
|
||||||
|
+ write_unlock(&ns->lock);
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
+
|
+
|
||||||
+ if (!old_profile)
|
+ if (!old_profile)
|
||||||
+ goto out;
|
+ goto out;
|
||||||
|
@ -865,32 +1060,148 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ * remove a profile from the profile list and all aa_task_context references
|
+ * remove a profile from the profile list and all aa_task_context references
|
||||||
+ * to said profile.
|
+ * to said profile.
|
||||||
+ */
|
+ */
|
||||||
+ssize_t aa_remove_profile(const char *name, size_t size)
|
+ssize_t aa_remove_profile(char *name, size_t size)
|
||||||
+{
|
+{
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
+ struct aa_profile *profile;
|
+ struct aa_profile *profile;
|
||||||
+
|
+
|
||||||
+ mutex_lock(&aa_interface_lock);
|
+ mutex_lock(&aa_interface_lock);
|
||||||
+ write_lock(&profile_list_lock);
|
+ write_lock(&profile_ns_list_lock);
|
||||||
+ profile = __aa_find_profile(name, &profile_list);
|
+
|
||||||
|
+ if (name[0] == '/') {
|
||||||
|
+ ns = default_namespace;
|
||||||
|
+ } else {
|
||||||
|
+ char *split = strchr(name, ':');
|
||||||
|
+ if (!split)
|
||||||
|
+ goto noent;
|
||||||
|
+ *split = 0;
|
||||||
|
+ ns = __aa_find_namespace(name, &profile_ns_list);
|
||||||
|
+ name = split + 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!ns)
|
||||||
|
+ goto noent;
|
||||||
|
+ write_lock(&ns->lock);
|
||||||
|
+ profile = __aa_find_profile(name, &ns->profiles);
|
||||||
+ if (!profile) {
|
+ if (!profile) {
|
||||||
+ write_unlock(&profile_list_lock);
|
+ write_unlock(&ns->lock);
|
||||||
+ mutex_unlock(&aa_interface_lock);
|
+ goto noent;
|
||||||
+ return -ENOENT;
|
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* Remove the profile from each task context it is on. */
|
+ /* Remove the profile from each task context it is on. */
|
||||||
+ lock_profile(profile);
|
+ lock_profile(profile);
|
||||||
+ profile->isstale = 1;
|
+ profile->isstale = 1;
|
||||||
+ aa_unconfine_tasks(profile);
|
+ aa_unconfine_tasks(profile);
|
||||||
+ unlock_profile(profile);
|
|
||||||
+
|
|
||||||
+ /* Release the profile itself. */
|
|
||||||
+ list_del_init(&profile->list);
|
+ list_del_init(&profile->list);
|
||||||
+ aa_put_profile(profile);
|
+ ns->profile_count--;
|
||||||
+ write_unlock(&profile_list_lock);
|
+ unlock_profile(profile);
|
||||||
|
+ /* Release the profile itself. */
|
||||||
|
+ write_unlock(&ns->lock);
|
||||||
|
+ /* check to see if the namespace has become stale */
|
||||||
|
+ if (ns != default_namespace && ns->profile_count == 0) {
|
||||||
|
+ list_del_init(&ns->list);
|
||||||
|
+ aa_put_namespace(ns);
|
||||||
|
+ }
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
+ mutex_unlock(&aa_interface_lock);
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
|
+ aa_put_profile(profile);
|
||||||
+
|
+
|
||||||
+ return size;
|
+ return size;
|
||||||
|
+
|
||||||
|
+noent:
|
||||||
|
+ write_unlock(&profile_ns_list_lock);
|
||||||
|
+ mutex_unlock(&aa_interface_lock);
|
||||||
|
+ return -ENOENT;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * free_aa_namespace_kref - free aa_namespace by kref (see aa_put_namespace)
|
||||||
|
+ * @kr: kref callback for freeing of a namespace
|
||||||
|
+ */
|
||||||
|
+void free_aa_namespace_kref(struct kref *kref)
|
||||||
|
+{
|
||||||
|
+ struct aa_namespace *ns=container_of(kref, struct aa_namespace, count);
|
||||||
|
+
|
||||||
|
+ free_aa_namespace(ns);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * alloc_aa_namespace - allocate, initialize and return a new namespace
|
||||||
|
+ * @name: a preallocated name
|
||||||
|
+ * Returns NULL on failure.
|
||||||
|
+ */
|
||||||
|
+struct aa_namespace *alloc_aa_namespace(char *name)
|
||||||
|
+{
|
||||||
|
+ struct aa_namespace *ns;
|
||||||
|
+
|
||||||
|
+ ns = kzalloc(sizeof(*ns), GFP_KERNEL);
|
||||||
|
+ AA_DEBUG("%s(%p)\n", __FUNCTION__, ns);
|
||||||
|
+ if (ns) {
|
||||||
|
+ ns->name = name;
|
||||||
|
+ INIT_LIST_HEAD(&ns->list);
|
||||||
|
+ INIT_LIST_HEAD(&ns->profiles);
|
||||||
|
+ kref_init(&ns->count);
|
||||||
|
+ rwlock_init(&ns->lock);
|
||||||
|
+
|
||||||
|
+ ns->null_complain_profile = alloc_aa_profile();
|
||||||
|
+ if (!ns->null_complain_profile) {
|
||||||
|
+ if (!name)
|
||||||
|
+ kfree(ns->name);
|
||||||
|
+ kfree(ns);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+ ns->null_complain_profile->name =
|
||||||
|
+ kstrdup("null-complain-profile", GFP_KERNEL);
|
||||||
|
+ if (!ns->null_complain_profile->name) {
|
||||||
|
+ free_aa_profile(ns->null_complain_profile);
|
||||||
|
+ if (!name)
|
||||||
|
+ kfree(ns->name);
|
||||||
|
+ kfree(ns);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+ ns->null_complain_profile->flags.complain = 1;
|
||||||
|
+ /* null_complain_profile doesn't contribute to ns ref count */
|
||||||
|
+ ns->null_complain_profile->ns = ns;
|
||||||
|
+ }
|
||||||
|
+ return ns;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * free_aa_namespace - free a profile namespace
|
||||||
|
+ * @namespace: the namespace to free
|
||||||
|
+ *
|
||||||
|
+ * Free a namespace. All references to the namespace must have been put.
|
||||||
|
+ * If the namespace was referenced by a profile confining a task,
|
||||||
|
+ * free_aa_namespace will be called indirectly (through free_aa_profile)
|
||||||
|
+ * from an rcu callback routine, so we must not sleep here.
|
||||||
|
+ */
|
||||||
|
+void free_aa_namespace(struct aa_namespace *ns)
|
||||||
|
+{
|
||||||
|
+ AA_DEBUG("%s(%p)\n", __FUNCTION__, ns);
|
||||||
|
+
|
||||||
|
+ if (!ns)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* namespace still contains profiles -- invalid */
|
||||||
|
+ if (!list_empty(&ns->profiles)) {
|
||||||
|
+ AA_ERROR("%s: internal error, "
|
||||||
|
+ "namespace '%s' still contains profiles\n",
|
||||||
|
+ __FUNCTION__,
|
||||||
|
+ ns->name);
|
||||||
|
+ BUG();
|
||||||
|
+ }
|
||||||
|
+ if (!list_empty(&ns->list)) {
|
||||||
|
+ AA_ERROR("%s: internal error, "
|
||||||
|
+ "namespace '%s' still on list\n",
|
||||||
|
+ __FUNCTION__,
|
||||||
|
+ ns->name);
|
||||||
|
+ BUG();
|
||||||
|
+ }
|
||||||
|
+ /* null_complain_profile doesn't contribute to ns ref counting */
|
||||||
|
+ ns->null_complain_profile->ns = NULL;
|
||||||
|
+ aa_put_profile(ns->null_complain_profile);
|
||||||
|
+ kfree(ns->name);
|
||||||
|
+ kfree(ns);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+/**
|
+/**
|
||||||
|
@ -940,7 +1251,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ if (!profile)
|
+ if (!profile)
|
||||||
+ return;
|
+ return;
|
||||||
+
|
+
|
||||||
+ /* profile is still on global profile list -- invalid */
|
+ /* profile is still on profile namespace list -- invalid */
|
||||||
+ if (!list_empty(&profile->list)) {
|
+ if (!list_empty(&profile->list)) {
|
||||||
+ AA_ERROR("%s: internal error, "
|
+ AA_ERROR("%s: internal error, "
|
||||||
+ "profile '%s' still on global list\n",
|
+ "profile '%s' still on global list\n",
|
||||||
|
@ -948,6 +1259,7 @@ Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
|
||||||
+ profile->name);
|
+ profile->name);
|
||||||
+ BUG();
|
+ BUG();
|
||||||
+ }
|
+ }
|
||||||
|
+ aa_put_namespace(profile->ns);
|
||||||
+
|
+
|
||||||
+ aa_match_free(profile->file_rules);
|
+ aa_match_free(profile->file_rules);
|
||||||
+
|
+
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
---
|
---
|
||||||
security/apparmor/Makefile | 7 +
|
security/apparmor/Makefile | 7 +
|
||||||
security/apparmor/apparmor.h | 9 ++
|
security/apparmor/apparmor.h | 9 ++
|
||||||
security/apparmor/lsm.c | 147 ++++++++++++++++++++++++++++++++++-
|
security/apparmor/lsm.c | 129 ++++++++++++++++++++++++++++++++++-
|
||||||
security/apparmor/main.c | 106 +++++++++++++++++++++++++
|
security/apparmor/main.c | 106 ++++++++++++++++++++++++++++
|
||||||
security/apparmor/module_interface.c | 20 ++++
|
security/apparmor/module_interface.c | 20 +++++
|
||||||
5 files changed, 285 insertions(+), 4 deletions(-)
|
5 files changed, 267 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
--- a/security/apparmor/Makefile
|
--- a/security/apparmor/Makefile
|
||||||
+++ b/security/apparmor/Makefile
|
+++ b/security/apparmor/Makefile
|
||||||
|
@ -70,7 +70,7 @@
|
||||||
|
|
||||||
#include "apparmor.h"
|
#include "apparmor.h"
|
||||||
#include "inline.h"
|
#include "inline.h"
|
||||||
@@ -653,6 +654,133 @@ static void apparmor_task_free_security(
|
@@ -653,6 +654,117 @@ static void apparmor_task_free_security(
|
||||||
aa_release(task);
|
aa_release(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,27 +184,11 @@
|
||||||
+
|
+
|
||||||
+ return aa_revalidate_sk(sk, "socket_shutdown");
|
+ return aa_revalidate_sk(sk, "socket_shutdown");
|
||||||
+}
|
+}
|
||||||
+
|
|
||||||
+static int apparmor_socket_getpeersec_stream(struct socket *sock,
|
|
||||||
+ char __user *optval, int __user *optlen, unsigned len)
|
|
||||||
+{
|
|
||||||
+ struct sock *sk = sock->sk;
|
|
||||||
+
|
|
||||||
+ return aa_revalidate_sk(sk, "socket_getpeersec_stream");
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static int apparmor_socket_getpeersec_dgram(struct socket *sock,
|
|
||||||
+ struct sk_buff *skb, u32 *secid)
|
|
||||||
+{
|
|
||||||
+ struct sock *sk = sock->sk;
|
|
||||||
+
|
|
||||||
+ return aa_revalidate_sk(sk, "socket_getpeersec_dgram");
|
|
||||||
+}
|
|
||||||
+
|
+
|
||||||
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
static int apparmor_getprocattr(struct task_struct *task, char *name,
|
||||||
char **value)
|
char **value)
|
||||||
{
|
{
|
||||||
@@ -753,9 +881,6 @@ struct security_operations apparmor_ops
|
@@ -753,9 +865,6 @@ struct security_operations apparmor_ops
|
||||||
.capable = apparmor_capable,
|
.capable = apparmor_capable,
|
||||||
.syslog = cap_syslog,
|
.syslog = cap_syslog,
|
||||||
|
|
||||||
|
@ -214,7 +198,7 @@
|
||||||
.bprm_apply_creds = cap_bprm_apply_creds,
|
.bprm_apply_creds = cap_bprm_apply_creds,
|
||||||
.bprm_set_security = apparmor_bprm_set_security,
|
.bprm_set_security = apparmor_bprm_set_security,
|
||||||
.bprm_secureexec = apparmor_bprm_secureexec,
|
.bprm_secureexec = apparmor_bprm_secureexec,
|
||||||
@@ -791,6 +916,22 @@ struct security_operations apparmor_ops
|
@@ -791,6 +900,20 @@ struct security_operations apparmor_ops
|
||||||
|
|
||||||
.getprocattr = apparmor_getprocattr,
|
.getprocattr = apparmor_getprocattr,
|
||||||
.setprocattr = apparmor_setprocattr,
|
.setprocattr = apparmor_setprocattr,
|
||||||
|
@ -232,8 +216,6 @@
|
||||||
+ .socket_getsockopt = apparmor_socket_getsockopt,
|
+ .socket_getsockopt = apparmor_socket_getsockopt,
|
||||||
+ .socket_setsockopt = apparmor_socket_setsockopt,
|
+ .socket_setsockopt = apparmor_socket_setsockopt,
|
||||||
+ .socket_shutdown = apparmor_socket_shutdown,
|
+ .socket_shutdown = apparmor_socket_shutdown,
|
||||||
+ .socket_getpeersec_stream = apparmor_socket_getpeersec_stream,
|
|
||||||
+ .socket_getpeersec_dgram = apparmor_socket_getpeersec_dgram,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void info_message(const char *str)
|
void info_message(const char *str)
|
||||||
|
|
|
@ -50,33 +50,35 @@ apparmor-module_interface.diff
|
||||||
apparmor-misc.diff
|
apparmor-misc.diff
|
||||||
apparmor-intree.diff
|
apparmor-intree.diff
|
||||||
|
|
||||||
fix-rcu-deref.diff
|
#fix-rcu-deref.diff
|
||||||
fix-name-errorpath.diff
|
#fix-name-errorpath.diff
|
||||||
change-profile-kernel-v2.diff
|
#change-profile-kernel-v2.diff
|
||||||
expand-dfa.diff
|
#expand-dfa.diff
|
||||||
#slash-null-dfa.diff
|
#slash-null-dfa.diff
|
||||||
profile-namespaces.diff
|
#profile-namespaces.diff
|
||||||
owner-perm-set.diff
|
#owner-perm-set.diff
|
||||||
apparmor-link-pairs.diff
|
#apparmor-link-pairs.diff
|
||||||
apparmor-bootdisable.diff
|
#apparmor-bootdisable.diff
|
||||||
apparmor-builtin-only.diff
|
#apparmor-builtin-only.diff
|
||||||
apparmor-security-goal.diff
|
#apparmor-security-goal.diff
|
||||||
apparmor-features.diff
|
#apparmor-features.diff
|
||||||
split_init.diff
|
#split_init.diff
|
||||||
apparmor-fix-sysctl-refcount.diff
|
#apparmor-fix-sysctl-refcount.diff
|
||||||
apparmor-fix-lock-letter.diff
|
#apparmor-fix-lock-letter.diff
|
||||||
fix-link-subset.diff
|
#fix-link-subset.diff
|
||||||
hat_perm.diff
|
#hat_perm.diff
|
||||||
extend-x-mods.diff
|
#extend-x-mods.diff
|
||||||
no-safex-link-subset.diff
|
#no-safex-link-subset.diff
|
||||||
apparmor-create-append.diff
|
#apparmor-create-append.diff
|
||||||
apparmor-failed-name-error.diff
|
#apparmor-failed-name-error.diff
|
||||||
audit-uid.diff
|
#audit-uid.diff
|
||||||
apparmor-secondary-accept.diff
|
#apparmor-secondary-accept.diff
|
||||||
apparmor-audit-flags2.diff
|
#apparmor-audit-flags2.diff
|
||||||
fix-profile-namespaces.diff
|
#fix-profile-namespaces.diff
|
||||||
fix-dfa.diff
|
#fix-dfa.diff
|
||||||
cap-set.diff
|
#cap-set.diff
|
||||||
|
|
||||||
|
|
||||||
#foobar.diff
|
#foobar.diff
|
||||||
# # NOT YET
|
# # NOT YET
|
||||||
# ecryptfs-d_revalidate.diff
|
# ecryptfs-d_revalidate.diff
|
||||||
|
@ -109,6 +111,6 @@ cap-set.diff
|
||||||
#FS2.1.3_fix-unionfs-with-AppArmor.patch
|
#FS2.1.3_fix-unionfs-with-AppArmor.patch
|
||||||
|
|
||||||
apparmor-network.diff
|
apparmor-network.diff
|
||||||
fix-net.diff
|
#fix-net.diff
|
||||||
rlimits.diff
|
rlimits.diff
|
||||||
audit-log-type-in-syslog.diff
|
audit-log-type-in-syslog.diff
|
||||||
|
|
Loading…
Add table
Reference in a new issue