@@ -1897,6 +1897,11 @@ struct security_hook_list {
extern void security_add_hooks(struct security_hook_list *hooks, int count,
char *lsm);
+#ifdef CONFIG_SECURITY_DYNAMIC_LOADING
+extern void security_add_hooks_dynamic(struct security_hook_list *hooks,
+ int count, char *lsm);
+#endif
+
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
/*
* Assuring the safety of deleting a security module is up to
@@ -1920,13 +1925,6 @@ static inline void security_delete_hooks(struct security_hook_list *hooks,
}
#endif /* CONFIG_SECURITY_SELINUX_DISABLE */
-/* Currently required to handle SELinux runtime hook disable. */
-#ifdef CONFIG_SECURITY_WRITABLE_HOOKS
-#define __lsm_ro_after_init
-#else
-#define __lsm_ro_after_init __ro_after_init
-#endif /* CONFIG_SECURITY_WRITABLE_HOOKS */
-
extern int __init security_module_enable(const char *module);
extern void __init capability_add_hooks(void);
#ifdef CONFIG_SECURITY_YAMA
@@ -31,10 +31,12 @@ config SECURITY
If you are unsure how to answer this question, answer N.
-config SECURITY_WRITABLE_HOOKS
+config SECURITY_DYNAMIC_LOADING
depends on SECURITY
- bool
+ bool "Allow dynamic registration of LSM modules"
default n
+ help
+ This option allows loadable LSM modules.
config SECURITYFS
bool "Enable the securityfs filesystem"
@@ -587,7 +587,7 @@ static int apparmor_task_setrlimit(struct task_struct *task,
return error;
}
-static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list apparmor_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
LSM_HOOK_INIT(capget, apparmor_capget),
@@ -1071,7 +1071,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot,
#ifdef CONFIG_SECURITY
-struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
+struct security_hook_list capability_hooks[] __ro_after_init = {
LSM_HOOK_INIT(capable, cap_capable),
LSM_HOOK_INIT(settime, cap_settime),
LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check),
@@ -174,7 +174,7 @@ static int loadpin_read_file(struct file *file, enum kernel_read_file_id id)
return 0;
}
-static struct security_hook_list loadpin_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list loadpin_hooks[] __ro_after_init = {
LSM_HOOK_INIT(sb_free_security, loadpin_sb_free_security),
LSM_HOOK_INIT(kernel_read_file, loadpin_read_file),
};
@@ -32,7 +32,13 @@
/* Maximum number of letters for an LSM name string */
#define SECURITY_NAME_MAX 10
-static struct security_hook_heads security_hook_heads __lsm_ro_after_init;
+static struct security_hook_heads security_hook_heads __ro_after_init;
+#ifdef CONFIG_SECURITY_DYNAMIC_LOADING
+static struct security_hook_heads security_hook_heads_dynamic;
+#else
+/* Dummy for hiding build errors. */
+#define security_hook_heads_dynamic security_hook_heads
+#endif
char *lsm_names;
/* Boot-time LSM user choice */
static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1] =
@@ -61,6 +67,12 @@ int __init security_init(void)
for (i = 0; i < sizeof(security_hook_heads) / sizeof(struct list_head);
i++)
INIT_LIST_HEAD(&list[i]);
+#ifdef CONFIG_SECURITY_DYNAMIC_LOADING
+ list = (struct list_head *) &security_hook_heads_dynamic;
+ for (i = 0; i < sizeof(security_hook_heads_dynamic) /
+ sizeof(struct list_head); i++)
+ INIT_LIST_HEAD(&list[i]);
+#endif
pr_info("Security Framework initialized\n");
/*
@@ -143,6 +155,24 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
panic("%s - Cannot get early memory.\n", __func__);
}
+#ifdef CONFIG_SECURITY_DYNAMIC_LOADING
+void security_add_hooks_dynamic(struct security_hook_list *hooks, int count,
+ char *lsm)
+{
+ int i;
+ struct list_head *list =
+ (struct list_head *) &security_hook_heads_dynamic;
+
+ for (i = 0; i < count; i++) {
+ hooks[i].lsm = lsm;
+ list_add_tail_rcu(&hooks[i].list, &list[hooks[i].idx]);
+ }
+ if (lsm_append(lsm, &lsm_names) < 0)
+ panic("%s - Cannot get early memory.\n", __func__);
+}
+EXPORT_SYMBOL_GPL(security_add_hooks_dynamic);
+#endif
+
/*
* Hook list operation macros.
*
@@ -159,6 +189,11 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
\
list_for_each_entry(P, &security_hook_heads.FUNC, list) \
P->hook.FUNC(__VA_ARGS__); \
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING)) \
+ list_for_each_entry(P, \
+ &security_hook_heads_dynamic.FUNC, \
+ list) \
+ P->hook.FUNC(__VA_ARGS__); \
} while (0)
#define call_int_hook(FUNC, IRC, ...) ({ \
@@ -171,6 +206,14 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count,
if (RC != 0) \
break; \
} \
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING)) \
+ list_for_each_entry(P, \
+ &security_hook_heads_dynamic.FUNC, \
+ list) { \
+ RC = P->hook.FUNC(__VA_ARGS__); \
+ if (RC != 0) \
+ break; \
+ } \
} while (0); \
RC; \
})
@@ -280,6 +323,16 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
break;
}
}
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING) && cap_sys_admin)
+ list_for_each_entry(hp,
+ &security_hook_heads_dynamic.vm_enough_memory,
+ list) {
+ rc = hp->hook.vm_enough_memory(mm, pages);
+ if (rc <= 0) {
+ cap_sys_admin = 0;
+ break;
+ }
+ }
return __vm_enough_memory(mm, pages, cap_sys_admin);
}
@@ -768,6 +821,15 @@ int security_inode_getsecurity(struct inode *inode, const char *name, void **buf
if (rc != -EOPNOTSUPP)
return rc;
}
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING))
+ list_for_each_entry(hp,
+ &security_hook_heads_dynamic.inode_getsecurity,
+ list) {
+ rc = hp->hook.inode_getsecurity(inode, name, buffer,
+ alloc);
+ if (rc != -EOPNOTSUPP)
+ return rc;
+ }
return -EOPNOTSUPP;
}
@@ -787,6 +849,15 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void
if (rc != -EOPNOTSUPP)
return rc;
}
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING))
+ list_for_each_entry(hp,
+ &security_hook_heads_dynamic.inode_setsecurity,
+ list) {
+ rc = hp->hook.inode_setsecurity(inode, name, value,
+ size, flags);
+ if (rc != -EOPNOTSUPP)
+ return rc;
+ }
return -EOPNOTSUPP;
}
@@ -1092,6 +1163,17 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
break;
}
}
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING) && rc == -ENOSYS)
+ list_for_each_entry(hp, &security_hook_heads_dynamic.task_prctl,
+ list) {
+ thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4,
+ arg5);
+ if (thisrc != -ENOSYS) {
+ rc = thisrc;
+ if (thisrc != 0)
+ break;
+ }
+ }
return rc;
}
@@ -1562,9 +1644,14 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
*/
list_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match,
list) {
- rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
- break;
+ return hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
}
+ if (IS_ENABLED(CONFIG_SECURITY_DYNAMIC_LOADING))
+ list_for_each_entry(hp,
+ &security_hook_heads_dynamic.xfrm_state_pol_flow_match,
+ list) {
+ return hp->hook.xfrm_state_pol_flow_match(x, xp, fl);
+ }
return rc;
}
@@ -40,7 +40,7 @@ config SECURITY_SELINUX_BOOTPARAM_VALUE
config SECURITY_SELINUX_DISABLE
bool "NSA SELinux runtime disable"
depends on SECURITY_SELINUX
- select SECURITY_WRITABLE_HOOKS
+ select SECURITY_DYNAMIC_LOADING
default n
help
This option enables writing to a selinuxfs node 'disable', which
@@ -52,7 +52,7 @@ config SECURITY_SELINUX_DISABLE
to employ.
NOTE: selecting this option will disable the '__ro_after_init'
- kernel hardening feature for security hooks. Please consider
+ kernel hardening feature for SELinux hooks. Please consider
using the selinux=0 boot parameter instead of enabling this
option.
@@ -6123,7 +6123,7 @@ static int selinux_key_getsecurity(struct key *key, char **_buffer)
#endif
-static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list selinux_hooks[] __ro_after_init = {
LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
@@ -6366,7 +6366,12 @@ static __init int selinux_init(void)
0, SLAB_PANIC, NULL);
avc_init();
+#ifndef CONFIG_SECURITY_SELINUX_DISABLE
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
+#else
+ security_add_hooks_dynamic(selinux_hooks, ARRAY_SIZE(selinux_hooks),
+ "selinux");
+#endif
if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
panic("SELinux: Unable to register AVC netcache callback\n");
@@ -4633,7 +4633,7 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
return 0;
}
-static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list smack_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme),
LSM_HOOK_INIT(syslog, smack_syslog),
@@ -496,7 +496,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg,
* tomoyo_security_ops is a "struct security_operations" which is used for
* registering TOMOYO.
*/
-static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list tomoyo_hooks[] __ro_after_init = {
LSM_HOOK_INIT(cred_alloc_blank, tomoyo_cred_alloc_blank),
LSM_HOOK_INIT(cred_prepare, tomoyo_cred_prepare),
LSM_HOOK_INIT(cred_transfer, tomoyo_cred_transfer),
@@ -428,7 +428,7 @@ int yama_ptrace_traceme(struct task_struct *parent)
return rc;
}
-static struct security_hook_list yama_hooks[] __lsm_ro_after_init = {
+static struct security_hook_list yama_hooks[] __ro_after_init = {
LSM_HOOK_INIT(ptrace_access_check, yama_ptrace_access_check),
LSM_HOOK_INIT(ptrace_traceme, yama_ptrace_traceme),
LSM_HOOK_INIT(task_prctl, yama_task_prctl),