--- security/apparmor/Kconfig | 15 ++++++ security/apparmor/apparmorfs.c | 12 +++++ security/apparmor/lsm.c | 93 +++++++++++++++++++++++++++++++++-------- 3 files changed, 103 insertions(+), 17 deletions(-) --- a/security/apparmor/Kconfig +++ b/security/apparmor/Kconfig @@ -25,3 +25,18 @@ config SECURITY_APPARMOR_BOOTPARAM_VALUE 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. --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -231,6 +231,9 @@ int create_apparmorfs(void) { int error; + if (!apparmor_initialized) + return 0; + if (apparmor_dentry) { AA_ERROR("%s: AppArmor securityfs already exists\n", __FUNCTION__); @@ -262,11 +265,20 @@ int create_apparmorfs(void) if (error) goto error; + /* Report that AppArmor has been successfully initialized */ + if (apparmor_complain) + info_message("AppArmor initialized: complainmode enabled"); + else + info_message("AppArmor initialized"); + return 0; error: destroy_apparmorfs(); AA_ERROR("Error creating AppArmor securityfs\n"); + apparmor_disable(); return error; } +fs_initcall(create_apparmorfs); + --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -23,16 +23,8 @@ #include "apparmor.h" #include "inline.h" -/* Boot time disable flag */ -int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; - -static int __init apparmor_enabled_setup(char *str) -{ - apparmor_enabled = simple_strtol(str, NULL, 0); - return 1; -} -__setup("apparmor=", apparmor_enabled_setup); - +/* Flag indicating whether initialization completed */ +int apparmor_initialized = 0; static int param_set_aabool(const char *val, struct kernel_param *kp); static int param_get_aabool(char *buffer, struct kernel_param *kp); @@ -75,6 +67,19 @@ unsigned int apparmor_path_max = 2 * PAT module_param_named(path_max, apparmor_path_max, aauint, S_IRUSR | S_IWUSR); 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 param_set_aabool(const char *val, struct kernel_param *kp) { if (aa_task_context(current)) @@ -103,6 +108,34 @@ static int param_get_aauint(char *buffer return param_get_uint(buffer, kp); } +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, const char *name) { @@ -879,13 +912,13 @@ struct security_operations apparmor_ops .socket_shutdown = apparmor_socket_shutdown, }; -static void info_message(const char *str) +void info_message(const char *str) { struct aa_audit sa; memset(&sa, 0, sizeof(sa)); sa.gfp_mask = GFP_KERNEL; sa.info = str; - printk(KERN_INFO "AppArmor: %s", str); + printk(KERN_INFO "AppArmor: %s\n", str); aa_audit_message(NULL, &sa, AUDIT_APPARMOR_STATUS); } @@ -913,10 +946,12 @@ static int __init apparmor_init(void) goto register_security_out; } - if (apparmor_complain) - info_message("AppArmor initialized: complainmode enabled"); - else - info_message("AppArmor initialized"); + /* Report that AppArmor successfully registered but delay + * reporting on success/failure of initialization until apparmorfs + * is created + */ + apparmor_initialized = 1; + info_message("AppArmor registered"); return error; @@ -931,7 +966,31 @@ createfs_out: } -module_init(apparmor_init); +security_initcall(apparmor_init); + +void apparmor_disable(void) +{ + /* Remove and release all the profiles on the profile list. */ + mutex_lock(&aa_interface_lock); + aa_profile_ns_list_release(); + + /* FIXME: cleanup profiles references on files */ + free_default_namespace(); + + /* + * Delay for an rcu cycle to make sure that all active task + * context readers have finished, and all profiles have been + * freed by their rcu callbacks. + */ + synchronize_rcu(); + + destroy_apparmorfs(); + mutex_unlock(&aa_interface_lock); + + apparmor_initialized = 0; + + info_message("AppArmor protection removed"); +} MODULE_DESCRIPTION("AppArmor process confinement"); MODULE_AUTHOR("Novell/Immunix, http://bugs.opensuse.org");