Received: by 10.192.165.156 with SMTP id m28csp933176imm; Wed, 11 Apr 2018 09:29:09 -0700 (PDT) X-Google-Smtp-Source: AIpwx4+LI//sKFD+MzglsplWk0432EVQPvRvUe6o+6Buuop2L5/L2Kylkr6q+l8vuJ5ugFGM7Rgs X-Received: by 2002:a17:902:d88a:: with SMTP id b10-v6mr5834647plz.172.1523464149365; Wed, 11 Apr 2018 09:29:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523464149; cv=none; d=google.com; s=arc-20160816; b=aBWvbaEJFhbmfAWhY5x4Xb5/OhWXkDiyJFStACKNCpMx4r2uDZxAMQuWPfeILB8rQM EGHc5eFSElVlFQ0yJHH3mbO5kDVN859pnV84z0UnmMs3G2cAOCQhyfkFYVliExUdyEX8 3AsAQIwKB4fX+dUYpj8ZfCrz72EqWDg4qraNrQfmINVNayCcvLH3ej5h3qZpcM0shoyr BFwB1kjlNzuJu3SWCYeYR7pXmqsnUzH9RR3NcGxNN9fY2jV9HJd5+ISXcxV1GUyEm8FZ DpV+5z+728xCSVwZiP6zF4Olr5cnRu3gW3xZSbo10dTai4s26bTZsBI1D6RTOMzfnsOy gA1w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:cc:to:from :subject:organization:arc-authentication-results; bh=N/MhWYOvkLau0XGExaOnVxqbFTjyWzP7CJmRV82Epvk=; b=Guf/OrUtitBXnrHX0kfFB75ntnHSbp1L2VBSLsRyg37ssbt8WheYDkaBx6Oyh7RV2Z qjtSOMrT7gLsZ1pUSIbyGLGd4u0JigSXPk4i+HaMusU/sgrZBhldke2VizILer0fHmdk i9qNpvqJoNFQcXelI1/jipA1zMF+1q1Thhk4Qy0cBdViZPjFVC9Y6x0ugwxTz3TJ0iK4 geP1zjf+B1oSAShe3he9+k3UER1ZEwAOA2PR0eJEDWj8Fa1LhdK4vyk2wm1E7hi0eRmz UC1FbQ0ZZidXlSVyix7hMdWPW8/bz0PeZiw33e+49uNgBAeSRCRmrNMWDXs8/B4Rf2Qe q1RQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g8-v6si1386156plt.254.2018.04.11.09.28.21; Wed, 11 Apr 2018 09:29:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753923AbeDKQY6 (ORCPT + 99 others); Wed, 11 Apr 2018 12:24:58 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:45136 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1753755AbeDKQYz (ORCPT ); Wed, 11 Apr 2018 12:24:55 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id C9FE981A88A3; Wed, 11 Apr 2018 16:24:53 +0000 (UTC) Received: from warthog.procyon.org.uk (ovpn-120-8.rdu2.redhat.com [10.10.120.8]) by smtp.corp.redhat.com (Postfix) with ESMTP id DC98810AF9E0; Wed, 11 Apr 2018 16:24:52 +0000 (UTC) Organization: Red Hat UK Ltd. Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SI4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Subject: [PATCH 02/24] Add a SysRq option to lift kernel lockdown From: David Howells To: torvalds@linux-foundation.org Cc: linux-man@vger.kernel.org, linux-api@vger.kernel.org, jmorris@namei.org, linux-kernel@vger.kernel.org, dhowells@redhat.com, linux-security-module@vger.kernel.org Date: Wed, 11 Apr 2018 17:24:52 +0100 Message-ID: <152346389240.4030.11187964053014260180.stgit@warthog.procyon.org.uk> In-Reply-To: <152346387861.4030.4408662483445703127.stgit@warthog.procyon.org.uk> References: <152346387861.4030.4408662483445703127.stgit@warthog.procyon.org.uk> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Wed, 11 Apr 2018 16:24:53 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Wed, 11 Apr 2018 16:24:53 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'dhowells@redhat.com' RCPT:'' Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Kyle McMartin Make an option to provide a sysrq key that will lift the kernel lockdown, thereby allowing the running kernel image to be accessed and modified. On x86 this is triggered with SysRq+x, but this key may not be available on all arches, so it is set by setting LOCKDOWN_LIFT_KEY in asm/setup.h. Since this macro must be defined in an arch to be able to use this facility for that arch, the Kconfig option is restricted to arches that support it. Signed-off-by: Kyle McMartin Signed-off-by: David Howells cc: x86@kernel.org --- arch/x86/include/asm/setup.h | 2 ++ drivers/input/misc/uinput.c | 1 + drivers/tty/sysrq.c | 19 ++++++++++++----- include/linux/input.h | 5 ++++ include/linux/sysrq.h | 8 ++++++- kernel/debug/kdb/kdb_main.c | 2 +- security/Kconfig | 11 ++++++++++ security/lock_down.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 87 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index ae13bc974416..3108e297d87d 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h @@ -9,6 +9,8 @@ #include #include +#define LOCKDOWN_LIFT_KEY 'x' + #ifdef __i386__ #include diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 96a887f33698..027c730631cc 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -365,6 +365,7 @@ static int uinput_create_device(struct uinput_device *udev) dev->flush = uinput_dev_flush; } + dev->flags |= INPUTDEV_FLAGS_SYNTHETIC; dev->event = uinput_dev_event; input_set_drvdata(udev->dev, udev); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 6364890575ec..ffeb3aa86cd1 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -487,6 +487,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* x: May be registered on mips for TLB dump */ /* x: May be registered on ppc/powerpc for xmon */ /* x: May be registered on sparc64 for global PMU dump */ + /* x: May be registered on x86_64 for disabling secure boot */ NULL, /* x */ /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ @@ -530,7 +531,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; } -void __handle_sysrq(int key, bool check_mask) +void __handle_sysrq(int key, unsigned int from) { struct sysrq_key_op *op_p; int orig_log_level; @@ -550,11 +551,15 @@ void __handle_sysrq(int key, bool check_mask) op_p = __sysrq_get_key_op(key); if (op_p) { + /* Ban synthetic events from some sysrq functionality */ + if ((from == SYSRQ_FROM_PROC || from == SYSRQ_FROM_SYNTHETIC) && + op_p->enable_mask & SYSRQ_DISABLE_USERSPACE) + printk("This sysrq operation is disabled from userspace.\n"); /* * Should we check for enabled operations (/proc/sysrq-trigger * should not) and is the invoked operation enabled? */ - if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { + if (from == SYSRQ_FROM_KERNEL || sysrq_on_mask(op_p->enable_mask)) { pr_cont("%s\n", op_p->action_msg); console_loglevel = orig_log_level; op_p->handler(key); @@ -586,7 +591,7 @@ void __handle_sysrq(int key, bool check_mask) void handle_sysrq(int key) { if (sysrq_on()) - __handle_sysrq(key, true); + __handle_sysrq(key, SYSRQ_FROM_KERNEL); } EXPORT_SYMBOL(handle_sysrq); @@ -667,7 +672,7 @@ static void sysrq_do_reset(struct timer_list *t) static void sysrq_handle_reset_request(struct sysrq_state *state) { if (state->reset_requested) - __handle_sysrq(sysrq_xlate[KEY_B], false); + __handle_sysrq(sysrq_xlate[KEY_B], SYSRQ_FROM_KERNEL); if (sysrq_reset_downtime_ms) mod_timer(&state->keyreset_timer, @@ -818,8 +823,10 @@ static bool sysrq_handle_keypress(struct sysrq_state *sysrq, default: if (sysrq->active && value && value != 2) { + int from = sysrq->handle.dev->flags & INPUTDEV_FLAGS_SYNTHETIC ? + SYSRQ_FROM_SYNTHETIC : 0; sysrq->need_reinject = false; - __handle_sysrq(sysrq_xlate[code], true); + __handle_sysrq(sysrq_xlate[code], from); } break; } @@ -1102,7 +1109,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, if (get_user(c, buf)) return -EFAULT; - __handle_sysrq(c, false); + __handle_sysrq(c, SYSRQ_FROM_PROC); } return count; diff --git a/include/linux/input.h b/include/linux/input.h index 7c7516eb7d76..38cd0ea72c37 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -42,6 +42,7 @@ struct input_value { * @phys: physical path to the device in the system hierarchy * @uniq: unique identification code for the device (if device has it) * @id: id of the device (struct input_id) + * @flags: input device flags (SYNTHETIC, etc.) * @propbit: bitmap of device properties and quirks * @evbit: bitmap of types of events supported by the device (EV_KEY, * EV_REL, etc.) @@ -124,6 +125,8 @@ struct input_dev { const char *uniq; struct input_id id; + unsigned int flags; + unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; @@ -190,6 +193,8 @@ struct input_dev { }; #define to_input_dev(d) container_of(d, struct input_dev, dev) +#define INPUTDEV_FLAGS_SYNTHETIC 0x000000001 + /* * Verify that we are in sync with input_device_id mod_devicetable.h #defines */ diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h index 8c71874e8485..7de1f08b60a9 100644 --- a/include/linux/sysrq.h +++ b/include/linux/sysrq.h @@ -29,6 +29,8 @@ #define SYSRQ_ENABLE_BOOT 0x0080 #define SYSRQ_ENABLE_RTNICE 0x0100 +#define SYSRQ_DISABLE_USERSPACE 0x00010000 + struct sysrq_key_op { void (*handler)(int); char *help_msg; @@ -43,8 +45,12 @@ struct sysrq_key_op { * are available -- else NULL's). */ +#define SYSRQ_FROM_KERNEL 0x0001 +#define SYSRQ_FROM_PROC 0x0002 +#define SYSRQ_FROM_SYNTHETIC 0x0004 + void handle_sysrq(int key); -void __handle_sysrq(int key, bool check_mask); +void __handle_sysrq(int key, unsigned int from); int register_sysrq_key(int key, struct sysrq_key_op *op); int unregister_sysrq_key(int key, struct sysrq_key_op *op); struct sysrq_key_op *__sysrq_get_key_op(int key); diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c index dbb0781a0533..aae9a0f44058 100644 --- a/kernel/debug/kdb/kdb_main.c +++ b/kernel/debug/kdb/kdb_main.c @@ -1970,7 +1970,7 @@ static int kdb_sr(int argc, const char **argv) return KDB_ARGCOUNT; kdb_trap_printk++; - __handle_sysrq(*argv[1], check_mask); + __handle_sysrq(*argv[1], check_mask ? SYSRQ_FROM_KERNEL : 0); kdb_trap_printk--; return 0; diff --git a/security/Kconfig b/security/Kconfig index a68e5bdebad5..46967ee77dfd 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -253,6 +253,17 @@ config LOCK_DOWN_MANDATORY Makes the lockdown non-negotiable. It is always on and cannot be disabled. +config ALLOW_LOCKDOWN_LIFT_BY_SYSRQ + bool "Allow the kernel lockdown to be lifted by SysRq" + depends on LOCK_DOWN_KERNEL + depends on !LOCK_DOWN_MANDATORY + depends on MAGIC_SYSRQ + depends on X86 + help + Allow the lockdown on a kernel to be lifted, by pressing a SysRq key + combination on a wired keyboard. On x86, this is SysRq+x. + + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig diff --git a/security/lock_down.c b/security/lock_down.c index f35ffdd096ad..2615669dbf03 100644 --- a/security/lock_down.c +++ b/security/lock_down.c @@ -11,9 +11,15 @@ #include #include +#include +#include #ifndef CONFIG_LOCK_DOWN_MANDATORY +#ifdef CONFIG_ALLOW_LOCKDOWN_LIFT_BY_SYSRQ +static __read_mostly bool kernel_locked_down; +#else static __ro_after_init bool kernel_locked_down; +#endif #else #define kernel_locked_down true #endif @@ -63,3 +69,44 @@ bool __kernel_is_locked_down(const char *what, bool first) return kernel_locked_down; } EXPORT_SYMBOL(__kernel_is_locked_down); + +#ifdef CONFIG_ALLOW_LOCKDOWN_LIFT_BY_SYSRQ + +/* + * Take the kernel out of lockdown mode. + */ +static void lift_kernel_lockdown(void) +{ + pr_notice("Lifting lockdown\n"); + kernel_locked_down = false; +} + +/* + * Allow lockdown to be lifted by pressing something like SysRq+x (and not by + * echoing the appropriate letter into the sysrq-trigger file). + */ +static void sysrq_handle_lockdown_lift(int key) +{ + if (kernel_locked_down) + lift_kernel_lockdown(); +} + +static struct sysrq_key_op lockdown_lift_sysrq_op = { + .handler = sysrq_handle_lockdown_lift, + .help_msg = "unSB(x)", + .action_msg = "Disabling Secure Boot restrictions", + .enable_mask = SYSRQ_DISABLE_USERSPACE, +}; + +static int __init lockdown_lift_sysrq(void) +{ + if (kernel_locked_down) { + lockdown_lift_sysrq_op.help_msg[5] = LOCKDOWN_LIFT_KEY; + register_sysrq_key(LOCKDOWN_LIFT_KEY, &lockdown_lift_sysrq_op); + } + return 0; +} + +late_initcall(lockdown_lift_sysrq); + +#endif /* CONFIG_ALLOW_LOCKDOWN_LIFT_BY_SYSRQ */