http://lkml.org/lkml/2007/10/23/3 diff -purN include/linux.org/security.h include/linux/security.h --- include/linux.org/security.h 2007-10-21 10:35:49.000000000 +0200 +++ include/linux/security.h 2007-10-21 10:36:00.000000000 +0200 @@ -1178,6 +1178,10 @@ struct request_sock; * allow module stacking. * @name contains the name of the security module being stacked. * @ops contains a pointer to the struct security_operations of the module to stack. + * @unregister_security: + * remove a stacked module. + * @name contains the name of the security module being unstacked. + * @ops contains a pointer to the struct security_operations of the module to unstack. * * @secid_to_secctx: * Convert secid to security context. @@ -1365,6 +1369,8 @@ struct security_operations { /* allow module stacking */ int (*register_security) (const char *name, struct security_operations *ops); + int (*unregister_security) (const char *name, + struct security_operations *ops); void (*d_instantiate) (struct dentry *dentry, struct inode *inode); @@ -1445,7 +1451,9 @@ struct security_operations { /* prototypes */ extern int security_init (void); extern int register_security (struct security_operations *ops); +extern int unregister_security (struct security_operations *ops); extern int mod_reg_security (const char *name, struct security_operations *ops); +extern int mod_unreg_security (const char *name, struct security_operations *ops); extern struct dentry *securityfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); diff -purN security.org/dummy.c security/dummy.c --- security.org/dummy.c 2007-10-21 02:04:21.000000000 +0200 +++ security/dummy.c 2007-10-21 10:36:00.000000000 +0200 @@ -908,6 +908,11 @@ static int dummy_register_security (cons return -EINVAL; } +static int dummy_unregister_security (const char *name, struct security_operations *ops) +{ + return -EINVAL; +} + static void dummy_d_instantiate (struct dentry *dentry, struct inode *inode) { return; @@ -1082,6 +1087,7 @@ void security_fixup_ops (struct security set_to_dummy_if_null(ops, netlink_send); set_to_dummy_if_null(ops, netlink_recv); set_to_dummy_if_null(ops, register_security); + set_to_dummy_if_null(ops, unregister_security); set_to_dummy_if_null(ops, d_instantiate); set_to_dummy_if_null(ops, getprocattr); set_to_dummy_if_null(ops, setprocattr); diff -purN security.org/Kconfig security/Kconfig --- security.org/Kconfig 2007-10-21 02:04:21.000000000 +0200 +++ security/Kconfig 2007-10-21 10:36:14.000000000 +0200 @@ -51,6 +51,20 @@ config SECURITY If you are unsure how to answer this question, answer N. +config SECURITY_MODULAR + bool "Allow loadable security models" + depends on SECURITY + help + This allows you to load and unload security modules at + runtime. + + This option is useful for developers of security modules + or for experimenting with security modules that are not in + your kernel (yet). Note that (un)loading security modules + can be a dangerous situation so use with care. + + If you are unsure how to answer this question, answer N. + config SECURITY_NETWORK bool "Socket and Networking Security Hooks" depends on SECURITY diff -purN security.org/security.c security/security.c --- security.org/security.c 2007-10-21 02:04:21.000000000 +0200 +++ security/security.c 2007-10-21 10:37:41.000000000 +0200 @@ -71,7 +71,8 @@ int __init security_init(void) * * This function is to allow a security module to register itself with the * kernel security subsystem. Some rudimentary checking is done on the @ops - * value passed to this function. + * value passed to this function. A call to unregister_security() should be + * done to remove this security_options structure from the kernel. * * If there is already a security module registered with the kernel, * an error will be returned. Otherwise 0 is returned on success. @@ -121,6 +122,62 @@ int mod_reg_security(const char *name, s return security_ops->register_security(name, ops); } +#ifdef CONFIG_SECURITY_MODULAR +/** + * unregister_security - unregisters a security framework with the kernel + * @ops: a pointer to the struct security_options that is to be registered + * + * This function removes a struct security_operations variable that had + * previously been registered with a successful call to register_security(). + * + * 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. + */ +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 " + "registered, failing.\n", __FUNCTION__); + return -EINVAL; + } + + security_ops = &dummy_security_ops; + + return 0; +} + +/** + * mod_unreg_security - allows a security module registered with mod_reg_security() to be unloaded + * @name: a pointer to a string with the name of the security_options to be removed + * @ops: a pointer to the struct security_options that is to be removed + * + * This function allows security modules that have been successfully registered + * with a call to mod_reg_security() to be unloaded from the system. + * This calls the currently loaded security module's unregister_security() call + * with the @name and @ops variables. + * + * The return value depends on the currently loaded security module, with 0 as + * success. + */ +int mod_unreg_security(const char *name, struct security_operations *ops) +{ + if (ops == security_ops) { + printk(KERN_INFO "%s invalid attempt to unregister " + " primary security ops.\n", __FUNCTION__); + return -EINVAL; + } + + return security_ops->unregister_security(name, ops); +} + +EXPORT_SYMBOL_GPL(register_security); +EXPORT_SYMBOL_GPL(unregister_security); +EXPORT_SYMBOL_GPL(mod_reg_security); +EXPORT_SYMBOL_GPL(mod_unreg_security); +#endif + /* Security operations */ int security_ptrace(struct task_struct *parent, struct task_struct *child) diff -purN security.org/selinux/hooks.c security/selinux/hooks.c --- security.org/selinux/hooks.c 2007-10-21 02:04:21.000000000 +0200 +++ security/selinux/hooks.c 2007-10-21 10:38:27.000000000 +0200 @@ -4549,6 +4549,19 @@ static int selinux_register_security (co return 0; } +static int selinux_unregister_security (const char *name, struct security_operations *ops) +{ + if (ops != secondary_ops) { + printk(KERN_ERR "%s: trying to unregister a security module " + "that is not registered.\n", __FUNCTION__); + return -EINVAL; + } + + secondary_ops = original_ops; + + return 0; +} + static void selinux_d_instantiate (struct dentry *dentry, struct inode *inode) { if (inode) @@ -4895,6 +4908,7 @@ static struct security_operations selinu .sem_semop = selinux_sem_semop, .register_security = selinux_register_security, + .unregister_security = selinux_unregister_security, .d_instantiate = selinux_d_instantiate,