From patchwork Wed Dec 11 14:08:33 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ondrej Mosnacek X-Patchwork-Id: 11285067 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 16255112B for ; Wed, 11 Dec 2019 14:08:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CB9AC214AF for ; Wed, 11 Dec 2019 14:08:46 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HjEqV9hu" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729672AbfLKOIq (ORCPT ); Wed, 11 Dec 2019 09:08:46 -0500 Received: from us-smtp-delivery-1.mimecast.com ([205.139.110.120]:29646 "EHLO us-smtp-1.mimecast.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727851AbfLKOIq (ORCPT ); Wed, 11 Dec 2019 09:08:46 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1576073323; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=H4PTU/VZ6QOrc57J1tK+3fRtILxQ1z8yE1iJ8msPHhw=; b=HjEqV9huTUHpyjJOw/Gamike3gwUlOty5+1R7a28G6DqbstkZvwdgyTbKwBN7cOFo+fGQy xIHh4iHxY8ddAzEg3FwfjN6z0OQ27zdoinUyCPISs8CB2vf5jWDgp0YxSDqYzFpHvyIbpP JI8ICucvboperm1bUTb96FHe41XDFeU= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-360-I96mcZ-rN2iQgYaGAvGvEQ-1; Wed, 11 Dec 2019 09:08:42 -0500 Received: by mail-wm1-f72.google.com with SMTP id t17so465562wmi.7 for ; Wed, 11 Dec 2019 06:08:41 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=GuIH2pantDoiRE9SB/uN49xudXYp2Zj+GzS3BieWPQA=; b=Gg7uuJF1jnYAwhiz3N+bFcBRmUdIoBZ6yKCFhXq1XXcqQGLmelJdBs0b0tLhvfYTA3 E2/mJ5niIioCz3dTe4Wr9gV/zOcKzMNNHf3241BTnlxSqD2upp/ZbqBZT0Nr7dJ/9QIU 9ijjJ8Th24BMF1iNzc3RQOm3TGp9axwsi2InJboerVcV5/YudP7x7N/MeXFnwXmBn+Dt Azz/lL8ppKS8w2UOObzBN4Hc8B9KNTif2UOEO4FBy6WbEuyE0Nb5YmQSQ1iR89r1nGYz rpT7AXa4yeNddIZZXBgyPmzEskauc8z2kA/8ojTX36zGR8Q9YJ/870d5nIxThnEadQgk MyCg== X-Gm-Message-State: APjAAAXNme1kMqeOD/6wWayjo/p91WCoiNBIiRnTN8j0Vfl6WgpsNnmy Uu4BtuScFCZ69cacg/Wc0TStOJTdoM37rpcaHN/xYEIWgpCmdWF7Q8KrgYyXcDZ4345oXxKvPi+ R7dStUUgA/XOp2BaF7okg3r1CNEeWT6GyC3Gi X-Received: by 2002:adf:dc8d:: with SMTP id r13mr4238119wrj.357.1576073317563; Wed, 11 Dec 2019 06:08:37 -0800 (PST) X-Google-Smtp-Source: APXvYqyOV645Oa5Skcbxwau1tX0UNzZp8d0hi4lM9/cXYgg/NoClQTixaaGiM3KxFNe+aqC0XAbUUg== X-Received: by 2002:adf:dc8d:: with SMTP id r13mr4238044wrj.357.1576073316810; Wed, 11 Dec 2019 06:08:36 -0800 (PST) Received: from localhost.localdomain.com (nat-pool-brq-t.redhat.com. [213.175.37.10]) by smtp.gmail.com with ESMTPSA id n129sm5945315wmb.1.2019.12.11.06.08.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 11 Dec 2019 06:08:36 -0800 (PST) From: Ondrej Mosnacek To: linux-security-module@vger.kernel.org, James Morris , "Serge E. Hallyn" Cc: Casey Schaufler , selinux@vger.kernel.org, Paul Moore , Stephen Smalley , John Johansen , Kees Cook , Micah Morton , Tetsuo Handa Subject: [PATCH] LSM: allow an LSM to disable all hooks at once Date: Wed, 11 Dec 2019 15:08:33 +0100 Message-Id: <20191211140833.939845-1-omosnace@redhat.com> X-Mailer: git-send-email 2.23.0 MIME-Version: 1.0 X-MC-Unique: I96mcZ-rN2iQgYaGAvGvEQ-1 X-Mimecast-Spam-Score: 0 Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: Instead of deleting the hooks from each list one-by-one (which creates some bad race conditions), allow an LSM to provide a reference to its "enabled" variable and check this variable before calling the hook. As a nice side effect, this allows marking the hooks (and other stuff) __ro_after_init unconditionally. Since SECURITY_WRITABLE_HOOKS no longer makes sense, remove it and instead use SECURITY_SELINUX_DISABLE directly for turning on the runtime disable functionality, to emphasize that this is only used by SELinux and is meant to be removed in the future. Fixes: b1d9e6b0646d ("LSM: Switch to lists of hooks") Signed-off-by: Ondrej Mosnacek --- This is an alternative to [1]. It turned out to be less simple than I had hoped, but OTOH the hook arrays can now be unconditionally made __ro_after_init so may be still worth it. Compile- and boot- tested with SECURITY_SELINUX_DISABLE set to =y and =n; SELinux enabled. Changes to other LSMs only compile-tested (but those are trivial). [1] https://lore.kernel.org/selinux/20191209075756.123157-1-omosnace@redhat.com/T/ include/linux/lsm_hooks.h | 46 +++++++++---------------------- security/Kconfig | 5 ---- security/apparmor/lsm.c | 14 ++++++---- security/commoncap.c | 11 +++++--- security/loadpin/loadpin.c | 10 +++++-- security/lockdown/lockdown.c | 11 +++++--- security/safesetid/lsm.c | 9 +++++-- security/security.c | 52 +++++++++++++++++++++--------------- security/selinux/Kconfig | 5 ++-- security/selinux/hooks.c | 28 ++++++++++++++----- security/smack/smack_lsm.c | 11 +++++--- security/tomoyo/tomoyo.c | 13 ++++++--- security/yama/yama_lsm.c | 10 +++++-- 13 files changed, 133 insertions(+), 92 deletions(-) diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 20d8cf194fb7..91b77ebcb822 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -27,7 +27,6 @@ #include #include -#include /** * union security_list_options - Linux Security Module hook function list @@ -2086,6 +2085,9 @@ struct security_hook_list { struct hlist_head *head; union security_list_options hook; char *lsm; +#ifdef CONFIG_SECURITY_SELINUX_DISABLE + const int *enabled; +#endif } __randomize_layout; /* @@ -2112,8 +2114,16 @@ struct lsm_blob_sizes { extern struct security_hook_heads security_hook_heads; extern char *lsm_names; -extern void security_add_hooks(struct security_hook_list *hooks, int count, - char *lsm); +struct security_hook_array { + struct security_hook_list *hooks; + int count; + char *lsm; +#ifdef CONFIG_SECURITY_SELINUX_DISABLE + const int *enabled; +#endif +}; + +extern void security_add_hook_array(const struct security_hook_array *array); #define LSM_FLAG_LEGACY_MAJOR BIT(0) #define LSM_FLAG_EXCLUSIVE BIT(1) @@ -2145,36 +2155,6 @@ extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[]; __used __section(.early_lsm_info.init) \ __aligned(sizeof(unsigned long)) -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -/* - * Assuring the safety of deleting a security module is up to - * the security module involved. This may entail ordering the - * module's hook list in a particular way, refusing to disable - * the module once a policy is loaded or any number of other - * actions better imagined than described. - * - * The name of the configuration option reflects the only module - * that currently uses the mechanism. Any developer who thinks - * disabling their module is a good idea needs to be at least as - * careful as the SELinux team. - */ -static inline void security_delete_hooks(struct security_hook_list *hooks, - int count) -{ - int i; - - for (i = 0; i < count; i++) - hlist_del_rcu(&hooks[i].list); -} -#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 lsm_inode_alloc(struct inode *inode); #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/security/Kconfig b/security/Kconfig index 2a1a2d396228..456764990a13 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -32,11 +32,6 @@ config SECURITY If you are unsure how to answer this question, answer N. -config SECURITY_WRITABLE_HOOKS - depends on SECURITY - bool - default n - config SECURITYFS bool "Enable the securityfs filesystem" help diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index b621ad74f54a..a27f48670b37 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -1158,13 +1158,13 @@ static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb, /* * The cred blob is a pointer to, not an instance of, an aa_task_ctx. */ -struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct aa_task_ctx *), .lbs_file = sizeof(struct aa_file_ctx), .lbs_task = sizeof(struct aa_task_ctx), }; -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), @@ -1368,7 +1368,7 @@ static const struct kernel_param_ops param_ops_aaintbool = { .get = param_get_aaintbool }; /* Boot time disable flag */ -static int apparmor_enabled __lsm_ro_after_init = 1; +static int apparmor_enabled __ro_after_init = 1; module_param_named(enabled, apparmor_enabled, aaintbool, 0444); static int __init apparmor_enabled_setup(char *str) @@ -1829,6 +1829,11 @@ __initcall(apparmor_nf_ip_init); static int __init apparmor_init(void) { + struct security_hook_array hook_array = { + .hooks = apparmor_hooks, + .count = ARRAY_SIZE(apparmor_hooks), + .lsm = "apparmor", + }; int error; aa_secids_init(); @@ -1864,8 +1869,7 @@ static int __init apparmor_init(void) aa_free_root_ns(); goto buffers_out; } - security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks), - "apparmor"); + security_add_hook_array(&hook_array); /* Report that AppArmor successfully initialized */ apparmor_initialized = 1; diff --git a/security/commoncap.c b/security/commoncap.c index f4ee0ae106b2..6e9f4b6b6b1d 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -1339,7 +1339,7 @@ int cap_mmap_file(struct file *file, unsigned long reqprot, #ifdef CONFIG_SECURITY -static struct security_hook_list capability_hooks[] __lsm_ro_after_init = { +static 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), @@ -1362,8 +1362,13 @@ static struct security_hook_list capability_hooks[] __lsm_ro_after_init = { static int __init capability_init(void) { - security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks), - "capability"); + struct security_hook_array hook_array = { + .hooks = capability_hooks, + .count = ARRAY_SIZE(capability_hooks), + .lsm = "capability", + }; + + security_add_hook_array(&hook_array); return 0; } diff --git a/security/loadpin/loadpin.c b/security/loadpin/loadpin.c index ee5cb944f4ad..5fadd4969d90 100644 --- a/security/loadpin/loadpin.c +++ b/security/loadpin/loadpin.c @@ -180,7 +180,7 @@ static int loadpin_load_data(enum kernel_load_data_id id) return loadpin_read_file(NULL, (enum kernel_read_file_id) id); } -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), LSM_HOOK_INIT(kernel_load_data, loadpin_load_data), @@ -224,10 +224,16 @@ static void __init parse_exclude(void) static int __init loadpin_init(void) { + struct security_hook_array hook_array = { + .hooks = loadpin_hooks, + .count = ARRAY_SIZE(loadpin_hooks), + .lsm = "loadpin", + }; + pr_info("ready to pin (currently %senforcing)\n", enforce ? "" : "not "); parse_exclude(); - security_add_hooks(loadpin_hooks, ARRAY_SIZE(loadpin_hooks), "loadpin"); + security_add_hook_array(&hook_array); return 0; } diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c index 5a952617a0eb..bcfa0ff4ee63 100644 --- a/security/lockdown/lockdown.c +++ b/security/lockdown/lockdown.c @@ -71,19 +71,24 @@ static int lockdown_is_locked_down(enum lockdown_reason what) return 0; } -static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = { +static struct security_hook_list lockdown_hooks[] __ro_after_init = { LSM_HOOK_INIT(locked_down, lockdown_is_locked_down), }; static int __init lockdown_lsm_init(void) { + struct security_hook_array hook_array = { + .hooks = lockdown_hooks, + .count = ARRAY_SIZE(lockdown_hooks), + .lsm = "lockdown", + }; + #if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY) lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY_MAX); #elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY) lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY_MAX); #endif - security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks), - "lockdown"); + security_add_hook_array(&hook_array); return 0; } diff --git a/security/safesetid/lsm.c b/security/safesetid/lsm.c index 7760019ad35d..4e36e53f033d 100644 --- a/security/safesetid/lsm.c +++ b/security/safesetid/lsm.c @@ -156,8 +156,13 @@ static struct security_hook_list safesetid_security_hooks[] = { static int __init safesetid_security_init(void) { - security_add_hooks(safesetid_security_hooks, - ARRAY_SIZE(safesetid_security_hooks), "safesetid"); + struct security_hook_array hook_array = { + .hooks = safesetid_security_hooks, + .count = ARRAY_SIZE(safesetid_security_hooks), + .lsm = "safesetid", + }; + + security_add_hook_array(&hook_array); /* Report that SafeSetID successfully initialized */ safesetid_initialized = 1; diff --git a/security/security.c b/security/security.c index 2b5473d92416..a5dd348bd37e 100644 --- a/security/security.c +++ b/security/security.c @@ -68,14 +68,14 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX+1] = { [LOCKDOWN_CONFIDENTIALITY_MAX] = "confidentiality", }; -struct security_hook_heads security_hook_heads __lsm_ro_after_init; +struct security_hook_heads security_hook_heads __ro_after_init; static BLOCKING_NOTIFIER_HEAD(blocking_lsm_notifier_chain); static struct kmem_cache *lsm_file_cache; static struct kmem_cache *lsm_inode_cache; char *lsm_names; -static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; +static struct lsm_blob_sizes blob_sizes __ro_after_init; /* Boot-time LSM user choice */ static __initdata const char *chosen_lsm_order; @@ -467,20 +467,20 @@ static int lsm_append(const char *new, char **result) /** * security_add_hooks - Add a modules hooks to the hook lists. - * @hooks: the hooks to add - * @count: the number of hooks to add - * @lsm: the name of the security module + * @array: the struct describing hooks to add * * Each LSM has to register its hooks with the infrastructure. */ -void __init security_add_hooks(struct security_hook_list *hooks, int count, - char *lsm) +void __init security_add_hook_array(const struct security_hook_array *array) { int i; - for (i = 0; i < count; i++) { - hooks[i].lsm = lsm; - hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); + for (i = 0; i < array->count; i++) { + array->hooks[i].lsm = array->lsm; +#ifdef CONFIG_SECURITY_SELINUX_DISABLE + array->hooks[i].enabled = array->enabled; +#endif + hlist_add_tail_rcu(&array->hooks[i].list, array->hooks[i].head); } /* @@ -488,7 +488,7 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, * and fix this up afterwards. */ if (slab_is_available()) { - if (lsm_append(lsm, &lsm_names) < 0) + if (lsm_append(array->lsm, &lsm_names) < 0) panic("%s - Cannot get early memory.\n", __func__); } } @@ -679,11 +679,22 @@ static void __init lsm_early_task(struct task_struct *task) * This is a hook that returns a value. */ +#define for_each_hook(p, func) \ + hlist_for_each_entry(p, &security_hook_heads.func, list) + +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +#define for_each_enabled_hook(p, func) \ + for_each_hook(p, func) \ + if (!(p)->enabled || READ_ONCE(*(p)->enabled)) +#else +#define for_each_enabled_hook for_each_hook +#endif + #define call_void_hook(FUNC, ...) \ do { \ struct security_hook_list *P; \ \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) \ + for_each_enabled_hook(P, FUNC) \ P->hook.FUNC(__VA_ARGS__); \ } while (0) @@ -692,7 +703,7 @@ static void __init lsm_early_task(struct task_struct *task) do { \ struct security_hook_list *P; \ \ - hlist_for_each_entry(P, &security_hook_heads.FUNC, list) { \ + for_each_enabled_hook(P, FUNC) { \ RC = P->hook.FUNC(__VA_ARGS__); \ if (RC != 0) \ break; \ @@ -795,7 +806,7 @@ int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) * agree that it should be set it will. If any module * thinks it should not be set it won't. */ - hlist_for_each_entry(hp, &security_hook_heads.vm_enough_memory, list) { + for_each_enabled_hook(hp, vm_enough_memory) { rc = hp->hook.vm_enough_memory(mm, pages); if (rc <= 0) { cap_sys_admin = 0; @@ -1343,7 +1354,7 @@ int security_inode_getsecurity(struct inode *inode, const char *name, void **buf /* * Only one module will provide an attribute with a given name. */ - hlist_for_each_entry(hp, &security_hook_heads.inode_getsecurity, list) { + for_each_enabled_hook(hp, inode_getsecurity) { rc = hp->hook.inode_getsecurity(inode, name, buffer, alloc); if (rc != -EOPNOTSUPP) return rc; @@ -1361,7 +1372,7 @@ int security_inode_setsecurity(struct inode *inode, const char *name, const void /* * Only one module will provide an attribute with a given name. */ - hlist_for_each_entry(hp, &security_hook_heads.inode_setsecurity, list) { + for_each_enabled_hook(hp, inode_setsecurity) { rc = hp->hook.inode_setsecurity(inode, name, value, size, flags); if (rc != -EOPNOTSUPP) @@ -1744,7 +1755,7 @@ int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, int rc = -ENOSYS; struct security_hook_list *hp; - hlist_for_each_entry(hp, &security_hook_heads.task_prctl, list) { + for_each_enabled_hook(hp, task_prctl) { thisrc = hp->hook.task_prctl(option, arg2, arg3, arg4, arg5); if (thisrc != -ENOSYS) { rc = thisrc; @@ -1913,7 +1924,7 @@ int security_getprocattr(struct task_struct *p, const char *lsm, char *name, { struct security_hook_list *hp; - hlist_for_each_entry(hp, &security_hook_heads.getprocattr, list) { + for_each_enabled_hook(hp, getprocattr) { if (lsm != NULL && strcmp(lsm, hp->lsm)) continue; return hp->hook.getprocattr(p, name, value); @@ -1926,7 +1937,7 @@ int security_setprocattr(const char *lsm, const char *name, void *value, { struct security_hook_list *hp; - hlist_for_each_entry(hp, &security_hook_heads.setprocattr, list) { + for_each_enabled_hook(hp, setprocattr) { if (lsm != NULL && strcmp(lsm, hp->lsm)) continue; return hp->hook.setprocattr(name, value, size); @@ -2327,8 +2338,7 @@ int security_xfrm_state_pol_flow_match(struct xfrm_state *x, * For speed optimization, we explicitly break the loop rather than * using the macro */ - hlist_for_each_entry(hp, &security_hook_heads.xfrm_state_pol_flow_match, - list) { + for_each_enabled_hook(hp, xfrm_state_pol_flow_match) { rc = hp->hook.xfrm_state_pol_flow_match(x, xp, fl); break; } diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig index 996d35d950f7..f64290de1f8a 100644 --- a/security/selinux/Kconfig +++ b/security/selinux/Kconfig @@ -26,7 +26,6 @@ config SECURITY_SELINUX_BOOTPARAM config SECURITY_SELINUX_DISABLE bool "NSA SELinux runtime disable" depends on SECURITY_SELINUX - select SECURITY_WRITABLE_HOOKS default n help This option enables writing to a selinuxfs node 'disable', which @@ -37,8 +36,8 @@ config SECURITY_SELINUX_DISABLE portability across platforms where boot parameters are difficult to employ. - NOTE: selecting this option will disable the '__ro_after_init' - kernel hardening feature for security hooks. Please consider + NOTE: Selecting this option might cause memory leaks and random + crashes when the runtime disable is used. Please consider using the selinux=0 boot parameter instead of enabling this option. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 47626342b6e5..b76acd98dda5 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -123,7 +123,13 @@ __setup("enforcing=", enforcing_setup); #define selinux_enforcing_boot 1 #endif -int selinux_enabled __lsm_ro_after_init = 1; +/* Currently required to handle SELinux runtime hook disable. */ +#ifdef CONFIG_SECURITY_SELINUX_DISABLE +int selinux_enabled = 1; +#else +int selinux_enabled __ro_after_init = 1; +#endif /* CONFIG_SECURITY_SELINUX_DISABLE */ + #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM static int __init selinux_enabled_setup(char *str) { @@ -6827,7 +6833,7 @@ static int selinux_lockdown(enum lockdown_reason what) LOCKDOWN__CONFIDENTIALITY, &ad); } -struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct task_security_struct), .lbs_file = sizeof(struct file_security_struct), .lbs_inode = sizeof(struct inode_security_struct), @@ -6896,7 +6902,7 @@ static int selinux_perf_event_write(struct perf_event *event) } #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), @@ -7145,6 +7151,15 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { static __init int selinux_init(void) { + struct security_hook_array hook_array = { + .hooks = selinux_hooks, + .count = ARRAY_SIZE(selinux_hooks), + .lsm = "selinux", +#ifdef CONFIG_SECURITY_SELINUX_DISABLE + .enabled = &selinux_enabled, +#endif + }; + pr_info("SELinux: Initializing.\n"); memset(&selinux_state, 0, sizeof(selinux_state)); @@ -7166,7 +7181,7 @@ static __init int selinux_init(void) hashtab_cache_init(); - security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); + security_add_hook_array(&hook_array); if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) panic("SELinux: Unable to register AVC netcache callback\n"); @@ -7319,9 +7334,10 @@ int selinux_disable(struct selinux_state *state) pr_info("SELinux: Disabled at runtime.\n"); - selinux_enabled = 0; + /* Unregister netfilter hooks. */ + selinux_nf_ip_exit(); - security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); + WRITE_ONCE(selinux_enabled, 0); /* Try to destroy the avc node cache */ avc_disable(); diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index ecea41ce919b..c21dda12bc4b 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -4583,7 +4583,7 @@ static int smack_dentry_create_files_as(struct dentry *dentry, int mode, return 0; } -struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes smack_blob_sizes __ro_after_init = { .lbs_cred = sizeof(struct task_smack), .lbs_file = sizeof(struct smack_known *), .lbs_inode = sizeof(struct inode_smack), @@ -4591,7 +4591,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { .lbs_msg_msg = sizeof(struct smack_known *), }; -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), @@ -4765,6 +4765,11 @@ static __init void init_smack_known_list(void) */ static __init int smack_init(void) { + struct security_hook_array hook_array = { + .hooks = smack_hooks, + .count = ARRAY_SIZE(smack_hooks), + .lsm = "smack", + }; struct cred *cred = (struct cred *) current->cred; struct task_smack *tsp; @@ -4787,7 +4792,7 @@ static __init int smack_init(void) /* * Register with LSM */ - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); + security_add_hook_array(&hook_array); smack_enabled = 1; pr_info("Smack: Initializing.\n"); diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 716c92ec941a..a4075379246d 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -486,7 +486,7 @@ static int tomoyo_socket_sendmsg(struct socket *sock, struct msghdr *msg, return tomoyo_socket_sendmsg_permission(sock, msg, size); } -struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { +struct lsm_blob_sizes tomoyo_blob_sizes __ro_after_init = { .lbs_task = sizeof(struct tomoyo_task), }; @@ -533,7 +533,7 @@ static void tomoyo_task_free(struct task_struct *task) * 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_prepare, tomoyo_cred_prepare), LSM_HOOK_INIT(bprm_committed_creds, tomoyo_bprm_committed_creds), LSM_HOOK_INIT(task_alloc, tomoyo_task_alloc), @@ -569,7 +569,7 @@ static struct security_hook_list tomoyo_hooks[] __lsm_ro_after_init = { /* Lock for GC. */ DEFINE_SRCU(tomoyo_ss); -int tomoyo_enabled __lsm_ro_after_init = 1; +int tomoyo_enabled __ro_after_init = 1; /** * tomoyo_init - Register TOMOYO Linux as a LSM module. @@ -578,10 +578,15 @@ int tomoyo_enabled __lsm_ro_after_init = 1; */ static int __init tomoyo_init(void) { + struct security_hook_array hook_array = { + .hooks = tomoyo_hooks, + .count = ARRAY_SIZE(tomoyo_hooks), + .lsm = "tomoyo", + }; struct tomoyo_task *s = tomoyo_task(current); /* register ourselves with the security framework */ - security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); + security_add_hook_array(&hook_array); pr_info("TOMOYO Linux initialized\n"); s->domain_info = &tomoyo_kernel_domain; atomic_inc(&tomoyo_kernel_domain.users); diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 94dc346370b1..ed752f6eafcf 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -421,7 +421,7 @@ static 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), @@ -476,8 +476,14 @@ static inline void yama_init_sysctl(void) { } static int __init yama_init(void) { + struct security_hook_array hook_array = { + .hooks = yama_hooks, + .count = ARRAY_SIZE(yama_hooks), + .lsm = "yama", + }; + pr_info("Yama: becoming mindful.\n"); - security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks), "yama"); + security_add_hook_array(&hook_array); yama_init_sysctl(); return 0; }