From: John Johnansen Subject: allow apparmor to stack with dazuko Patch-mainline: no References: 300965 Allow AppArmor to stack with dazuko so that the clamav virus scanner can be used on an AppArmored machine. Signed-off-by: John Johansen --- security/apparmor/apparmor.h | 2 security/apparmor/apparmorfs.c | 2 security/apparmor/lsm.c | 101 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 92 insertions(+), 13 deletions(-) --- a/security/apparmor/apparmor.h +++ b/security/apparmor/apparmor.h @@ -347,7 +347,7 @@ extern void aa_set_rlimits(struct task_s /* lsm.c */ extern int apparmor_initialized; -extern void info_message(const char *str); +extern void info_message(const char *str, const char *name); extern void apparmor_disable(void); /* list.c */ --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -266,7 +266,7 @@ int create_apparmorfs(void) goto error; /* Report that AppArmor fs is enabled */ - info_message("AppArmor Filesystem Enabled"); + info_message("AppArmor Filesystem Enabled", ""); return 0; error: --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -26,6 +26,20 @@ /* Flag indicating whether initialization completed */ int apparmor_initialized = 0; +/* point to the apparmor module */ +struct module *aa_module = NULL; + +/* secondary ops if apparmor is stacked */ +static struct security_operations *aa_secondary_ops = NULL; +static DEFINE_MUTEX(aa_secondary_lock); + +#define AA_SECONDARY(FN, ARGS...) \ + ({ \ + struct security_operations *__f1; \ + __f1 = rcu_dereference(aa_secondary_ops); \ + (unlikely(__f1) && __f1->FN) ? __f1->FN(ARGS) : 0; \ + }) + static int param_set_aabool(const char *val, 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) @@ -452,19 +466,25 @@ out: static int apparmor_inode_permission(struct inode *inode, int mask, struct nameidata *nd) { - int check = 0; + int check = 0, error = 0; if (!nd || nd->flags & (LOOKUP_PARENT | LOOKUP_CONTINUE)) - return 0; + goto out; mask = aa_mask_permissions(mask); if (S_ISDIR(inode->i_mode)) { check |= AA_CHECK_DIR; /* allow traverse accesses to directories */ mask &= ~MAY_EXEC; } - return aa_permission("inode_permission", inode, nd->path.dentry, - nd->path.mnt, - mask, check); + error = aa_permission("inode_permission", inode, nd->path.dentry, + nd->path.mnt, + mask, check); + +out: + if (!error) + error = AA_SECONDARY(inode_permission, inode, mask, nd); + + return error; } static int apparmor_inode_setattr(struct dentry *dentry, struct vfsmount *mnt, @@ -882,6 +902,61 @@ static int apparmor_task_setrlimit(unsig return error; } +int apparmor_register_subsecurity(const char *name, + struct security_operations *ops) +{ + int error = 0; + + if (mutex_lock_interruptible(&aa_secondary_lock)) + return -ERESTARTSYS; + + /* allow dazuko and capability to stack. The stacking with + * capability is not needed since apparmor already composes + * capability using common cap. + */ + if (!aa_secondary_ops && (strcmp(name, "dazuko") == 0 || + strcmp(name, "capability") == 0)){ + /* The apparmor module needs to be pinned while a secondary is + * registered + */ + if (try_module_get(aa_module)) { + aa_secondary_ops = ops; + info_message("Registered secondary security module", + name); + } else { + error = -EINVAL; + } + } else { + info_message("Unable to register %s as a secondary security " + "module", name); + error = -EPERM; + } + mutex_unlock(&aa_secondary_lock); + return error; +} + +int apparmor_unregister_subsecurity(const char *name, + struct security_operations *ops) +{ + int error = 0; + + if (mutex_lock_interruptible(&aa_secondary_lock)) + return -ERESTARTSYS; + + if (aa_secondary_ops && aa_secondary_ops == ops) { + rcu_assign_pointer(aa_secondary_ops, NULL); + synchronize_rcu(); + module_put(aa_module); + info_message("Unregistered secondary security module", name); + } else { + info_message("Unable to unregister secondary security module", + name); + error = -EPERM; + } + mutex_unlock(&aa_secondary_lock); + return error; +} + struct security_operations apparmor_ops = { .ptrace = apparmor_ptrace, .capget = cap_capget, @@ -928,6 +1003,8 @@ struct security_operations apparmor_ops .getprocattr = apparmor_getprocattr, .setprocattr = apparmor_setprocattr, + .register_security = apparmor_register_subsecurity, + .socket_create = apparmor_socket_create, .socket_post_create = apparmor_socket_post_create, .socket_bind = apparmor_socket_bind, @@ -943,13 +1020,14 @@ struct security_operations apparmor_ops .socket_shutdown = apparmor_socket_shutdown, }; -void info_message(const char *str) +void info_message(const char *str, const char *name) { struct aa_audit sa; memset(&sa, 0, sizeof(sa)); sa.gfp_mask = GFP_KERNEL; sa.info = str; - printk(KERN_INFO "AppArmor: %s\n", str); + sa.name = name; + printk(KERN_INFO "AppArmor: %s %s\n", str, name); if (audit_enabled) aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS); } @@ -959,7 +1037,7 @@ static int __init apparmor_init(void) int error; if (!apparmor_enabled) { - info_message("AppArmor disabled by boottime parameter\n"); + info_message("AppArmor disabled by boottime parameter", ""); return 0; } @@ -981,9 +1059,10 @@ static int __init apparmor_init(void) /* Report that AppArmor successfully initialized */ apparmor_initialized = 1; if (apparmor_complain) - info_message("AppArmor initialized: complainmode enabled"); + info_message("AppArmor initialized: complainmode enabled", + NULL); else - info_message("AppArmor initialized"); + info_message("AppArmor initialized", NULL); return error; @@ -1021,7 +1100,7 @@ void apparmor_disable(void) apparmor_initialized = 0; - info_message("AppArmor protection removed"); + info_message("AppArmor protection removed", NULL); } MODULE_DESCRIPTION("AppArmor process confinement");