From patchwork Tue May 21 22:40:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10954559 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 456D717D2 for ; Tue, 21 May 2019 22:40:30 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 34CBC289A3 for ; Tue, 21 May 2019 22:40:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 291C428A09; Tue, 21 May 2019 22:40:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 8B307289A3 for ; Tue, 21 May 2019 22:40:29 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727424AbfEUWk2 (ORCPT ); Tue, 21 May 2019 18:40:28 -0400 Received: from mail-ot1-f74.google.com ([209.85.210.74]:38045 "EHLO mail-ot1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727015AbfEUWkT (ORCPT ); Tue, 21 May 2019 18:40:19 -0400 Received: by mail-ot1-f74.google.com with SMTP id x23so248242otp.5 for ; Tue, 21 May 2019 15:40:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=hGPKA9QoScUdBbJ7le3fhZSr13IA+IrjO6JtRN49sNw=; b=hY3ZSvFrQqrRfKxS7416nT4FjMeOL8gX56biDa7FBpjErp4VxDCH4pKzy9TSMDpPSp L91KoEvLZiGceYydSd+7y5Aeq3WoBUGi22u+cftcCgx8Ly1OMXoSwHoZfEl2duWiuS9A P6HYV+6+IpetPK70wo+dU6nmMhur0PypRzBcGfNvf6F8BwUWT7gEBxpR/M79ILeRRJpX uaGcJZreCrZAgsSPR1uXFfz6Y6Zd98ste9+7s/EOHYs+BtsMmPpJfAS9GWm9tKvnwYXh MTYYkFCWEgI2x1VIkHiKz60bcsdSI8OFqDSYYFw8PWj27oynzkO4OvY8lajOcBRbcyFK ulkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=hGPKA9QoScUdBbJ7le3fhZSr13IA+IrjO6JtRN49sNw=; b=gupFZQx1boC3hBv8xrv0jWAuNJiA2SPN0b003d+MhEL6ZDwQSxd8XbOu/oEl811l41 yIveQ5iPAQRXXri8EJ1+F6BcBvyDOASZHJky2fXf9tL82K2Ulcf0BBKTp76TyFHYyy4M eUHQ7r33iokEbFX0UjCHawBedzZPDDTV9JbiZ0j23Le2yiEQW4W7dgxgrOYoeNTeCfPZ Ug1qc3ywNcVE/d8DhtSsQ/cpt5bzxaApaqZqvcCSwbEUuIj2rW4EigbCtJMPnUhyNAWV 4MYud0NtnJl5pO2x873MREoG+ZMZZ9AOyrehrTNnCdgDjaU2hzMhm7DuBqMOlJTSTDZx 3HRg== X-Gm-Message-State: APjAAAXjLlbBWISh7EbuCTuCAGZZWFdbgRUJFopsI7RyzReZQlzuTfj7 xWxDOo/eWU0F0ICGCPXssv3sSbIhWdi7D9Bs0ruo+g== X-Google-Smtp-Source: APXvYqx1uOSBnWtC4Ju8Idb9d0bpSG6Hfy/yeDZ0RBK+IsJMTGchForXcH04lZdBPUuLZRu86OFHcUoIGyEx/SvJk+8lYg== X-Received: by 2002:aca:cd0a:: with SMTP id d10mr5144145oig.1.1558478418568; Tue, 21 May 2019 15:40:18 -0700 (PDT) Date: Tue, 21 May 2019 15:40:12 -0700 In-Reply-To: <20190521224013.3782-1-matthewgarrett@google.com> Message-Id: <20190521224013.3782-2-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190521224013.3782-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [RFC 1/2] security: Support early LSMs From: Matthew Garrett To: jmorris@namei.org Cc: linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, Matthew Garrett , Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP The lockdown module is intended to allow for kernels to be locked down early in boot - sufficiently early that we don't have the ability to kmalloc() yet. Add support for early initialisation of some LSMs, and then add them to the list of names when we do full initialisation later. Signed-off-by: Matthew Garrett --- include/asm-generic/vmlinux.lds.h | 8 +++++- include/linux/lsm_hooks.h | 6 ++++ include/linux/security.h | 1 + init/main.c | 1 + security/security.c | 48 +++++++++++++++++++++++++------ 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3d7a6a9c2370..e9761ed1f5b3 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -208,8 +208,13 @@ __start_lsm_info = .; \ KEEP(*(.lsm_info.init)) \ __end_lsm_info = .; +#define EARLY_LSM_TABLE() . = ALIGN(8); \ + __start_early_lsm_info = .; \ + KEEP(*(.early_lsm_info.init)) \ + __end_early_lsm_info = .; #else #define LSM_TABLE() +#define EARLY_LSM_TABLE() #endif #define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) @@ -610,7 +615,8 @@ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(timer) \ EARLYCON_TABLE() \ - LSM_TABLE() + LSM_TABLE() \ + EARLY_LSM_TABLE() #define INIT_TEXT \ *(.init.text .init.text.*) \ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 22fc786d723a..1a841d134e05 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -2074,12 +2074,18 @@ struct lsm_info { }; extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; +extern struct lsm_info __start_early_lsm_info[], __end_early_lsm_info[]; #define DEFINE_LSM(lsm) \ static struct lsm_info __lsm_##lsm \ __used __section(.lsm_info.init) \ __aligned(sizeof(unsigned long)) +#define DEFINE_EARLY_LSM(lsm) \ + static struct lsm_info __early_lsm_##lsm \ + __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 diff --git a/include/linux/security.h b/include/linux/security.h index 13537a49ae97..f4363a1339a8 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -191,6 +191,7 @@ int unregister_lsm_notifier(struct notifier_block *nb); /* prototypes */ extern int security_init(void); +extern int early_security_init(void); /* Security operations */ int security_binder_set_context_mgr(struct task_struct *mgr); diff --git a/init/main.c b/init/main.c index e2e80ca3165a..6bdceaaeddbd 100644 --- a/init/main.c +++ b/init/main.c @@ -555,6 +555,7 @@ asmlinkage __visible void __init start_kernel(void) boot_cpu_init(); page_address_init(); pr_notice("%s", linux_banner); + early_security_init(); setup_arch(&command_line); /* * Set up the the initial canary and entropy after arch diff --git a/security/security.c b/security/security.c index ed9b8cbf21cf..e3a7d4e96541 100644 --- a/security/security.c +++ b/security/security.c @@ -37,6 +37,7 @@ /* How many LSMs were built into the kernel? */ #define LSM_COUNT (__end_lsm_info - __start_lsm_info) +#define EARLY_LSM_COUNT (__end_early_lsm_info - __start_early_lsm_info) struct security_hook_heads security_hook_heads __lsm_ro_after_init; static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); @@ -281,6 +282,8 @@ static void __init ordered_lsm_parse(const char *order, const char *origin) static void __init lsm_early_cred(struct cred *cred); static void __init lsm_early_task(struct task_struct *task); +static int lsm_append(const char *new, char **result); + static void __init ordered_lsm_init(void) { struct lsm_info **lsm; @@ -327,15 +330,11 @@ static void __init ordered_lsm_init(void) kfree(ordered_lsms); } -/** - * security_init - initializes the security framework - * - * This should be called early in the kernel initialization sequence. - */ -int __init security_init(void) +int __init early_security_init(void) { int i; struct hlist_head *list = (struct hlist_head *) &security_hook_heads; + struct lsm_info *lsm; pr_info("Security Framework initializing\n"); @@ -343,6 +342,30 @@ int __init security_init(void) i++) INIT_HLIST_HEAD(&list[i]); + for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { + if (!lsm->enabled) + lsm->enabled = &lsm_enabled_true; + initialize_lsm(lsm); + } + + return 0; +} + +/** + * security_init - initializes the security framework + * + * This should be called early in the kernel initialization sequence. + */ +int __init security_init(void) +{ + struct lsm_info *lsm; + + /* Append the names of the early LSM modules now */ + for (lsm = __start_early_lsm_info; lsm < __end_early_lsm_info; lsm++) { + if (lsm->enabled) + lsm_append(lsm->name, &lsm_names); + } + /* Load LSMs in specified order. */ ordered_lsm_init(); @@ -388,7 +411,7 @@ static bool match_last_lsm(const char *list, const char *lsm) return !strcmp(last, lsm); } -static int lsm_append(char *new, char **result) +static int lsm_append(const char *new, char **result) { char *cp; @@ -426,8 +449,15 @@ void __init security_add_hooks(struct security_hook_list *hooks, int count, hooks[i].lsm = lsm; hlist_add_tail_rcu(&hooks[i].list, hooks[i].head); } - if (lsm_append(lsm, &lsm_names) < 0) - panic("%s - Cannot get early memory.\n", __func__); + + /* + * Don't try to append during early_security_init(), we'll come back + * and fix this up afterwards. + */ + if (slab_is_available()) { + if (lsm_append(lsm, &lsm_names) < 0) + panic("%s - Cannot get early memory.\n", __func__); + } } int call_lsm_notifier(enum lsm_event event, void *data) From patchwork Tue May 21 22:40:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthew Garrett X-Patchwork-Id: 10954557 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id B13D6924 for ; Tue, 21 May 2019 22:40:29 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 98C61289F7 for ; Tue, 21 May 2019 22:40:29 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 8910828A09; Tue, 21 May 2019 22:40:29 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,RCVD_IN_DNSWL_HI,USER_IN_DEF_DKIM_WL autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 61B62289F7 for ; Tue, 21 May 2019 22:40:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727453AbfEUWkW (ORCPT ); Tue, 21 May 2019 18:40:22 -0400 Received: from mail-ot1-f74.google.com ([209.85.210.74]:36386 "EHLO mail-ot1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726017AbfEUWkV (ORCPT ); Tue, 21 May 2019 18:40:21 -0400 Received: by mail-ot1-f74.google.com with SMTP id f92so251518otb.3 for ; Tue, 21 May 2019 15:40:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=8SqzjktYdSolKelsIc3Thg9RmyEnmv2PTnsSYE0WIFo=; b=jcQqaXWtvQ2h0NJyn6JW+nurPh0CM7Qa8pFiJGNcXJTFKI3DpA5o7ERCvDZa0ALUI1 6BKSjHD3Q+oqZXoPc8vK+zskEcJG3jEfwkUNRXu1hcIYzP1ARgfqrplNqnQV3Y0ADFLe UWgghFXK8vtA5jTQtzH7PdxdyPzEM/+IoHtfDbwSo4VsD4aDk0DOGtQQEdWkd6w912ic 38WfPbQfuOieRG3/ls7U+vuDQa1CQ0K7dh7K3Ylkz4HyxRxi7pm4mn4s68zbhzRhJQQa 2brxRcSwoPBr3E2iMUliZ9CUJLTnqgOQyeWvKintWtgcfuGw+XnOz5Ry8Z9F37ULNn15 9W3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=8SqzjktYdSolKelsIc3Thg9RmyEnmv2PTnsSYE0WIFo=; b=tgfAbVpB8HuRKr3FQGvfG7TqLTs9mEasqgawZZkrogkDwdDXl8C66bq05wxCDuFlqU qqzTcMeEGGwoUpxtuQgf6DowYHXiz/VIB29sXPbjmkGRzWxT4yf15oZSaR1ERosE2RUq J+HJZjlDHX9BX8ZzJbBxEQECtVcEt3xqTuoEmmNJBwi/QhTeN8TluFQ4ZZ2kXATS1/j0 N581RhNuB7QFXI5erYTgBW6wNrgva59DPwpBqwb/loTTmg8j+ZCeK+ikCqhT7Dr9Qg0r C4zvo9FAJyoV9s2w/vUSaJmHnj0C3zhGhI5OKt+t+pQQGeE+LGOXkBCy7+KVRB8TOVYU didg== X-Gm-Message-State: APjAAAXMQIZZLvT2xOhcjMX1N6hTba5hjrW3+ylfx0/NfUunxQaFX4a9 MlrQnLwOqY1TB1Vb//Uq/+l7LNFOXfDJpW76li5F0g== X-Google-Smtp-Source: APXvYqzZAw4VXdyVZVuynhp+UJpQQmV7L3VIA+LOCo4vIXMDk7QfMNeme3W/g6dVs5s3vjQoh0WUG16dacFLPSrost4Nvw== X-Received: by 2002:aca:c057:: with SMTP id q84mr2894973oif.135.1558478420669; Tue, 21 May 2019 15:40:20 -0700 (PDT) Date: Tue, 21 May 2019 15:40:13 -0700 In-Reply-To: <20190521224013.3782-1-matthewgarrett@google.com> Message-Id: <20190521224013.3782-3-matthewgarrett@google.com> Mime-Version: 1.0 References: <20190521224013.3782-1-matthewgarrett@google.com> X-Mailer: git-send-email 2.21.0.1020.gf2820cf01a-goog Subject: [RFC 2/2] Add the ability to lock down access to the running kernel image From: Matthew Garrett To: jmorris@namei.org Cc: linux-security-module@vger.kernel.org, linux-kernel@vger.kernel.org, David Howells , Matthew Garrett Sender: owner-linux-security-module@vger.kernel.org Precedence: bulk List-ID: X-Virus-Scanned: ClamAV using ClamSMTP From: David Howells Provide a single call to allow kernel code to determine whether the system should be locked down, thereby disallowing various accesses that might allow the running kernel image to be changed including the loading of modules that aren't validly signed with a key we recognise, fiddling with MSR registers and disallowing hibernation. Signed-off-by: David Howells Signed-off-by: Matthew Garrett --- Documentation/ABI/testing/lockdown | 19 +++ .../admin-guide/kernel-parameters.txt | 9 + Documentation/admin-guide/lockdown.rst | 60 +++++++ include/linux/kernel.h | 7 + include/linux/lsm_hooks.h | 2 + include/linux/security.h | 6 +- security/Kconfig | 3 +- security/Makefile | 2 + security/lockdown/Kconfig | 46 +++++ security/lockdown/Makefile | 1 + security/lockdown/lockdown.c | 157 ++++++++++++++++++ security/security.c | 6 + 12 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/lockdown create mode 100644 Documentation/admin-guide/lockdown.rst create mode 100644 security/lockdown/Kconfig create mode 100644 security/lockdown/Makefile create mode 100644 security/lockdown/lockdown.c diff --git a/Documentation/ABI/testing/lockdown b/Documentation/ABI/testing/lockdown new file mode 100644 index 000000000000..5bd51e20917a --- /dev/null +++ b/Documentation/ABI/testing/lockdown @@ -0,0 +1,19 @@ +What: security/lockdown +Date: March 2019 +Contact: Matthew Garrett +Description: + If CONFIG_LOCK_DOWN_KERNEL is enabled, the kernel can be + moved to a more locked down state at runtime by writing to + this attribute. Valid values are: + + integrity: + The kernel will disable functionality that allows + userland to modify the running kernel image, other + than through the loading or execution of appropriately + signed objects. + + confidentiality: + The kernel will disable all functionality disabled by + the integrity mode, but additionally will disable + features that potentially permit userland to obtain + confidential information stored within the kernel. diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 91c0251fdb86..594d268d92ba 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -2213,6 +2213,15 @@ lockd.nlm_udpport=M [NFS] Assign UDP port. Format: + lockdown= [SECURITY] + { integrity | confidentiality } + Enable the kernel lockdown feature. If set to + integrity, kernel features that allow userland to + modify the running kernel are disabled. If set to + confidentiality, kernel features that allow userland + to extract confidential information from the kernel + are also disabled. + locktorture.nreaders_stress= [KNL] Set the number of locking read-acquisition kthreads. Defaults to being automatically set based on the diff --git a/Documentation/admin-guide/lockdown.rst b/Documentation/admin-guide/lockdown.rst new file mode 100644 index 000000000000..d05dcedd20d1 --- /dev/null +++ b/Documentation/admin-guide/lockdown.rst @@ -0,0 +1,60 @@ +Kernel lockdown functionality +----------------------------- + +.. CONTENTS +.. +.. - Overview. +.. - Enabling Lockdown. + +======== +Overview +======== + +Traditionally Linux systems have been run with the presumption that a +process running with full capabilities is effectively equivalent in +privilege to the kernel itself. The lockdown feature attempts to draw +a stronger boundary between privileged processes and the kernel, +increasing the level of trust that can be placed in the kernel even in +the face of hostile processes. + +Lockdown can be run in two modes - integrity and confidentiality. In +integrity mode, kernel features that allow arbitrary modification of +the running kernel image are disabled. Confidentiality mode behaves in +the same way as integrity mode, but also blocks features that +potentially allow a hostile userland process to extract secret +information from the kernel. + +Note that lockdown depends upon the correct behaviour of the +kernel. Exploitable vulnerabilities in the kernel may still permit +arbitrary modification of the kernel or make it possible to disable +lockdown features. + +================= +Enabling Lockdown +================= + +Lockdown can be enabled in multiple ways. + +Kernel configuration +==================== + +The kernel can be statically configured by setting either +CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY or +CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY. A kernel configured +with CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY may be booted into +confidentiality mode using one of the other mechanisms, but otherwise +the kernel will always boot into the configured mode. + +Kernel command line +=================== + +Passing lockdown=integrity or lockdown=confidentiality on the kernel +command line will configure lockdown into the appropriate mode. + +Runtime configuration +===================== + +/sys/kernel/security/lockdown will indicate the current lockdown +state. The system state may be made stricter by writing either +"integrity" or "confidentiality" into this file, but any attempts to +make it less strict will fail. diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 8f0e68e250a7..7ce52151b76c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -340,6 +340,13 @@ static inline void refcount_error_report(struct pt_regs *regs, const char *err) { } #endif +enum lockdown_level { + LOCKDOWN_NONE, + LOCKDOWN_INTEGRITY, + LOCKDOWN_CONFIDENTIALITY, + LOCKDOWN_MAX, +}; + /* Internal, do not use. */ int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); int __must_check _kstrtol(const char *s, unsigned int base, long *res); diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 1a841d134e05..0377d8ee6454 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1781,6 +1781,7 @@ union security_list_options { int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); #endif /* CONFIG_BPF_SYSCALL */ + int (*locked_down)(const char *where, enum lockdown_level level); }; struct security_hook_heads { @@ -2016,6 +2017,7 @@ struct security_hook_heads { struct hlist_head bpf_prog_alloc_security; struct hlist_head bpf_prog_free_security; #endif /* CONFIG_BPF_SYSCALL */ + struct hlist_head locked_down; } __randomize_layout; /* diff --git a/include/linux/security.h b/include/linux/security.h index f4363a1339a8..87102694b033 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -384,6 +384,7 @@ void security_inode_invalidate_secctx(struct inode *inode); int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); +int security_is_locked_down(const char *where, enum lockdown_level level); #else /* CONFIG_SECURITY */ static inline int call_lsm_notifier(enum lsm_event event, void *data) @@ -1173,6 +1174,10 @@ static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 { return -EOPNOTSUPP; } +static inline int security_is_locked_down(const char *where, enum lockdown_level level) +{ + return 0; +} #endif /* CONFIG_SECURITY */ #ifdef CONFIG_SECURITY_NETWORK @@ -1800,4 +1805,3 @@ static inline void security_bpf_prog_free(struct bpf_prog_aux *aux) #endif /* CONFIG_BPF_SYSCALL */ #endif /* ! __LINUX_SECURITY_H */ - diff --git a/security/Kconfig b/security/Kconfig index 1d6463fb1450..c35aa72103df 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -236,12 +236,13 @@ source "security/apparmor/Kconfig" source "security/loadpin/Kconfig" source "security/yama/Kconfig" source "security/safesetid/Kconfig" +source "security/lockdown/Kconfig" source "security/integrity/Kconfig" config LSM string "Ordered list of enabled LSMs" - default "yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" + default "lockdown,yama,loadpin,safesetid,integrity,selinux,smack,tomoyo,apparmor" help A comma-separated list of LSMs, in initialization order. Any LSMs left off this list will be ignored. This can be diff --git a/security/Makefile b/security/Makefile index c598b904938f..be1dd9d2cb2f 100644 --- a/security/Makefile +++ b/security/Makefile @@ -11,6 +11,7 @@ subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor subdir-$(CONFIG_SECURITY_YAMA) += yama subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin subdir-$(CONFIG_SECURITY_SAFESETID) += safesetid +subdir-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown # always enable default capabilities obj-y += commoncap.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ obj-$(CONFIG_SECURITY_YAMA) += yama/ obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ obj-$(CONFIG_SECURITY_SAFESETID) += safesetid/ +obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown/ obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/security/lockdown/Kconfig b/security/lockdown/Kconfig new file mode 100644 index 000000000000..431cd2b9a14e --- /dev/null +++ b/security/lockdown/Kconfig @@ -0,0 +1,46 @@ +config SECURITY_LOCKDOWN_LSM + bool "Basic module for enforcing kernel lockdown" + depends on SECURITY + help + Build support for an LSM that enforces a coarse kernel lockdown + behaviour. + +config SECURITY_LOCKDOWN_LSM_EARLY + bool "Enable lockdown LSM early in init" + depends on SECURITY_LOCKDOWN_LSM + help + Enable the lockdown LSM early in boot. This is necessary in order + to ensure that lockdown enforcement can be carried out on kernel + boot parameters that are otherwise parsed before the security + subsystem is fully initialised. + +choice + prompt "Kernel default lockdown mode" + default LOCK_DOWN_KERNEL_FORCE_NONE + depends on SECURITY_LOCKDOWN_LSM + help + The kernel can be configured to default to differing levels of + lockdown. + +config LOCK_DOWN_KERNEL_FORCE_NONE + bool "None" + help + No lockdown functionality is enabled by default. Lockdown may be + enabled via the kernel commandline or /sys/kernel/security/lockdown. + +config LOCK_DOWN_KERNEL_FORCE_INTEGRITY + bool "Integrity" + help + The kernel runs in integrity mode by default. Features that allow + the kernel to be modified at runtime are disabled. + +config LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY + bool "Confidentiality" + help + The kernel runs in confidentiality mode by default. Features that + allow the kernel to be modified at runtime or that permit userland + code to read confidential material held inside the kernel are + disabled. + +endchoice + diff --git a/security/lockdown/Makefile b/security/lockdown/Makefile new file mode 100644 index 000000000000..e3634b9017e7 --- /dev/null +++ b/security/lockdown/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SECURITY_LOCKDOWN_LSM) += lockdown.o diff --git a/security/lockdown/lockdown.c b/security/lockdown/lockdown.c new file mode 100644 index 000000000000..6c707492344b --- /dev/null +++ b/security/lockdown/lockdown.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Lock down the kernel + * + * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include + +static enum lockdown_level kernel_locked_down; + +char *lockdown_levels[LOCKDOWN_MAX] = {"none", "integrity", "confidentiality"}; + +/* + * Put the kernel into lock-down mode. + */ +static int lock_kernel_down(const char *where, enum lockdown_level level) +{ + if (kernel_locked_down >= level) + return -EPERM; + + kernel_locked_down = level; + pr_notice("Kernel is locked down from %s; see man kernel_lockdown.7\n", + where); + return 0; +} + +static int __init lockdown_param(char *level) +{ + if (!level) + return -EINVAL; + + if (strcmp(level, "integrity") == 0) + lock_kernel_down("command line", LOCKDOWN_INTEGRITY); + else if (strcmp(level, "confidentiality") == 0) + lock_kernel_down("command line", LOCKDOWN_CONFIDENTIALITY); + else + return -EINVAL; + + return 0; +} + +early_param("lockdown", lockdown_param); + +/** + * lockdown_is_locked_down - Find out if the kernel is locked down + * @what: Tag to use in notice generated if lockdown is in effect + */ +static int lockdown_is_locked_down(const char *what, enum lockdown_level level) +{ + if ((kernel_locked_down >= level) && what) + pr_notice("Lockdown: %s is restricted; see man kernel_lockdown.7\n", + what); + return (kernel_locked_down >= level); +} + +static struct security_hook_list lockdown_hooks[] __lsm_ro_after_init = { + LSM_HOOK_INIT(locked_down, lockdown_is_locked_down), +}; + +static int __init lockdown_lsm_init(void) +{ +#if defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_INTEGRITY) + lock_kernel_down("Kernel configuration", LOCKDOWN_INTEGRITY); +#elif defined(CONFIG_LOCK_DOWN_KERNEL_FORCE_CONFIDENTIALITY) + lock_kernel_down("Kernel configuration", LOCKDOWN_CONFIDENTIALITY); +#endif + security_add_hooks(lockdown_hooks, ARRAY_SIZE(lockdown_hooks), + "lockdown"); + return 0; +} + +static ssize_t lockdown_read(struct file *filp, char __user *buf, size_t count, + loff_t *ppos) +{ + char temp[80]; + int i, offset=0; + + for (i = LOCKDOWN_NONE; i < LOCKDOWN_MAX; i++) { + if (lockdown_levels[i]) { + const char *label = lockdown_levels[i]; + + if (kernel_locked_down == i) + offset += sprintf(temp+offset, "[%s] ", label); + else + offset += sprintf(temp+offset, "%s ", label); + } + } + + /* Convert the last space to a newline if needed. */ + if (offset > 0) + temp[offset-1] = '\n'; + + return simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); +} + +static ssize_t lockdown_write(struct file *file, const char __user *buf, + size_t n, loff_t *ppos) +{ + char *state; + int i, len, err = -EINVAL; + + state = memdup_user_nul(buf, n); + if (IS_ERR(state)) + return PTR_ERR(state); + + len = strlen(state); + if (len && state[len-1] == '\n') { + state[len-1] = '\0'; + len--; + } + + for (i = 0; i < LOCKDOWN_MAX; i++) { + const char *label = lockdown_levels[i]; + + if (label && !strcmp(state, label)) + err = lock_kernel_down("securityfs", i); + } + + kfree(state); + return err ? err : n; +} + +static const struct file_operations lockdown_ops = { + .read = lockdown_read, + .write = lockdown_write, +}; + +static int __init lockdown_secfs_init(void) +{ + struct dentry *dentry; + + dentry = securityfs_create_file("lockdown", 0600, NULL, NULL, + &lockdown_ops); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + return 0; +} + +core_initcall(lockdown_secfs_init); + +#ifdef CONFIG_SECURITY_LOCKDOWN_LSM_EARLY +DEFINE_EARLY_LSM(lockdown) = { +#else +DEFINE_LSM(lockdown) = { +#endif + .name = "lockdown", + .init = lockdown_lsm_init, +}; diff --git a/security/security.c b/security/security.c index e3a7d4e96541..73ccf3be55bf 100644 --- a/security/security.c +++ b/security/security.c @@ -2370,3 +2370,9 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) call_void_hook(bpf_prog_free_security, aux); } #endif /* CONFIG_BPF_SYSCALL */ + +int security_is_locked_down(const char *where, enum lockdown_level level) +{ + return call_int_hook(locked_down, 0, where, level); +} +EXPORT_SYMBOL(security_is_locked_down);