From: Kurt Garloff Subject: Default to capability rather than dummy if no LSM is loaded References: SUSE40217, SUSE39439 If a kernel is compiled with CONFIG_SECURITY to enable LSM, the default behaviour changes unless the admin loads capability. This is undesirable. This patch makes capability the default. capability can still be compiled as module and be loaded as LSM. If loaded as primary LSM, it won't change anything. But it may also be loaded as secondary LSM and stacked on top of another LSM (if the other LSM allows this or if stacker is used). Note that we could think of getting rid of dummy; however, it's still used as fallback for stubs that are not implemented by an LSM. I did not want to change this with this patch set, though I'd like to see it done as a subsequent step if everyone agrees it's a good idea. We'd need to review existing LSMs and see what changes they might need. This is patch 1/3 of the LSM overhaul. Signed-off-by: Kurt Garloff Makefile | 8 +++----- capability.c | 47 +++++++++++++++++++++++------------------------ commoncap.c | 37 +++++++++++++++++++++++++++++++++++++ security.c | 21 ++++++++++++--------- 4 files changed, 75 insertions(+), 38 deletions(-) Index: linux-2.6.12/security/security.c =================================================================== --- linux-2.6.12.orig/security/security.c +++ linux-2.6.12/security/security.c @@ -21,8 +21,9 @@ #define SECURITY_FRAMEWORK_VERSION "1.0.0" /* things that live in dummy.c */ -extern struct security_operations dummy_security_ops; extern void security_fixup_ops(struct security_operations *ops); +/* default security ops */ +extern struct security_operations capability_security_ops; struct security_operations *security_ops; /* Initialized to NULL */ @@ -55,13 +56,15 @@ int __init security_init(void) printk(KERN_INFO "Security Framework v" SECURITY_FRAMEWORK_VERSION " initialized\n"); - if (verify(&dummy_security_ops)) { + if (verify(&capability_security_ops)) { printk(KERN_ERR "%s could not verify " - "dummy_security_ops structure.\n", __FUNCTION__); + "capability_security_ops structure.\n", __FUNCTION__); return -EIO; } - security_ops = &dummy_security_ops; + security_ops = &capability_security_ops; + + /* Initialize compiled-in security modules */ do_security_initcalls(); return 0; @@ -87,7 +90,7 @@ int register_security(struct security_op return -EINVAL; } - if (security_ops != &dummy_security_ops) + if (security_ops != &capability_security_ops) return -EAGAIN; security_ops = ops; @@ -104,18 +107,18 @@ int register_security(struct security_op * * If @ops does not match the valued previously passed to register_security() * an error is returned. Otherwise the default security options is set to the - * the dummy_security_ops structure, and 0 is returned. + * the capability_security_ops structure, and 0 is returned. */ int unregister_security(struct security_operations *ops) { if (ops != security_ops) { printk(KERN_INFO "%s: trying to unregister " - "a security_opts structure that is not " + "a security_ops structure that is not " "registered, failing.\n", __FUNCTION__); return -EINVAL; } - security_ops = &dummy_security_ops; + security_ops = &capability_security_ops; return 0; } Index: linux-2.6.12/security/commoncap.c =================================================================== --- linux-2.6.12.orig/security/commoncap.c +++ linux-2.6.12/security/commoncap.c @@ -325,6 +325,41 @@ int cap_vm_enough_memory(long pages) return __vm_enough_memory(pages, cap_sys_admin); } +#ifdef CONFIG_SECURITY +struct security_operations capability_security_ops = { + .ptrace = cap_ptrace, + .capget = cap_capget, + .capset_check = cap_capset_check, + .capset_set = cap_capset_set, + .capable = cap_capable, + .settime = cap_settime, + .netlink_send = cap_netlink_send, + .netlink_recv = cap_netlink_recv, + + .bprm_apply_creds = cap_bprm_apply_creds, + .bprm_set_security = cap_bprm_set_security, + .bprm_secureexec = cap_bprm_secureexec, + + .inode_setxattr = cap_inode_setxattr, + .inode_removexattr = cap_inode_removexattr, + + .task_post_setuid = cap_task_post_setuid, + .task_reparent_to_init = cap_task_reparent_to_init, + + .syslog = cap_syslog, + + .vm_enough_memory = cap_vm_enough_memory, +}; + +EXPORT_SYMBOL(capability_security_ops); +/* Note: capability_security_ops is the default for security_ops + * now which gets used if no LSM is loaded. + * If capability is loaded, a copy of capability_security_ops + * is registered, so we know whether or not we use a non-default + * security_ops. If we don't, replacement is not possible. + */ +#endif + EXPORT_SYMBOL(cap_capable); EXPORT_SYMBOL(cap_settime); EXPORT_SYMBOL(cap_ptrace); Index: linux-2.6.12/security/Makefile =================================================================== --- linux-2.6.12.orig/security/Makefile +++ linux-2.6.12/security/Makefile @@ -5,15 +5,13 @@ obj-$(CONFIG_KEYS) += keys/ subdir-$(CONFIG_SECURITY_SELINUX) += selinux -# if we don't select a security model, use the default capabilities -ifneq ($(CONFIG_SECURITY),y) +# We always need commoncap as it's default obj-y += commoncap.o -endif # Object file lists obj-$(CONFIG_SECURITY) += security.o dummy.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o -obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o -obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o +obj-$(CONFIG_SECURITY_CAPABILITIES) += capability.o +obj-$(CONFIG_SECURITY_ROOTPLUG) += root_plug.o obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o Index: linux-2.6.12/security/capability.c =================================================================== --- linux-2.6.12.orig/security/capability.c +++ linux-2.6.12/security/capability.c @@ -24,30 +24,28 @@ #include #include -static struct security_operations capability_ops = { - .ptrace = cap_ptrace, - .capget = cap_capget, - .capset_check = cap_capset_check, - .capset_set = cap_capset_set, - .capable = cap_capable, - .settime = cap_settime, - .netlink_send = cap_netlink_send, - .netlink_recv = cap_netlink_recv, - - .bprm_apply_creds = cap_bprm_apply_creds, - .bprm_set_security = cap_bprm_set_security, - .bprm_secureexec = cap_bprm_secureexec, - - .inode_setxattr = cap_inode_setxattr, - .inode_removexattr = cap_inode_removexattr, - - .task_post_setuid = cap_task_post_setuid, - .task_reparent_to_init = cap_task_reparent_to_init, - - .syslog = cap_syslog, - - .vm_enough_memory = cap_vm_enough_memory, -}; +/* Note: Capabilities are default now, even if CONFIG_SECURITY + * is enabled and no LSM is loaded. (Previously, the dummy + * functions would have been called in that case which resulted + * in a slightly unusable system.) + * The capability LSM may still be compiled and loaded; it won't + * make a difference though except for slowing down some operations + * a tiny bit and (more severly) for disallowing loading another LSM. + * To have it as LSM may still be useful: It could be stacked on top + * of another LSM (if the other LSM allows this or if the stacker + * is used). + * If the capability LSM is loaded, we do NOT register the + * capability_security_ops but a second structure capability_ops + * that has identical entries. We need to differentiate + * between capabilities used as default and used as LSM as in + * the latter case replacing it by just loading another LSM is + * not possible. + */ + +/* Struct from commoncaps */ +extern struct security_operations capability_security_ops; +/* Struct to hold the copy */ +static struct security_operations capability_ops; #define MY_NAME __stringify(KBUILD_MODNAME) @@ -64,6 +62,7 @@ static int __init capability_init (void) printk(KERN_INFO "Capabilities disabled at initialization\n"); return 0; } + memcpy(&capability_ops, &capability_security_ops, sizeof(capability_ops)); /* register ourselves with the security framework */ if (register_security (&capability_ops)) { /* try registering with primary module */