Message ID | 20221114-disable-kexec-reset-v1-2-fb51d20cf871@chromium.org |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp2147278wru; Mon, 14 Nov 2022 05:36:43 -0800 (PST) X-Google-Smtp-Source: AA0mqf5jTiB+LJyZMbXxyGl+uhCQJH+ot/5XxaMt5fdsXFLL3K6MrRQOAWDE9y2bujq89I1rKPNF X-Received: by 2002:a05:6402:144c:b0:45f:b9d8:9514 with SMTP id d12-20020a056402144c00b0045fb9d89514mr11349910edx.204.1668433003523; Mon, 14 Nov 2022 05:36:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668433003; cv=none; d=google.com; s=arc-20160816; b=pzbEbKWfjMDyjMUNaQzj6dmkJORB6dUFquuKOs4YQf169a9XYAWKoDNszV+egb4wxz BkPcXDbSxULWL+QDo2EggB87e4V+MRABP5azqYmnBfMGo9gMhLIh/QR6Aa5VDmRCfdw5 YNf4l37GZ/0M46TIAG9+UyzzjBXJo7g3X/wBxqIehfnjdJxuBe+YILqCD9x/chY2drd/ DPAE/HUJyvqBWRVKaEpVD+oD9IJhWXuQ52/mB1e/9QaG63EIyEZ7EoAG+Fn2Y5bMnp6R 3/oEASbgYI/P20OodMe+uVYjoqMN6fXiMbg4KlPjKMQcy/QNjL0LCTNMdx1PDftYlbR9 QzvQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:in-reply-to:references:message-id :content-transfer-encoding:mime-version:subject:date:from :dkim-signature; bh=YBDqrK6ZdWq2OzrZLHJQraMMoPoinvhQP0W8u+3GcTk=; b=pas7saHlQRtCk5oMEI6l/YdSZAhOAXhzP8ub49CGxCl+H86DExbgxFdbkKd2a3WYjA PCVqnkDjp7xt/ySq9J9j3FSOBuIzP95VV9LTRu5ZwF9JQVFJcyOLsi0SSYGPEWLJSfgc Mzw+sb5tt86T4FhjTDAUg2UUZLA0K1jhOqWhXXL8MijVys+xLFxerF+o4lBb0zdNmVze SDHqEAQpomYq4C4JWo4gQNNej0uz9WpfihFk5DSMzJVFhiKeXhDekqgzLMGIXkB6OuM9 yLYehRnSeJUVzRZQyINCU8Ow2iCN98pddl4RdHHGh5gGaCK43DEVd5QCIsJ6nglcKVfk MAoA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=l+SRhUtV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id hg3-20020a1709072cc300b0078df1c345dcsi7246614ejc.535.2022.11.14.05.36.19; Mon, 14 Nov 2022 05:36:43 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@chromium.org header.s=google header.b=l+SRhUtV; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=chromium.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236661AbiKNNT6 (ORCPT <rfc822;winker.wchi@gmail.com> + 99 others); Mon, 14 Nov 2022 08:19:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46208 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237985AbiKNNTg (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 14 Nov 2022 08:19:36 -0500 Received: from mail-ej1-x635.google.com (mail-ej1-x635.google.com [IPv6:2a00:1450:4864:20::635]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AED1D2BB1B for <linux-kernel@vger.kernel.org>; Mon, 14 Nov 2022 05:19:07 -0800 (PST) Received: by mail-ej1-x635.google.com with SMTP id i10so19573599ejg.6 for <linux-kernel@vger.kernel.org>; Mon, 14 Nov 2022 05:19:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=YBDqrK6ZdWq2OzrZLHJQraMMoPoinvhQP0W8u+3GcTk=; b=l+SRhUtVZVJ0JfZqzT7bi1gWoeK5gqgOT1cfNOL0iydr9/ACO4IBVNXucMwfahDafq CcjyAjAzeje8N09iCbh4cC4KqMlln1mN4sbG6gBrvQZZ4jUrmqPsT0sGID2YHiZfN3pG CoywAWz6UY5pqFVZHhmTJBgeSD1qak/cqkiWI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=YBDqrK6ZdWq2OzrZLHJQraMMoPoinvhQP0W8u+3GcTk=; b=GXgSJ78ljP7YhUGARctbwG8TYX7YlYOPh3fTCcK29+Dk/h3q8xoB5U7bHBLEIvNbmX Ewql84jdM+ub+Pund2jn8iKTtppuSJJvILB6VAE6u2gJgJvVQyg+SCw+Z6cFhFWjLiC3 9ojc0cvNN7iUv5LaRQGfj4PBryf9YLlm5JzGEHo/eRG4ZD5/1DclKEj5ewlyPmhikQzw b2fpL4ZRxK3ZQCq7333RKL3wGNWFTroHrFoSecTfqIQFES0QrpkFHE88FD6KtIhdu15M Cfi1vhijf5pqF8Z50YEfwUeKC6dWUf7N9zZFKx/Qa/dkF33Vc0NPsG+BBgjeo0Jk5SWt b6tg== X-Gm-Message-State: ANoB5pnzS2kSJSfZ58OpRPMXIqfrLkuvuPKt23tdv7+vVdC9ngFoVrRX lQbKRRgAfTjW3R00udd6fvuCRA== X-Received: by 2002:a17:906:f208:b0:7ae:2277:9fec with SMTP id gt8-20020a170906f20800b007ae22779fecmr9990574ejb.623.1668431947306; Mon, 14 Nov 2022 05:19:07 -0800 (PST) Received: from alco.roam.corp.google.com ([2620:0:1059:10:c205:5c4e:7456:c8cc]) by smtp.gmail.com with ESMTPSA id g13-20020a50ec0d000000b0045b3853c4b7sm4802061edr.51.2022.11.14.05.19.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 14 Nov 2022 05:19:06 -0800 (PST) From: Ricardo Ribalda <ribalda@chromium.org> Date: Mon, 14 Nov 2022 14:18:39 +0100 Subject: [PATCH v1 2/2] kexec: Introduce kexec_reboot_disabled MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 8bit Message-Id: <20221114-disable-kexec-reset-v1-2-fb51d20cf871@chromium.org> References: <20221114-disable-kexec-reset-v1-0-fb51d20cf871@chromium.org> In-Reply-To: <20221114-disable-kexec-reset-v1-0-fb51d20cf871@chromium.org> To: Eric Biederman <ebiederm@xmission.com>, Jonathan Corbet <corbet@lwn.net> Cc: Sergey Senozhatsky <senozhatsky@chromium.org>, linux-kernel@vger.kernel.org, kexec@lists.infradead.org, Ross Zwisler <zwisler@kernel.org>, linux-doc@vger.kernel.org, "Joel Fernandes (Google)" <joel@joelfernandes.org>, Steven Rostedt <rostedt@goodmis.org>, Ricardo Ribalda <ribalda@chromium.org> X-Mailer: b4 0.11.0-dev-d93f8 X-Developer-Signature: v=1; a=openpgp-sha256; l=3808; i=ribalda@chromium.org; h=from:subject:message-id; bh=dblSayUsSfEKi8F2aGC75NJql5jVZbhwpLBwKIyAUtI=; b=owEBbQKS/ZANAwAKAdE30T7POsSIAcsmYgBjckBFo6eu9Gtv5tVzghpwemmGVrmtXYcngm/W6RxM 3Cx6NGiJAjMEAAEKAB0WIQREDzjr+/4oCDLSsx7RN9E+zzrEiAUCY3JARQAKCRDRN9E+zzrEiKEID/ 4te8B7uFehLdBDS2AiqR+VMunRK2lzXEeuVXblaP3r9ExwUMnGbUtAWttF2wal25J7+bvvo5sQnQWQ /BbODeZY+8zGMtVVZGYXtwZ9uGeX53xvh1fheLmkHVHxuKwB7TC3SsPxSIhDj+6M+9YbmEbrJe1YB5 VcCdjYyjDHo9YFjKOXDIQ/zrsYzhCpCX1xND0zKYlIe58zE+LkT6EGs47rw9I0GUdqRvbWDIa6MrlO cKE8iQAOX9ihR5wGRJVBO1O8+GBbq+3x7xfeEo4qYfJv64ne4t/TUXRAajUAg8mIZRlWp0/r9vAqB4 siXhXif6Sbr0P7D3ND5d5/e3A7vCy4jnIEAFnyoA2bMZp8lPtKa0OZ/CkIYVygBbymXYiwgMmqhs89 01cb4w3UOj810NTpXb1nR/D5wnH1A5jtHvp+09F+Js/8q5GPEDGqdaglAlE2fnATD07PdX/GD4xsDz vsqnw7M4vpGHQuPPzFizXXK8vTJIcJnmVpZJG7nX+s3QHH7FgAaUFC6yKYcFw/5aKqYEtHD1rCuLBf xPmpZ8s6CIzKx0kfixlh9mmR+pbwFC9QqULyccreqPocelwhaHSZXUZRvABk1AAkrFWRt39ChNVEOr g7LSeqsxViMsBQgX/QuEcRq4LGx/aHZOplyG/1DFFpu9P86p7zYC8a3U7sdw== X-Developer-Key: i=ribalda@chromium.org; a=openpgp; fpr=9EC3BB66E2FC129A6F90B39556A0D81F9F782DA9 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749478805024763935?= X-GMAIL-MSGID: =?utf-8?q?1749478805024763935?= |
Series |
kexec: Add new toogle to disable kexec_reboot
|
|
Commit Message
Ricardo Ribalda
Nov. 14, 2022, 1:18 p.m. UTC
Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the
attack surface to a system.
Without this toogle, an attacker can only reboot into a different kernel
if they can create a panic().
Signed-off-by: Ricardo Ribalda <ribalda@chromium.org>
Comments
Hi Ricardo, all in all I think this patch makes sense. However, there is one point I don't like... On Mon, 14 Nov 2022 14:18:39 +0100 Ricardo Ribalda <ribalda@chromium.org> wrote: > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > attack surface to a system. > > Without this toogle, an attacker can only reboot into a different kernel > if they can create a panic(). > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > index 97394bd9d065..25d019682d33 100644 > --- a/Documentation/admin-guide/sysctl/kernel.rst > +++ b/Documentation/admin-guide/sysctl/kernel.rst > @@ -462,6 +462,17 @@ altered. > Generally used together with the `modules_disabled`_ sysctl. > > > +kexec_reboot_disabled > +===================== > + > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > +Once true, kexec can no longer be used for reboot and the toggle > +cannot be set back to false. > +This toggle does not affect the use of kexec during a crash. > + > + > kptr_restrict > ============= > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > index 41a686996aaa..15c3fad8918b 100644 > --- a/include/linux/kexec.h > +++ b/include/linux/kexec.h > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > extern struct kimage *kexec_image; > extern struct kimage *kexec_crash_image; > extern int kexec_load_disabled; > +extern int kexec_reboot_disabled; > > #ifndef kexec_flush_icache_page > #define kexec_flush_icache_page(page) > diff --git a/kernel/kexec.c b/kernel/kexec.c > index cb8e6e6f983c..43063f803d81 100644 > --- a/kernel/kexec.c > +++ b/kernel/kexec.c > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > return -EPERM; > > + /* Check if the system admin has disabled kexec reboot. */ > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > + return -EPERM; ... Allowing to load a crashkernel doesn't make sense in my opinion. If an attacker is capable of creating a malicious kernel, planting it on the victims system and then find a way to boot it via kexec this attacker also knows how to load the malicious kernel as crashkernel and trigger a panic. So you haven't really gained anything. That's why I would simply drop this hunk (and the corresponding one from kexec_file_load) and let users who worry about this use a combination of kexec_load_disabled and kexec_reboot_disabled. Thanks Philipp > + > /* Permit LSMs and IMA to fail the kexec */ > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > if (result < 0) > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > index ca2743f9c634..fe82e2525705 100644 > --- a/kernel/kexec_core.c > +++ b/kernel/kexec_core.c > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > struct kimage *kexec_image; > struct kimage *kexec_crash_image; > int kexec_load_disabled; > +int kexec_reboot_disabled; > #ifdef CONFIG_SYSCTL > static struct ctl_table kexec_core_sysctls[] = { > { > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > .extra1 = SYSCTL_ONE, > .extra2 = SYSCTL_ONE, > }, > + { > + .procname = "kexec_reboot_disabled", > + .data = &kexec_reboot_disabled, > + .maxlen = sizeof(int), > + .mode = 0644, > + /* only handle a transition from default "0" to "1" */ > + .proc_handler = proc_dointvec_minmax, > + .extra1 = SYSCTL_ONE, > + .extra2 = SYSCTL_ONE, > + }, > { } > }; > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > if (!kexec_trylock()) > return -EBUSY; > - if (!kexec_image) { > + if (!kexec_image || kexec_reboot_disabled) { > error = -EINVAL; > goto Unlock; > } > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > index 45637511e0de..583fba6de5cb 100644 > --- a/kernel/kexec_file.c > +++ b/kernel/kexec_file.c > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > return -EPERM; > > + /* Check if the system admin has disabled kexec reboot. */ > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > + && kexec_reboot_disabled) > + return -EPERM; > + > /* Make sure we have a legal set of flags */ > if (flags != (flags & KEXEC_FILE_FLAGS)) > return -EINVAL; >
Hi Philipp Thanks for your review! On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > Hi Ricardo, > > all in all I think this patch makes sense. However, there is one point > I don't like... > > On Mon, 14 Nov 2022 14:18:39 +0100 > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > attack surface to a system. > > > > Without this toogle, an attacker can only reboot into a different kernel > > if they can create a panic(). > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > index 97394bd9d065..25d019682d33 100644 > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > @@ -462,6 +462,17 @@ altered. > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > +kexec_reboot_disabled > > +===================== > > + > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > +Once true, kexec can no longer be used for reboot and the toggle > > +cannot be set back to false. > > +This toggle does not affect the use of kexec during a crash. > > + > > + > > kptr_restrict > > ============= > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > index 41a686996aaa..15c3fad8918b 100644 > > --- a/include/linux/kexec.h > > +++ b/include/linux/kexec.h > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > extern struct kimage *kexec_image; > > extern struct kimage *kexec_crash_image; > > extern int kexec_load_disabled; > > +extern int kexec_reboot_disabled; > > > > #ifndef kexec_flush_icache_page > > #define kexec_flush_icache_page(page) > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > index cb8e6e6f983c..43063f803d81 100644 > > --- a/kernel/kexec.c > > +++ b/kernel/kexec.c > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > return -EPERM; > > > > + /* Check if the system admin has disabled kexec reboot. */ > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > + return -EPERM; > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > an attacker is capable of creating a malicious kernel, planting it on > the victims system and then find a way to boot it via kexec this > attacker also knows how to load the malicious kernel as crashkernel and > trigger a panic. So you haven't really gained anything. That's why I > would simply drop this hunk (and the corresponding one from > kexec_file_load) and let users who worry about this use a combination of > kexec_load_disabled and kexec_reboot_disabled. If for whatever reason your sysadmin configured kexec_reboot_disabed it can be nice that when a user try to load it they get a warning. It is easier to debug than waiting two steps later when they run kexec -e.... That is why I added it. But i am also ok removing it > > Thanks > Philipp > > > + > > /* Permit LSMs and IMA to fail the kexec */ > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > if (result < 0) > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > index ca2743f9c634..fe82e2525705 100644 > > --- a/kernel/kexec_core.c > > +++ b/kernel/kexec_core.c > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > struct kimage *kexec_image; > > struct kimage *kexec_crash_image; > > int kexec_load_disabled; > > +int kexec_reboot_disabled; > > #ifdef CONFIG_SYSCTL > > static struct ctl_table kexec_core_sysctls[] = { > > { > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > .extra1 = SYSCTL_ONE, > > .extra2 = SYSCTL_ONE, > > }, > > + { > > + .procname = "kexec_reboot_disabled", > > + .data = &kexec_reboot_disabled, > > + .maxlen = sizeof(int), > > + .mode = 0644, > > + /* only handle a transition from default "0" to "1" */ > > + .proc_handler = proc_dointvec_minmax, > > + .extra1 = SYSCTL_ONE, > > + .extra2 = SYSCTL_ONE, > > + }, > > { } > > }; > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > if (!kexec_trylock()) > > return -EBUSY; > > - if (!kexec_image) { > > + if (!kexec_image || kexec_reboot_disabled) { > > error = -EINVAL; > > goto Unlock; > > } > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > index 45637511e0de..583fba6de5cb 100644 > > --- a/kernel/kexec_file.c > > +++ b/kernel/kexec_file.c > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > return -EPERM; > > > > + /* Check if the system admin has disabled kexec reboot. */ > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > + && kexec_reboot_disabled) > > + return -EPERM; > > + > > /* Make sure we have a legal set of flags */ > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > return -EINVAL; > > >
Hi Ricardo, On Thu, 17 Nov 2022 16:15:07 +0100 Ricardo Ribalda <ribalda@chromium.org> wrote: > Hi Philipp > > Thanks for your review! happy to help. > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > Hi Ricardo, > > > > all in all I think this patch makes sense. However, there is one point > > I don't like... > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > attack surface to a system. > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > if they can create a panic(). > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > index 97394bd9d065..25d019682d33 100644 > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > @@ -462,6 +462,17 @@ altered. > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > +kexec_reboot_disabled > > > +===================== > > > + > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > +Once true, kexec can no longer be used for reboot and the toggle > > > +cannot be set back to false. > > > +This toggle does not affect the use of kexec during a crash. > > > + > > > + > > > kptr_restrict > > > ============= > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > index 41a686996aaa..15c3fad8918b 100644 > > > --- a/include/linux/kexec.h > > > +++ b/include/linux/kexec.h > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > extern struct kimage *kexec_image; > > > extern struct kimage *kexec_crash_image; > > > extern int kexec_load_disabled; > > > +extern int kexec_reboot_disabled; > > > > > > #ifndef kexec_flush_icache_page > > > #define kexec_flush_icache_page(page) > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > index cb8e6e6f983c..43063f803d81 100644 > > > --- a/kernel/kexec.c > > > +++ b/kernel/kexec.c > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > return -EPERM; > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > + return -EPERM; > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > an attacker is capable of creating a malicious kernel, planting it on > > the victims system and then find a way to boot it via kexec this > > attacker also knows how to load the malicious kernel as crashkernel and > > trigger a panic. So you haven't really gained anything. That's why I > > would simply drop this hunk (and the corresponding one from > > kexec_file_load) and let users who worry about this use a combination of > > kexec_load_disabled and kexec_reboot_disabled. > > If for whatever reason your sysadmin configured kexec_reboot_disabed > it can be nice that when a user try to load it they get a warning. > It is easier to debug than waiting two steps later when they run kexec -e.... I'm having second thoughts about this patch. My main problem is that I don't see a real use case where kexec_reboot_disabled is advantageous over kexec_load_disabled. The point is that disabling LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without a loaded kernel (when you don't have a kernel loaded you cannot reboot into it). With this the main use case of kexec_reboot_disabled is already covered by kexec_load_disabled. However, there are two differences 1) with kexec_reboot_disable you can still (re-)load a crash kernel e.g. to update the initramfs after a config change. But as discussed in my first mail this comes on the cost that an attacker could still load a malicious crash kernel and then 'panic into it'. 2) kexec_load_disabled also prevents unloading of a loaded kernel. So once loaded kexec_load_disabled cannot prevent the reboot into this kernel. For 1) I doubt that this is desired at all. My expectation is that on systems where a sysadmin restricts a user to reboot via kexec the sysadmin also wants to prevent the user to load an arbitrary crash kernel. Especially as this still keeps the loophole open you are trying to close. So only 2) is left as real benefit. But that is an extremely specific scenario. How often does this scenario happen in real life? What problem does kexec_reboot_disable solve different implementation (also in userspace) cannot? Sorry about being this pedantic but you want to introduce some new uapi which will be hard if not impossible to change once introduced. That's why I want to be a 100% sure it is really needed. Thanks Philipp > That is why I added it. But i am also ok removing it > > > > > Thanks > > Philipp > > > > > + > > > /* Permit LSMs and IMA to fail the kexec */ > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > if (result < 0) > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > index ca2743f9c634..fe82e2525705 100644 > > > --- a/kernel/kexec_core.c > > > +++ b/kernel/kexec_core.c > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > struct kimage *kexec_image; > > > struct kimage *kexec_crash_image; > > > int kexec_load_disabled; > > > +int kexec_reboot_disabled; > > > #ifdef CONFIG_SYSCTL > > > static struct ctl_table kexec_core_sysctls[] = { > > > { > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > .extra1 = SYSCTL_ONE, > > > .extra2 = SYSCTL_ONE, > > > }, > > > + { > > > + .procname = "kexec_reboot_disabled", > > > + .data = &kexec_reboot_disabled, > > > + .maxlen = sizeof(int), > > > + .mode = 0644, > > > + /* only handle a transition from default "0" to "1" */ > > > + .proc_handler = proc_dointvec_minmax, > > > + .extra1 = SYSCTL_ONE, > > > + .extra2 = SYSCTL_ONE, > > > + }, > > > { } > > > }; > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > if (!kexec_trylock()) > > > return -EBUSY; > > > - if (!kexec_image) { > > > + if (!kexec_image || kexec_reboot_disabled) { > > > error = -EINVAL; > > > goto Unlock; > > > } > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > index 45637511e0de..583fba6de5cb 100644 > > > --- a/kernel/kexec_file.c > > > +++ b/kernel/kexec_file.c > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > return -EPERM; > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > + && kexec_reboot_disabled) > > > + return -EPERM; > > > + > > > /* Make sure we have a legal set of flags */ > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > return -EINVAL; > > > > > > >
Hi Philipp Thanks for your review. My scenario is a trusted system, where even if you are root, your access to the system is very limited. Let's assume LOADPIN and verity are enabled. On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > Hi Ricardo, > > On Thu, 17 Nov 2022 16:15:07 +0100 > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > Hi Philipp > > > > Thanks for your review! > > happy to help. > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > Hi Ricardo, > > > > > > all in all I think this patch makes sense. However, there is one point > > > I don't like... > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > attack surface to a system. > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > if they can create a panic(). > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > index 97394bd9d065..25d019682d33 100644 > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > @@ -462,6 +462,17 @@ altered. > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > +kexec_reboot_disabled > > > > +===================== > > > > + > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > +cannot be set back to false. > > > > +This toggle does not affect the use of kexec during a crash. > > > > + > > > > + > > > > kptr_restrict > > > > ============= > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > --- a/include/linux/kexec.h > > > > +++ b/include/linux/kexec.h > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > extern struct kimage *kexec_image; > > > > extern struct kimage *kexec_crash_image; > > > > extern int kexec_load_disabled; > > > > +extern int kexec_reboot_disabled; > > > > > > > > #ifndef kexec_flush_icache_page > > > > #define kexec_flush_icache_page(page) > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > --- a/kernel/kexec.c > > > > +++ b/kernel/kexec.c > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > return -EPERM; > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > + return -EPERM; > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > an attacker is capable of creating a malicious kernel, planting it on > > > the victims system and then find a way to boot it via kexec this > > > attacker also knows how to load the malicious kernel as crashkernel and > > > trigger a panic. So you haven't really gained anything. That's why I > > > would simply drop this hunk (and the corresponding one from > > > kexec_file_load) and let users who worry about this use a combination of > > > kexec_load_disabled and kexec_reboot_disabled. > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > it can be nice that when a user try to load it they get a warning. > > It is easier to debug than waiting two steps later when they run kexec -e.... > > I'm having second thoughts about this patch. My main problem is that I > don't see a real use case where kexec_reboot_disabled is advantageous > over kexec_load_disabled. The point is that disabling > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > a loaded kernel (when you don't have a kernel loaded you cannot reboot > into it). With this the main use case of kexec_reboot_disabled is > already covered by kexec_load_disabled. > > However, there are two differences > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > e.g. to update the initramfs after a config change. But as discussed in > my first mail this comes on the cost that an attacker could still load a > malicious crash kernel and then 'panic into it'. That crash kernel must be already in the signed malicious kernel. which reduces the chances of attack. Plus an attacker must be able to panic the current kernel at will, instead of just call reset. > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > once loaded kexec_load_disabled cannot prevent the reboot into this > kernel. > > > For 1) I doubt that this is desired at all. My expectation is that on > systems where a sysadmin restricts a user to reboot via kexec the > sysadmin also wants to prevent the user to load an arbitrary crash > kernel. Especially as this still keeps the loophole open you are trying > to close. > > So only 2) is left as real benefit. But that is an extremely specific > scenario. How often does this scenario happen in real life? What > problem does kexec_reboot_disable solve different implementation > (also in userspace) cannot? > > Sorry about being this pedantic but you want to introduce some new uapi > which will be hard if not impossible to change once introduced. That's > why I want to be a 100% sure it is really needed. No worries. Completely understand :). Thanks for taking this seriously.. Best regards! > > Thanks > Philipp > > > > That is why I added it. But i am also ok removing it > > > > > > > > Thanks > > > Philipp > > > > > > > + > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > if (result < 0) > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > index ca2743f9c634..fe82e2525705 100644 > > > > --- a/kernel/kexec_core.c > > > > +++ b/kernel/kexec_core.c > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > struct kimage *kexec_image; > > > > struct kimage *kexec_crash_image; > > > > int kexec_load_disabled; > > > > +int kexec_reboot_disabled; > > > > #ifdef CONFIG_SYSCTL > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > { > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > .extra1 = SYSCTL_ONE, > > > > .extra2 = SYSCTL_ONE, > > > > }, > > > > + { > > > > + .procname = "kexec_reboot_disabled", > > > > + .data = &kexec_reboot_disabled, > > > > + .maxlen = sizeof(int), > > > > + .mode = 0644, > > > > + /* only handle a transition from default "0" to "1" */ > > > > + .proc_handler = proc_dointvec_minmax, > > > > + .extra1 = SYSCTL_ONE, > > > > + .extra2 = SYSCTL_ONE, > > > > + }, > > > > { } > > > > }; > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > if (!kexec_trylock()) > > > > return -EBUSY; > > > > - if (!kexec_image) { > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > error = -EINVAL; > > > > goto Unlock; > > > > } > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > index 45637511e0de..583fba6de5cb 100644 > > > > --- a/kernel/kexec_file.c > > > > +++ b/kernel/kexec_file.c > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > return -EPERM; > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > + && kexec_reboot_disabled) > > > > + return -EPERM; > > > > + > > > > /* Make sure we have a legal set of flags */ > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > return -EINVAL; > > > > > > > > > > > >
On 11/14/22 at 02:18pm, Ricardo Ribalda wrote: > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the ~ toggle > attack surface to a system. > > Without this toogle, an attacker can only reboot into a different kernel ~~s/without/with/ > if they can create a panic(). The log just tells what it's doing, but miss the most important why this has to be needed, the motivation. I roughly read the talking between you and Philipp, wondering why do you believe panicked kernel, if you worry about the untrusted kernel kexec rebooted into. People can change scripts in initramfs, e.g drop into emergency shell and switch into rootfs, there are a lot of things people can do in there too. > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > index 97394bd9d065..25d019682d33 100644 > --- a/Documentation/admin-guide/sysctl/kernel.rst > +++ b/Documentation/admin-guide/sysctl/kernel.rst > @@ -462,6 +462,17 @@ altered. > Generally used together with the `modules_disabled`_ sysctl. > > > +kexec_reboot_disabled > +===================== > + > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > +Once true, kexec can no longer be used for reboot and the toggle > +cannot be set back to false. > +This toggle does not affect the use of kexec during a crash. > + > + > kptr_restrict > ============= > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > index 41a686996aaa..15c3fad8918b 100644 > --- a/include/linux/kexec.h > +++ b/include/linux/kexec.h > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > extern struct kimage *kexec_image; > extern struct kimage *kexec_crash_image; > extern int kexec_load_disabled; > +extern int kexec_reboot_disabled; > > #ifndef kexec_flush_icache_page > #define kexec_flush_icache_page(page) > diff --git a/kernel/kexec.c b/kernel/kexec.c > index cb8e6e6f983c..43063f803d81 100644 > --- a/kernel/kexec.c > +++ b/kernel/kexec.c > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > return -EPERM; > > + /* Check if the system admin has disabled kexec reboot. */ > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > + return -EPERM; > + > /* Permit LSMs and IMA to fail the kexec */ > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > if (result < 0) > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > index ca2743f9c634..fe82e2525705 100644 > --- a/kernel/kexec_core.c > +++ b/kernel/kexec_core.c > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > struct kimage *kexec_image; > struct kimage *kexec_crash_image; > int kexec_load_disabled; > +int kexec_reboot_disabled; > #ifdef CONFIG_SYSCTL > static struct ctl_table kexec_core_sysctls[] = { > { > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > .extra1 = SYSCTL_ONE, > .extra2 = SYSCTL_ONE, > }, > + { > + .procname = "kexec_reboot_disabled", > + .data = &kexec_reboot_disabled, > + .maxlen = sizeof(int), > + .mode = 0644, > + /* only handle a transition from default "0" to "1" */ > + .proc_handler = proc_dointvec_minmax, > + .extra1 = SYSCTL_ONE, > + .extra2 = SYSCTL_ONE, > + }, > { } > }; > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > if (!kexec_trylock()) > return -EBUSY; > - if (!kexec_image) { > + if (!kexec_image || kexec_reboot_disabled) { > error = -EINVAL; > goto Unlock; > } > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > index 45637511e0de..583fba6de5cb 100644 > --- a/kernel/kexec_file.c > +++ b/kernel/kexec_file.c > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > return -EPERM; > > + /* Check if the system admin has disabled kexec reboot. */ > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > + && kexec_reboot_disabled) > + return -EPERM; > + > /* Make sure we have a legal set of flags */ > if (flags != (flags & KEXEC_FILE_FLAGS)) > return -EINVAL; > > -- > b4 0.11.0-dev-d93f8 >
Hi Ricardo, On Wed, 23 Nov 2022 09:58:08 +0100 Ricardo Ribalda <ribalda@chromium.org> wrote: > Hi Philipp > > Thanks for your review. > > My scenario is a trusted system, where even if you are root, your > access to the system is very limited. > > Let's assume LOADPIN and verity are enabled. My point is that on such systems I expect that a sysadmin also wants to control the crash kernel including its initramfs (which also has to be part of the signed kernel?). But if that's the case a sysadmin can simply arm kdump early during boot and then toggle kexec_load_disabled. With that LINUX_REBOOT_CMD_KEXEC also gets disabled as no kexec kernel can be loaded while kdump works. Thus there is no need to add the new interface. Or am I missing anything? Thanks Philipp > > On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > > > Hi Ricardo, > > > > On Thu, 17 Nov 2022 16:15:07 +0100 > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > Hi Philipp > > > > > > Thanks for your review! > > > > happy to help. > > > > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > Hi Ricardo, > > > > > > > > all in all I think this patch makes sense. However, there is one point > > > > I don't like... > > > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > > attack surface to a system. > > > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > > if they can create a panic(). > > > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > > index 97394bd9d065..25d019682d33 100644 > > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > > @@ -462,6 +462,17 @@ altered. > > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > > > > +kexec_reboot_disabled > > > > > +===================== > > > > > + > > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > > +cannot be set back to false. > > > > > +This toggle does not affect the use of kexec during a crash. > > > > > + > > > > > + > > > > > kptr_restrict > > > > > ============= > > > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > > --- a/include/linux/kexec.h > > > > > +++ b/include/linux/kexec.h > > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > > extern struct kimage *kexec_image; > > > > > extern struct kimage *kexec_crash_image; > > > > > extern int kexec_load_disabled; > > > > > +extern int kexec_reboot_disabled; > > > > > > > > > > #ifndef kexec_flush_icache_page > > > > > #define kexec_flush_icache_page(page) > > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > > --- a/kernel/kexec.c > > > > > +++ b/kernel/kexec.c > > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > return -EPERM; > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > > + return -EPERM; > > > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > > an attacker is capable of creating a malicious kernel, planting it on > > > > the victims system and then find a way to boot it via kexec this > > > > attacker also knows how to load the malicious kernel as crashkernel and > > > > trigger a panic. So you haven't really gained anything. That's why I > > > > would simply drop this hunk (and the corresponding one from > > > > kexec_file_load) and let users who worry about this use a combination of > > > > kexec_load_disabled and kexec_reboot_disabled. > > > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > > it can be nice that when a user try to load it they get a warning. > > > It is easier to debug than waiting two steps later when they run kexec -e.... > > > > I'm having second thoughts about this patch. My main problem is that I > > don't see a real use case where kexec_reboot_disabled is advantageous > > over kexec_load_disabled. The point is that disabling > > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > > a loaded kernel (when you don't have a kernel loaded you cannot reboot > > into it). With this the main use case of kexec_reboot_disabled is > > already covered by kexec_load_disabled. > > > > > However, there are two differences > > > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > > e.g. to update the initramfs after a config change. But as discussed in > > my first mail this comes on the cost that an attacker could still load a > > malicious crash kernel and then 'panic into it'. > > That crash kernel must be already in the signed malicious kernel. > which reduces the chances of attack. > Plus an attacker must be able to panic the current kernel at will, > instead of just call reset. > > > > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > > once loaded kexec_load_disabled cannot prevent the reboot into this > > kernel. > > > > > > For 1) I doubt that this is desired at all. My expectation is that on > > systems where a sysadmin restricts a user to reboot via kexec the > > sysadmin also wants to prevent the user to load an arbitrary crash > > kernel. Especially as this still keeps the loophole open you are trying > > to close. > > > > So only 2) is left as real benefit. But that is an extremely specific > > scenario. How often does this scenario happen in real life? What > > problem does kexec_reboot_disable solve different implementation > > (also in userspace) cannot? > > > > Sorry about being this pedantic but you want to introduce some new uapi > > which will be hard if not impossible to change once introduced. That's > > why I want to be a 100% sure it is really needed. > > No worries. Completely understand :). Thanks for taking this seriously.. > > > Best regards! > > > > Thanks > > Philipp > > > > > > > That is why I added it. But i am also ok removing it > > > > > > > > > > > Thanks > > > > Philipp > > > > > > > > > + > > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > > if (result < 0) > > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > > index ca2743f9c634..fe82e2525705 100644 > > > > > --- a/kernel/kexec_core.c > > > > > +++ b/kernel/kexec_core.c > > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > > struct kimage *kexec_image; > > > > > struct kimage *kexec_crash_image; > > > > > int kexec_load_disabled; > > > > > +int kexec_reboot_disabled; > > > > > #ifdef CONFIG_SYSCTL > > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > > { > > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > > .extra1 = SYSCTL_ONE, > > > > > .extra2 = SYSCTL_ONE, > > > > > }, > > > > > + { > > > > > + .procname = "kexec_reboot_disabled", > > > > > + .data = &kexec_reboot_disabled, > > > > > + .maxlen = sizeof(int), > > > > > + .mode = 0644, > > > > > + /* only handle a transition from default "0" to "1" */ > > > > > + .proc_handler = proc_dointvec_minmax, > > > > > + .extra1 = SYSCTL_ONE, > > > > > + .extra2 = SYSCTL_ONE, > > > > > + }, > > > > > { } > > > > > }; > > > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > > > if (!kexec_trylock()) > > > > > return -EBUSY; > > > > > - if (!kexec_image) { > > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > > error = -EINVAL; > > > > > goto Unlock; > > > > > } > > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > > index 45637511e0de..583fba6de5cb 100644 > > > > > --- a/kernel/kexec_file.c > > > > > +++ b/kernel/kexec_file.c > > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > return -EPERM; > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > > + && kexec_reboot_disabled) > > > > > + return -EPERM; > > > > > + > > > > > /* Make sure we have a legal set of flags */ > > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > > return -EINVAL; > > > > > > > > > > > > > > > > > > >
On Thu, 24 Nov 2022 at 12:40, Philipp Rudo <prudo@redhat.com> wrote: > > Hi Ricardo, > > On Wed, 23 Nov 2022 09:58:08 +0100 > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > Hi Philipp > > > > Thanks for your review. > > > > My scenario is a trusted system, where even if you are root, your > > access to the system is very limited. > > > > Let's assume LOADPIN and verity are enabled. > > My point is that on such systems I expect that a sysadmin also wants to > control the crash kernel including its initramfs (which also has to be part > of the signed kernel?). But if that's the case a sysadmin can simply arm > kdump early during boot and then toggle kexec_load_disabled. With that > LINUX_REBOOT_CMD_KEXEC also gets disabled as no kexec kernel can be loaded > while kdump works. Thus there is no need to add the new interface. Or am > I missing anything? Let's say that you have a script that does something like this kexec -p dump_kernel echo 1 > /proc/sys/kernel/kexec_load_disabled If an attacker can DDos the system and make that script crash... then kexec is still accessible On the other hand, if you load the kernel with the commandline sysctl.kernel.kexec_load_disabled=1 Then even if the script crashes, the only way to abuse kexec is by panicing the running kernel.... Would it make you more comfortable if I model this as a kernel config instead of a runtime option? Thanks! > > Thanks > Philipp > > > > > On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > Hi Ricardo, > > > > > > On Thu, 17 Nov 2022 16:15:07 +0100 > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > Hi Philipp > > > > > > > > Thanks for your review! > > > > > > happy to help. > > > > > > > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > Hi Ricardo, > > > > > > > > > > all in all I think this patch makes sense. However, there is one point > > > > > I don't like... > > > > > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > > > attack surface to a system. > > > > > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > > > if they can create a panic(). > > > > > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > index 97394bd9d065..25d019682d33 100644 > > > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > @@ -462,6 +462,17 @@ altered. > > > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > > > > > > > +kexec_reboot_disabled > > > > > > +===================== > > > > > > + > > > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > > > +cannot be set back to false. > > > > > > +This toggle does not affect the use of kexec during a crash. > > > > > > + > > > > > > + > > > > > > kptr_restrict > > > > > > ============= > > > > > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > > > --- a/include/linux/kexec.h > > > > > > +++ b/include/linux/kexec.h > > > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > > > extern struct kimage *kexec_image; > > > > > > extern struct kimage *kexec_crash_image; > > > > > > extern int kexec_load_disabled; > > > > > > +extern int kexec_reboot_disabled; > > > > > > > > > > > > #ifndef kexec_flush_icache_page > > > > > > #define kexec_flush_icache_page(page) > > > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > > > --- a/kernel/kexec.c > > > > > > +++ b/kernel/kexec.c > > > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > return -EPERM; > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > > > + return -EPERM; > > > > > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > > > an attacker is capable of creating a malicious kernel, planting it on > > > > > the victims system and then find a way to boot it via kexec this > > > > > attacker also knows how to load the malicious kernel as crashkernel and > > > > > trigger a panic. So you haven't really gained anything. That's why I > > > > > would simply drop this hunk (and the corresponding one from > > > > > kexec_file_load) and let users who worry about this use a combination of > > > > > kexec_load_disabled and kexec_reboot_disabled. > > > > > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > > > it can be nice that when a user try to load it they get a warning. > > > > It is easier to debug than waiting two steps later when they run kexec -e.... > > > > > > I'm having second thoughts about this patch. My main problem is that I > > > don't see a real use case where kexec_reboot_disabled is advantageous > > > over kexec_load_disabled. The point is that disabling > > > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > > > a loaded kernel (when you don't have a kernel loaded you cannot reboot > > > into it). With this the main use case of kexec_reboot_disabled is > > > already covered by kexec_load_disabled. > > > > > > > > However, there are two differences > > > > > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > > > e.g. to update the initramfs after a config change. But as discussed in > > > my first mail this comes on the cost that an attacker could still load a > > > malicious crash kernel and then 'panic into it'. > > > > That crash kernel must be already in the signed malicious kernel. > > which reduces the chances of attack. > > Plus an attacker must be able to panic the current kernel at will, > > instead of just call reset. > > > > > > > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > > > once loaded kexec_load_disabled cannot prevent the reboot into this > > > kernel. > > > > > > > > > For 1) I doubt that this is desired at all. My expectation is that on > > > systems where a sysadmin restricts a user to reboot via kexec the > > > sysadmin also wants to prevent the user to load an arbitrary crash > > > kernel. Especially as this still keeps the loophole open you are trying > > > to close. > > > > > > So only 2) is left as real benefit. But that is an extremely specific > > > scenario. How often does this scenario happen in real life? What > > > problem does kexec_reboot_disable solve different implementation > > > (also in userspace) cannot? > > > > > > Sorry about being this pedantic but you want to introduce some new uapi > > > which will be hard if not impossible to change once introduced. That's > > > why I want to be a 100% sure it is really needed. > > > > No worries. Completely understand :). Thanks for taking this seriously.. > > > > > > Best regards! > > > > > > Thanks > > > Philipp > > > > > > > > > > That is why I added it. But i am also ok removing it > > > > > > > > > > > > > > Thanks > > > > > Philipp > > > > > > > > > > > + > > > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > > > if (result < 0) > > > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > > > index ca2743f9c634..fe82e2525705 100644 > > > > > > --- a/kernel/kexec_core.c > > > > > > +++ b/kernel/kexec_core.c > > > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > > > struct kimage *kexec_image; > > > > > > struct kimage *kexec_crash_image; > > > > > > int kexec_load_disabled; > > > > > > +int kexec_reboot_disabled; > > > > > > #ifdef CONFIG_SYSCTL > > > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > > > { > > > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > > > .extra1 = SYSCTL_ONE, > > > > > > .extra2 = SYSCTL_ONE, > > > > > > }, > > > > > > + { > > > > > > + .procname = "kexec_reboot_disabled", > > > > > > + .data = &kexec_reboot_disabled, > > > > > > + .maxlen = sizeof(int), > > > > > > + .mode = 0644, > > > > > > + /* only handle a transition from default "0" to "1" */ > > > > > > + .proc_handler = proc_dointvec_minmax, > > > > > > + .extra1 = SYSCTL_ONE, > > > > > > + .extra2 = SYSCTL_ONE, > > > > > > + }, > > > > > > { } > > > > > > }; > > > > > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > > > > > if (!kexec_trylock()) > > > > > > return -EBUSY; > > > > > > - if (!kexec_image) { > > > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > > > error = -EINVAL; > > > > > > goto Unlock; > > > > > > } > > > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > > > index 45637511e0de..583fba6de5cb 100644 > > > > > > --- a/kernel/kexec_file.c > > > > > > +++ b/kernel/kexec_file.c > > > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > return -EPERM; > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > > > + && kexec_reboot_disabled) > > > > > > + return -EPERM; > > > > > > + > > > > > > /* Make sure we have a legal set of flags */ > > > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > > > return -EINVAL; > > > > > > > > > > > > > > > > > > > > > > > > > > >
On Thu, 24 Nov 2022 13:52:58 +0100 Ricardo Ribalda <ribalda@chromium.org> wrote: > On Thu, 24 Nov 2022 at 12:40, Philipp Rudo <prudo@redhat.com> wrote: > > > > Hi Ricardo, > > > > On Wed, 23 Nov 2022 09:58:08 +0100 > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > Hi Philipp > > > > > > Thanks for your review. > > > > > > My scenario is a trusted system, where even if you are root, your > > > access to the system is very limited. > > > > > > Let's assume LOADPIN and verity are enabled. > > > > My point is that on such systems I expect that a sysadmin also wants to > > control the crash kernel including its initramfs (which also has to be part > > of the signed kernel?). But if that's the case a sysadmin can simply arm > > kdump early during boot and then toggle kexec_load_disabled. With that > > LINUX_REBOOT_CMD_KEXEC also gets disabled as no kexec kernel can be loaded > > while kdump works. Thus there is no need to add the new interface. Or am > > I missing anything? > > Let's say that you have a script that does something like this > > > kexec -p dump_kernel > echo 1 > /proc/sys/kernel/kexec_load_disabled > > If an attacker can DDos the system and make that script crash... then > kexec is still accessible > > On the other hand, if you load the kernel with the commandline > > sysctl.kernel.kexec_load_disabled=1 ^^^^ reboot? Otherwise you shouldn't be able to load the crash kernel at all. > Then even if the script crashes, the only way to abuse kexec is by > panicing the running kernel.... True. But when an attacker can DDos the system the final workload is already running. So wouldn't it be enough to make sure that the script above has finished before starting you workload. E.g. by setting an appropriate Before=/After= in the systemd.unit? Furthermore, I don't think that restricting kexec reboot alone is sufficient when the attacker can still control the crash kernel. At least my assumption is that triggering a panic instead of just rebooting is just a mild inconvenience for somebody who is able to pull off an attack like that. > Would it make you more comfortable if I model this as a kernel config > instead of a runtime option? No, I think the implementation is fine. I'm currently only struggling to understand what problem kexec_reboot_disabled solves that cannot be solved by kexec_load_disabled. > Thanks! Happy to help. Thanks Philipp > > > > > > Thanks > > Philipp > > > > > > > > On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > Hi Ricardo, > > > > > > > > On Thu, 17 Nov 2022 16:15:07 +0100 > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > Hi Philipp > > > > > > > > > > Thanks for your review! > > > > > > > > happy to help. > > > > > > > > > > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > > > Hi Ricardo, > > > > > > > > > > > > all in all I think this patch makes sense. However, there is one point > > > > > > I don't like... > > > > > > > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > > > > attack surface to a system. > > > > > > > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > > > > if they can create a panic(). > > > > > > > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > index 97394bd9d065..25d019682d33 100644 > > > > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > @@ -462,6 +462,17 @@ altered. > > > > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > > > > > > > > > > +kexec_reboot_disabled > > > > > > > +===================== > > > > > > > + > > > > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > > > > +cannot be set back to false. > > > > > > > +This toggle does not affect the use of kexec during a crash. > > > > > > > + > > > > > > > + > > > > > > > kptr_restrict > > > > > > > ============= > > > > > > > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > > > > --- a/include/linux/kexec.h > > > > > > > +++ b/include/linux/kexec.h > > > > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > > > > extern struct kimage *kexec_image; > > > > > > > extern struct kimage *kexec_crash_image; > > > > > > > extern int kexec_load_disabled; > > > > > > > +extern int kexec_reboot_disabled; > > > > > > > > > > > > > > #ifndef kexec_flush_icache_page > > > > > > > #define kexec_flush_icache_page(page) > > > > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > > > > --- a/kernel/kexec.c > > > > > > > +++ b/kernel/kexec.c > > > > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > return -EPERM; > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > > > > + return -EPERM; > > > > > > > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > > > > an attacker is capable of creating a malicious kernel, planting it on > > > > > > the victims system and then find a way to boot it via kexec this > > > > > > attacker also knows how to load the malicious kernel as crashkernel and > > > > > > trigger a panic. So you haven't really gained anything. That's why I > > > > > > would simply drop this hunk (and the corresponding one from > > > > > > kexec_file_load) and let users who worry about this use a combination of > > > > > > kexec_load_disabled and kexec_reboot_disabled. > > > > > > > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > > > > it can be nice that when a user try to load it they get a warning. > > > > > It is easier to debug than waiting two steps later when they run kexec -e.... > > > > > > > > I'm having second thoughts about this patch. My main problem is that I > > > > don't see a real use case where kexec_reboot_disabled is advantageous > > > > over kexec_load_disabled. The point is that disabling > > > > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > > > > a loaded kernel (when you don't have a kernel loaded you cannot reboot > > > > into it). With this the main use case of kexec_reboot_disabled is > > > > already covered by kexec_load_disabled. > > > > > > > > > > > However, there are two differences > > > > > > > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > > > > e.g. to update the initramfs after a config change. But as discussed in > > > > my first mail this comes on the cost that an attacker could still load a > > > > malicious crash kernel and then 'panic into it'. > > > > > > That crash kernel must be already in the signed malicious kernel. > > > which reduces the chances of attack. > > > Plus an attacker must be able to panic the current kernel at will, > > > instead of just call reset. > > > > > > > > > > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > > > > once loaded kexec_load_disabled cannot prevent the reboot into this > > > > kernel. > > > > > > > > > > > > For 1) I doubt that this is desired at all. My expectation is that on > > > > systems where a sysadmin restricts a user to reboot via kexec the > > > > sysadmin also wants to prevent the user to load an arbitrary crash > > > > kernel. Especially as this still keeps the loophole open you are trying > > > > to close. > > > > > > > > So only 2) is left as real benefit. But that is an extremely specific > > > > scenario. How often does this scenario happen in real life? What > > > > problem does kexec_reboot_disable solve different implementation > > > > (also in userspace) cannot? > > > > > > > > Sorry about being this pedantic but you want to introduce some new uapi > > > > which will be hard if not impossible to change once introduced. That's > > > > why I want to be a 100% sure it is really needed. > > > > > > No worries. Completely understand :). Thanks for taking this seriously.. > > > > > > > > > Best regards! > > > > > > > > Thanks > > > > Philipp > > > > > > > > > > > > > That is why I added it. But i am also ok removing it > > > > > > > > > > > > > > > > > Thanks > > > > > > Philipp > > > > > > > > > > > > > + > > > > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > > > > if (result < 0) > > > > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > > > > index ca2743f9c634..fe82e2525705 100644 > > > > > > > --- a/kernel/kexec_core.c > > > > > > > +++ b/kernel/kexec_core.c > > > > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > > > > struct kimage *kexec_image; > > > > > > > struct kimage *kexec_crash_image; > > > > > > > int kexec_load_disabled; > > > > > > > +int kexec_reboot_disabled; > > > > > > > #ifdef CONFIG_SYSCTL > > > > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > > > > { > > > > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > > > > .extra1 = SYSCTL_ONE, > > > > > > > .extra2 = SYSCTL_ONE, > > > > > > > }, > > > > > > > + { > > > > > > > + .procname = "kexec_reboot_disabled", > > > > > > > + .data = &kexec_reboot_disabled, > > > > > > > + .maxlen = sizeof(int), > > > > > > > + .mode = 0644, > > > > > > > + /* only handle a transition from default "0" to "1" */ > > > > > > > + .proc_handler = proc_dointvec_minmax, > > > > > > > + .extra1 = SYSCTL_ONE, > > > > > > > + .extra2 = SYSCTL_ONE, > > > > > > > + }, > > > > > > > { } > > > > > > > }; > > > > > > > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > > > > > > > if (!kexec_trylock()) > > > > > > > return -EBUSY; > > > > > > > - if (!kexec_image) { > > > > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > > > > error = -EINVAL; > > > > > > > goto Unlock; > > > > > > > } > > > > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > > > > index 45637511e0de..583fba6de5cb 100644 > > > > > > > --- a/kernel/kexec_file.c > > > > > > > +++ b/kernel/kexec_file.c > > > > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > return -EPERM; > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > > > > + && kexec_reboot_disabled) > > > > > > > + return -EPERM; > > > > > > > + > > > > > > > /* Make sure we have a legal set of flags */ > > > > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > > > > return -EINVAL; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
Hi Philipp On Thu, 24 Nov 2022 at 16:01, Philipp Rudo <prudo@redhat.com> wrote: > > On Thu, 24 Nov 2022 13:52:58 +0100 > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > On Thu, 24 Nov 2022 at 12:40, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > Hi Ricardo, > > > > > > On Wed, 23 Nov 2022 09:58:08 +0100 > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > Hi Philipp > > > > > > > > Thanks for your review. > > > > > > > > My scenario is a trusted system, where even if you are root, your > > > > access to the system is very limited. > > > > > > > > Let's assume LOADPIN and verity are enabled. > > > > > > My point is that on such systems I expect that a sysadmin also wants to > > > control the crash kernel including its initramfs (which also has to be part > > > of the signed kernel?). But if that's the case a sysadmin can simply arm > > > kdump early during boot and then toggle kexec_load_disabled. With that > > > LINUX_REBOOT_CMD_KEXEC also gets disabled as no kexec kernel can be loaded > > > while kdump works. Thus there is no need to add the new interface. Or am > > > I missing anything? > > > > Let's say that you have a script that does something like this > > > > > > kexec -p dump_kernel > > echo 1 > /proc/sys/kernel/kexec_load_disabled > > > > If an attacker can DDos the system and make that script crash... then > > kexec is still accessible > > > > On the other hand, if you load the kernel with the commandline > > > > sysctl.kernel.kexec_load_disabled=1 > ^^^^ > reboot? yes :) thanks! > Otherwise you shouldn't be able to load the crash kernel at all. > > > Then even if the script crashes, the only way to abuse kexec is by > > panicing the running kernel.... > > True. But when an attacker can DDos the system the final workload is > already running. So wouldn't it be enough to make sure that the script > above has finished before starting you workload. E.g. by setting an > appropriate Before=/After= in the systemd.unit? What if the kexec binary crashes and the unit will never succeed? Or worse, your distro does not use systemd !!! > > Furthermore, I don't think that restricting kexec reboot alone is > sufficient when the attacker can still control the crash kernel. At > least my assumption is that triggering a panic instead of just > rebooting is just a mild inconvenience for somebody who is able to pull > off an attack like that. The attacker does not control the crash kernel completely. loadpin is still in place. Yes, they can downgrade the whole system to a vulnerable kernel image. But the choices are limited :) With physical access to the device panicing a kernel is easily doable (but not trivial). But remotely, it is more challenging. > > > Would it make you more comfortable if I model this as a kernel config > > instead of a runtime option? > > No, I think the implementation is fine. I'm currently only struggling > to understand what problem kexec_reboot_disabled solves that cannot be > solved by kexec_load_disabled. > > > Thanks! > > Happy to help. > > Thanks > Philipp > > > > > > > > > > > Thanks > > > Philipp > > > > > > > > > > > On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > Hi Ricardo, > > > > > > > > > > On Thu, 17 Nov 2022 16:15:07 +0100 > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > Hi Philipp > > > > > > > > > > > > Thanks for your review! > > > > > > > > > > happy to help. > > > > > > > > > > > > > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > > > > > Hi Ricardo, > > > > > > > > > > > > > > all in all I think this patch makes sense. However, there is one point > > > > > > > I don't like... > > > > > > > > > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > > > > > attack surface to a system. > > > > > > > > > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > > > > > if they can create a panic(). > > > > > > > > > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > index 97394bd9d065..25d019682d33 100644 > > > > > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > @@ -462,6 +462,17 @@ altered. > > > > > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > > > > > > > > > > > > > +kexec_reboot_disabled > > > > > > > > +===================== > > > > > > > > + > > > > > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > > > > > +cannot be set back to false. > > > > > > > > +This toggle does not affect the use of kexec during a crash. > > > > > > > > + > > > > > > > > + > > > > > > > > kptr_restrict > > > > > > > > ============= > > > > > > > > > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > > > > > --- a/include/linux/kexec.h > > > > > > > > +++ b/include/linux/kexec.h > > > > > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > > > > > extern struct kimage *kexec_image; > > > > > > > > extern struct kimage *kexec_crash_image; > > > > > > > > extern int kexec_load_disabled; > > > > > > > > +extern int kexec_reboot_disabled; > > > > > > > > > > > > > > > > #ifndef kexec_flush_icache_page > > > > > > > > #define kexec_flush_icache_page(page) > > > > > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > > > > > --- a/kernel/kexec.c > > > > > > > > +++ b/kernel/kexec.c > > > > > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > > return -EPERM; > > > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > > > > > + return -EPERM; > > > > > > > > > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > > > > > an attacker is capable of creating a malicious kernel, planting it on > > > > > > > the victims system and then find a way to boot it via kexec this > > > > > > > attacker also knows how to load the malicious kernel as crashkernel and > > > > > > > trigger a panic. So you haven't really gained anything. That's why I > > > > > > > would simply drop this hunk (and the corresponding one from > > > > > > > kexec_file_load) and let users who worry about this use a combination of > > > > > > > kexec_load_disabled and kexec_reboot_disabled. > > > > > > > > > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > > > > > it can be nice that when a user try to load it they get a warning. > > > > > > It is easier to debug than waiting two steps later when they run kexec -e.... > > > > > > > > > > I'm having second thoughts about this patch. My main problem is that I > > > > > don't see a real use case where kexec_reboot_disabled is advantageous > > > > > over kexec_load_disabled. The point is that disabling > > > > > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > > > > > a loaded kernel (when you don't have a kernel loaded you cannot reboot > > > > > into it). With this the main use case of kexec_reboot_disabled is > > > > > already covered by kexec_load_disabled. > > > > > > > > > > > > > > However, there are two differences > > > > > > > > > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > > > > > e.g. to update the initramfs after a config change. But as discussed in > > > > > my first mail this comes on the cost that an attacker could still load a > > > > > malicious crash kernel and then 'panic into it'. > > > > > > > > That crash kernel must be already in the signed malicious kernel. > > > > which reduces the chances of attack. > > > > Plus an attacker must be able to panic the current kernel at will, > > > > instead of just call reset. > > > > > > > > > > > > > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > > > > > once loaded kexec_load_disabled cannot prevent the reboot into this > > > > > kernel. > > > > > > > > > > > > > > > For 1) I doubt that this is desired at all. My expectation is that on > > > > > systems where a sysadmin restricts a user to reboot via kexec the > > > > > sysadmin also wants to prevent the user to load an arbitrary crash > > > > > kernel. Especially as this still keeps the loophole open you are trying > > > > > to close. > > > > > > > > > > So only 2) is left as real benefit. But that is an extremely specific > > > > > scenario. How often does this scenario happen in real life? What > > > > > problem does kexec_reboot_disable solve different implementation > > > > > (also in userspace) cannot? > > > > > > > > > > Sorry about being this pedantic but you want to introduce some new uapi > > > > > which will be hard if not impossible to change once introduced. That's > > > > > why I want to be a 100% sure it is really needed. > > > > > > > > No worries. Completely understand :). Thanks for taking this seriously.. > > > > > > > > > > > > Best regards! > > > > > > > > > > Thanks > > > > > Philipp > > > > > > > > > > > > > > > > That is why I added it. But i am also ok removing it > > > > > > > > > > > > > > > > > > > > Thanks > > > > > > > Philipp > > > > > > > > > > > > > > > + > > > > > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > > > > > if (result < 0) > > > > > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > > > > > index ca2743f9c634..fe82e2525705 100644 > > > > > > > > --- a/kernel/kexec_core.c > > > > > > > > +++ b/kernel/kexec_core.c > > > > > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > > > > > struct kimage *kexec_image; > > > > > > > > struct kimage *kexec_crash_image; > > > > > > > > int kexec_load_disabled; > > > > > > > > +int kexec_reboot_disabled; > > > > > > > > #ifdef CONFIG_SYSCTL > > > > > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > > > > > { > > > > > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > > > > > .extra1 = SYSCTL_ONE, > > > > > > > > .extra2 = SYSCTL_ONE, > > > > > > > > }, > > > > > > > > + { > > > > > > > > + .procname = "kexec_reboot_disabled", > > > > > > > > + .data = &kexec_reboot_disabled, > > > > > > > > + .maxlen = sizeof(int), > > > > > > > > + .mode = 0644, > > > > > > > > + /* only handle a transition from default "0" to "1" */ > > > > > > > > + .proc_handler = proc_dointvec_minmax, > > > > > > > > + .extra1 = SYSCTL_ONE, > > > > > > > > + .extra2 = SYSCTL_ONE, > > > > > > > > + }, > > > > > > > > { } > > > > > > > > }; > > > > > > > > > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > > > > > > > > > if (!kexec_trylock()) > > > > > > > > return -EBUSY; > > > > > > > > - if (!kexec_image) { > > > > > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > > > > > error = -EINVAL; > > > > > > > > goto Unlock; > > > > > > > > } > > > > > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > > > > > index 45637511e0de..583fba6de5cb 100644 > > > > > > > > --- a/kernel/kexec_file.c > > > > > > > > +++ b/kernel/kexec_file.c > > > > > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > > return -EPERM; > > > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > > > > > + && kexec_reboot_disabled) > > > > > > > > + return -EPERM; > > > > > > > > + > > > > > > > > /* Make sure we have a legal set of flags */ > > > > > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > > > > > return -EINVAL; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
Hi Ricardo, On Thu, 24 Nov 2022 23:32:34 +0100 Ricardo Ribalda <ribalda@chromium.org> wrote: > Hi Philipp > > > On Thu, 24 Nov 2022 at 16:01, Philipp Rudo <prudo@redhat.com> wrote: > > > > On Thu, 24 Nov 2022 13:52:58 +0100 > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > On Thu, 24 Nov 2022 at 12:40, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > Hi Ricardo, > > > > > > > > On Wed, 23 Nov 2022 09:58:08 +0100 > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > Hi Philipp > > > > > > > > > > Thanks for your review. > > > > > > > > > > My scenario is a trusted system, where even if you are root, your > > > > > access to the system is very limited. > > > > > > > > > > Let's assume LOADPIN and verity are enabled. > > > > > > > > My point is that on such systems I expect that a sysadmin also wants to > > > > control the crash kernel including its initramfs (which also has to be part > > > > of the signed kernel?). But if that's the case a sysadmin can simply arm > > > > kdump early during boot and then toggle kexec_load_disabled. With that > > > > LINUX_REBOOT_CMD_KEXEC also gets disabled as no kexec kernel can be loaded > > > > while kdump works. Thus there is no need to add the new interface. Or am > > > > I missing anything? > > > > > > Let's say that you have a script that does something like this > > > > > > > > > kexec -p dump_kernel > > > echo 1 > /proc/sys/kernel/kexec_load_disabled > > > > > > If an attacker can DDos the system and make that script crash... then > > > kexec is still accessible > > > > > > On the other hand, if you load the kernel with the commandline > > > > > > sysctl.kernel.kexec_load_disabled=1 > > ^^^^ > > reboot? > > yes :) thanks! > > > Otherwise you shouldn't be able to load the crash kernel at all. > > > > > Then even if the script crashes, the only way to abuse kexec is by > > > panicing the running kernel.... > > > > True. But when an attacker can DDos the system the final workload is > > already running. So wouldn't it be enough to make sure that the script > > above has finished before starting you workload. E.g. by setting an > > appropriate Before=/After= in the systemd.unit? > > What if the kexec binary crashes and the unit will never succeed? Then there are options like OnFailure= or FailureAction= the sysadmin can use do what ever he seems appropriate. > Or worse, your distro does not use systemd !!! In that case there are other ways to achieve the same. The two options are only examples. Why can't this be used as a replacement? > > Furthermore, I don't think that restricting kexec reboot alone is > > sufficient when the attacker can still control the crash kernel. At > > least my assumption is that triggering a panic instead of just > > rebooting is just a mild inconvenience for somebody who is able to pull > > off an attack like that. > > The attacker does not control the crash kernel completely. loadpin is > still in place. > Yes, they can downgrade the whole system to a vulnerable kernel image. > But the choices are limited :) > > With physical access to the device panicing a kernel is easily doable > (but not trivial). But remotely, it is more challenging. Well the same holds for kexec. So the only difference is triggering the panic where I'm still not convinced it's a huge obstacle for someone who is able to pull off all the steps before for such an attack. To be honest I don't think we make a progress here at the moment. I would like to hear from others what they think about this. Thanks Philipp > > > > > > Would it make you more comfortable if I model this as a kernel config > > > instead of a runtime option? > > > > No, I think the implementation is fine. I'm currently only struggling > > to understand what problem kexec_reboot_disabled solves that cannot be > > solved by kexec_load_disabled. > > > > > Thanks! > > > > Happy to help. > > > > Thanks > > Philipp > > > > > > > > > > > > > > > > Thanks > > > > Philipp > > > > > > > > > > > > > > On Mon, 21 Nov 2022 at 15:10, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > > > Hi Ricardo, > > > > > > > > > > > > On Thu, 17 Nov 2022 16:15:07 +0100 > > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > > > Hi Philipp > > > > > > > > > > > > > > Thanks for your review! > > > > > > > > > > > > happy to help. > > > > > > > > > > > > > > > > > > > > On Thu, 17 Nov 2022 at 16:07, Philipp Rudo <prudo@redhat.com> wrote: > > > > > > > > > > > > > > > > Hi Ricardo, > > > > > > > > > > > > > > > > all in all I think this patch makes sense. However, there is one point > > > > > > > > I don't like... > > > > > > > > > > > > > > > > On Mon, 14 Nov 2022 14:18:39 +0100 > > > > > > > > Ricardo Ribalda <ribalda@chromium.org> wrote: > > > > > > > > > > > > > > > > > Create a new toogle that disables LINUX_REBOOT_CMD_KEXEC, reducing the > > > > > > > > > attack surface to a system. > > > > > > > > > > > > > > > > > > Without this toogle, an attacker can only reboot into a different kernel > > > > > > > > > if they can create a panic(). > > > > > > > > > > > > > > > > > > Signed-off-by: Ricardo Ribalda <ribalda@chromium.org> > > > > > > > > > > > > > > > > > > diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > > index 97394bd9d065..25d019682d33 100644 > > > > > > > > > --- a/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > > +++ b/Documentation/admin-guide/sysctl/kernel.rst > > > > > > > > > @@ -462,6 +462,17 @@ altered. > > > > > > > > > Generally used together with the `modules_disabled`_ sysctl. > > > > > > > > > > > > > > > > > > > > > > > > > > > +kexec_reboot_disabled > > > > > > > > > +===================== > > > > > > > > > + > > > > > > > > > +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. > > > > > > > > > +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), > > > > > > > > > +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). > > > > > > > > > +Once true, kexec can no longer be used for reboot and the toggle > > > > > > > > > +cannot be set back to false. > > > > > > > > > +This toggle does not affect the use of kexec during a crash. > > > > > > > > > + > > > > > > > > > + > > > > > > > > > kptr_restrict > > > > > > > > > ============= > > > > > > > > > > > > > > > > > > diff --git a/include/linux/kexec.h b/include/linux/kexec.h > > > > > > > > > index 41a686996aaa..15c3fad8918b 100644 > > > > > > > > > --- a/include/linux/kexec.h > > > > > > > > > +++ b/include/linux/kexec.h > > > > > > > > > @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); > > > > > > > > > extern struct kimage *kexec_image; > > > > > > > > > extern struct kimage *kexec_crash_image; > > > > > > > > > extern int kexec_load_disabled; > > > > > > > > > +extern int kexec_reboot_disabled; > > > > > > > > > > > > > > > > > > #ifndef kexec_flush_icache_page > > > > > > > > > #define kexec_flush_icache_page(page) > > > > > > > > > diff --git a/kernel/kexec.c b/kernel/kexec.c > > > > > > > > > index cb8e6e6f983c..43063f803d81 100644 > > > > > > > > > --- a/kernel/kexec.c > > > > > > > > > +++ b/kernel/kexec.c > > > > > > > > > @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, > > > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > > > return -EPERM; > > > > > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > > > + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) > > > > > > > > > + return -EPERM; > > > > > > > > > > > > > > > > ... Allowing to load a crashkernel doesn't make sense in my opinion. If > > > > > > > > an attacker is capable of creating a malicious kernel, planting it on > > > > > > > > the victims system and then find a way to boot it via kexec this > > > > > > > > attacker also knows how to load the malicious kernel as crashkernel and > > > > > > > > trigger a panic. So you haven't really gained anything. That's why I > > > > > > > > would simply drop this hunk (and the corresponding one from > > > > > > > > kexec_file_load) and let users who worry about this use a combination of > > > > > > > > kexec_load_disabled and kexec_reboot_disabled. > > > > > > > > > > > > > > If for whatever reason your sysadmin configured kexec_reboot_disabed > > > > > > > it can be nice that when a user try to load it they get a warning. > > > > > > > It is easier to debug than waiting two steps later when they run kexec -e.... > > > > > > > > > > > > I'm having second thoughts about this patch. My main problem is that I > > > > > > don't see a real use case where kexec_reboot_disabled is advantageous > > > > > > over kexec_load_disabled. The point is that disabling > > > > > > LINUX_REBOOT_CMD_KEXEC is almost identical to toggling kexec_load_disabled without > > > > > > a loaded kernel (when you don't have a kernel loaded you cannot reboot > > > > > > into it). With this the main use case of kexec_reboot_disabled is > > > > > > already covered by kexec_load_disabled. > > > > > > > > > > > > > > > > > However, there are two differences > > > > > > > > > > > > 1) with kexec_reboot_disable you can still (re-)load a crash kernel > > > > > > e.g. to update the initramfs after a config change. But as discussed in > > > > > > my first mail this comes on the cost that an attacker could still load a > > > > > > malicious crash kernel and then 'panic into it'. > > > > > > > > > > That crash kernel must be already in the signed malicious kernel. > > > > > which reduces the chances of attack. > > > > > Plus an attacker must be able to panic the current kernel at will, > > > > > instead of just call reset. > > > > > > > > > > > > > > > > > 2) kexec_load_disabled also prevents unloading of a loaded kernel. So > > > > > > once loaded kexec_load_disabled cannot prevent the reboot into this > > > > > > kernel. > > > > > > > > > > > > > > > > > > For 1) I doubt that this is desired at all. My expectation is that on > > > > > > systems where a sysadmin restricts a user to reboot via kexec the > > > > > > sysadmin also wants to prevent the user to load an arbitrary crash > > > > > > kernel. Especially as this still keeps the loophole open you are trying > > > > > > to close. > > > > > > > > > > > > So only 2) is left as real benefit. But that is an extremely specific > > > > > > scenario. How often does this scenario happen in real life? What > > > > > > problem does kexec_reboot_disable solve different implementation > > > > > > (also in userspace) cannot? > > > > > > > > > > > > Sorry about being this pedantic but you want to introduce some new uapi > > > > > > which will be hard if not impossible to change once introduced. That's > > > > > > why I want to be a 100% sure it is really needed. > > > > > > > > > > No worries. Completely understand :). Thanks for taking this seriously.. > > > > > > > > > > > > > > > Best regards! > > > > > > > > > > > > Thanks > > > > > > Philipp > > > > > > > > > > > > > > > > > > > That is why I added it. But i am also ok removing it > > > > > > > > > > > > > > > > > > > > > > > Thanks > > > > > > > > Philipp > > > > > > > > > > > > > > > > > + > > > > > > > > > /* Permit LSMs and IMA to fail the kexec */ > > > > > > > > > result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); > > > > > > > > > if (result < 0) > > > > > > > > > diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c > > > > > > > > > index ca2743f9c634..fe82e2525705 100644 > > > > > > > > > --- a/kernel/kexec_core.c > > > > > > > > > +++ b/kernel/kexec_core.c > > > > > > > > > @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, > > > > > > > > > struct kimage *kexec_image; > > > > > > > > > struct kimage *kexec_crash_image; > > > > > > > > > int kexec_load_disabled; > > > > > > > > > +int kexec_reboot_disabled; > > > > > > > > > #ifdef CONFIG_SYSCTL > > > > > > > > > static struct ctl_table kexec_core_sysctls[] = { > > > > > > > > > { > > > > > > > > > @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { > > > > > > > > > .extra1 = SYSCTL_ONE, > > > > > > > > > .extra2 = SYSCTL_ONE, > > > > > > > > > }, > > > > > > > > > + { > > > > > > > > > + .procname = "kexec_reboot_disabled", > > > > > > > > > + .data = &kexec_reboot_disabled, > > > > > > > > > + .maxlen = sizeof(int), > > > > > > > > > + .mode = 0644, > > > > > > > > > + /* only handle a transition from default "0" to "1" */ > > > > > > > > > + .proc_handler = proc_dointvec_minmax, > > > > > > > > > + .extra1 = SYSCTL_ONE, > > > > > > > > > + .extra2 = SYSCTL_ONE, > > > > > > > > > + }, > > > > > > > > > { } > > > > > > > > > }; > > > > > > > > > > > > > > > > > > @@ -1138,7 +1149,7 @@ int kernel_kexec(void) > > > > > > > > > > > > > > > > > > if (!kexec_trylock()) > > > > > > > > > return -EBUSY; > > > > > > > > > - if (!kexec_image) { > > > > > > > > > + if (!kexec_image || kexec_reboot_disabled) { > > > > > > > > > error = -EINVAL; > > > > > > > > > goto Unlock; > > > > > > > > > } > > > > > > > > > diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c > > > > > > > > > index 45637511e0de..583fba6de5cb 100644 > > > > > > > > > --- a/kernel/kexec_file.c > > > > > > > > > +++ b/kernel/kexec_file.c > > > > > > > > > @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, > > > > > > > > > if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) > > > > > > > > > return -EPERM; > > > > > > > > > > > > > > > > > > + /* Check if the system admin has disabled kexec reboot. */ > > > > > > > > > + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) > > > > > > > > > + && kexec_reboot_disabled) > > > > > > > > > + return -EPERM; > > > > > > > > > + > > > > > > > > > /* Make sure we have a legal set of flags */ > > > > > > > > > if (flags != (flags & KEXEC_FILE_FLAGS)) > > > > > > > > > return -EINVAL; > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
On Thu, 24 Nov 2022 16:01:15 +0100 Philipp Rudo <prudo@redhat.com> wrote: > No, I think the implementation is fine. I'm currently only struggling > to understand what problem kexec_reboot_disabled solves that cannot be > solved by kexec_load_disabled. Hi Philipp, Thanks for working with us on this. Let me try to explain our use case. We want kexec/kdump enabled, but we really do not want kexec used for any other purpose. We must have the kexec kernel loaded at boot up and not afterward. Your recommendation of: kexec -p dump_kernel echo 1 > /proc/sys/kernel/kexec_load_disabled can work, and we will probably add it. But we are taking the paranoid approach, and what I learned in security 101 ;-) and that is, only open up the minimal attack surface as possible. Yes, it's highly unlikely that the above would crash. But as with most security vulnerabilities, it's not going to be an attacker that creates a new gadget here, but probably another script in the future that causes this to be delayed or something, and a new window of opportunity will arise for an attacker. Maybe, that new window only works for non panic kernels. Yes, this is a contrived scenario, but the work vs risk is very low in adding this feature. Perhaps the attack surface that a reboot kexec could be, is that the attacker gets the ability at boot up to load the kexec for reboot and not panic. Then the attack must wait for the victim to reboot their machine before they have access to the new kernel. Again, I admit this is contrived, but just because I can't think of a real situation that this could be a problem doesn't mean that one doesn't exist. In other words, if we never want to allow a kexec reboot, why allow it at all from the beginning? The above allows it, until we don't. That alone makes us nervous. Whereas this patch is rather trivial and doesn't add complexity. Thanks for your time, we appreciate it. -- Steve
On Mon, 28 Nov 2022 17:28:55 +0100 Philipp Rudo <prudo@redhat.com> wrote: > To be honest I don't think we make a progress here at the moment. I > would like to hear from others what they think about this. Not sure if you missed my reply. https://lore.kernel.org/all/20221128114200.72b3e2fe@gandalf.local.home/ -- Steve
Hi Steven, On Mon, 28 Nov 2022 11:42:00 -0500 Steven Rostedt <rostedt@goodmis.org> wrote: > On Thu, 24 Nov 2022 16:01:15 +0100 > Philipp Rudo <prudo@redhat.com> wrote: > > > No, I think the implementation is fine. I'm currently only struggling > > to understand what problem kexec_reboot_disabled solves that cannot be > > solved by kexec_load_disabled. > > Hi Philipp, > > Thanks for working with us on this. > > Let me try to explain our use case. We want kexec/kdump enabled, but we > really do not want kexec used for any other purpose. We must have the kexec > kernel loaded at boot up and not afterward. > > Your recommendation of: > > kexec -p dump_kernel > echo 1 > /proc/sys/kernel/kexec_load_disabled > > can work, and we will probably add it. But we are taking the paranoid > approach, and what I learned in security 101 ;-) and that is, only open up > the minimal attack surface as possible. Well that's sort of my problem. When you go all in on paranoia I would expect that you also restrict the crash kernel. Otherwise you keep most of the attack surface. But disabling 'reboot' of the crash kernel is quite intrusive and probably not what you want. That's why I think it is better do the restriction on the 'load' rather than the 'reboot' path. One solution for that is the script above. But that pushes all the responsibilities concerning syncing and error handling to the sysadmin. Depending on your level of paranoia that might be too risky. Personally I think it's fine as the kernel alone cannot fix all potential security problems. In my opinion this has to be done in the layer that is responsible for the task done. So when a security problem arises due to ill syncing when starting different services it's the job of the init system to fix the issue. An alternative approach and sort of compromise I see is to convert kexec_load_disabled from a simple on/off switch to a counter on how often a kexec load can be made (in practice a tristate on/off/one-shot should be sufficient). Ideally the reboot and panic path will have separate counters. With that you could for example use kexec_load_limit.reboot=0 and kexec_load_limit.panic=1 to disable the load of images for reboot while still allow to load a crash kernel once. With this you have the flexibility you need while also preventing a race where an attacker overwrites your crash kernel before you can toggle the switch. What do you think? > Yes, it's highly unlikely that the above would crash. But as with most > security vulnerabilities, it's not going to be an attacker that creates a > new gadget here, but probably another script in the future that causes this > to be delayed or something, and a new window of opportunity will arise for > an attacker. Maybe, that new window only works for non panic kernels. Yes, > this is a contrived scenario, but the work vs risk is very low in adding > this feature. True, but that problem is not limited to userspace. For example see Ricardos other patch [1] where he treats the load of a crash kernel just like a standard load. In my opinion he creates such a gadget in that patch. [1] https://lore.kernel.org/all/20221124-kexec-noalloc-v1-0-d78361e99aec@chromium.org/ Thanks Philipp > Perhaps the attack surface that a reboot kexec could be, is that the > attacker gets the ability at boot up to load the kexec for reboot and not panic. > Then the attack must wait for the victim to reboot their machine before > they have access to the new kernel. Again, I admit this is contrived, but > just because I can't think of a real situation that this could be a problem > doesn't mean that one doesn't exist. > > In other words, if we never want to allow a kexec reboot, why allow it at > all from the beginning? The above allows it, until we don't. That alone > makes us nervous. Whereas this patch is rather trivial and doesn't add > complexity. > > Thanks for your time, we appreciate it. > > -- Steve > > _______________________________________________ > kexec mailing list > kexec@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/kexec >
On Tue, 29 Nov 2022 14:44:50 +0100 Philipp Rudo <prudo@redhat.com> wrote: > An alternative approach and sort of compromise I see is to convert > kexec_load_disabled from a simple on/off switch to a counter on how > often a kexec load can be made (in practice a tristate on/off/one-shot > should be sufficient). Ideally the reboot and panic path will > have separate counters. With that you could for example use > kexec_load_limit.reboot=0 and kexec_load_limit.panic=1 to disable the > load of images for reboot while still allow to load a crash kernel > once. With this you have the flexibility you need while also preventing > a race where an attacker overwrites your crash kernel before you can > toggle the switch. What do you think? I actually like this idea :-) -- Steve
Hi Philipp On Tue, 29 Nov 2022 at 15:32, Steven Rostedt <rostedt@goodmis.org> wrote: > > On Tue, 29 Nov 2022 14:44:50 +0100 > Philipp Rudo <prudo@redhat.com> wrote: > > > An alternative approach and sort of compromise I see is to convert > > kexec_load_disabled from a simple on/off switch to a counter on how > > often a kexec load can be made (in practice a tristate on/off/one-shot > > should be sufficient). Ideally the reboot and panic path will > > have separate counters. With that you could for example use > > kexec_load_limit.reboot=0 and kexec_load_limit.panic=1 to disable the > > load of images for reboot while still allow to load a crash kernel > > once. With this you have the flexibility you need while also preventing > > a race where an attacker overwrites your crash kernel before you can > > toggle the switch. What do you think? > > I actually like this idea :-) In case you missed it. I sent an initial implementation of this at https://lore.kernel.org/lkml/20221114-disable-kexec-reset-v2-0-c498313c1bb5@chromium.org/ Regards! > > -- Steve
diff --git a/Documentation/admin-guide/sysctl/kernel.rst b/Documentation/admin-guide/sysctl/kernel.rst index 97394bd9d065..25d019682d33 100644 --- a/Documentation/admin-guide/sysctl/kernel.rst +++ b/Documentation/admin-guide/sysctl/kernel.rst @@ -462,6 +462,17 @@ altered. Generally used together with the `modules_disabled`_ sysctl. +kexec_reboot_disabled +===================== + +A toggle indicating if ``LINUX_REBOOT_CMD_KEXEC`` has been disabled. +This value defaults to 0 (false: ``LINUX_REBOOT_CMD_KEXEC`` enabled), +but can be set to 1 (true: ``LINUX_REBOOT_CMD_KEXEC`` disabled). +Once true, kexec can no longer be used for reboot and the toggle +cannot be set back to false. +This toggle does not affect the use of kexec during a crash. + + kptr_restrict ============= diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 41a686996aaa..15c3fad8918b 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -407,6 +407,7 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image); extern struct kimage *kexec_image; extern struct kimage *kexec_crash_image; extern int kexec_load_disabled; +extern int kexec_reboot_disabled; #ifndef kexec_flush_icache_page #define kexec_flush_icache_page(page) diff --git a/kernel/kexec.c b/kernel/kexec.c index cb8e6e6f983c..43063f803d81 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -196,6 +196,10 @@ static inline int kexec_load_check(unsigned long nr_segments, if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) return -EPERM; + /* Check if the system admin has disabled kexec reboot. */ + if (!(flags & KEXEC_ON_CRASH) && kexec_reboot_disabled) + return -EPERM; + /* Permit LSMs and IMA to fail the kexec */ result = security_kernel_load_data(LOADING_KEXEC_IMAGE, false); if (result < 0) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index ca2743f9c634..fe82e2525705 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -929,6 +929,7 @@ int kimage_load_segment(struct kimage *image, struct kimage *kexec_image; struct kimage *kexec_crash_image; int kexec_load_disabled; +int kexec_reboot_disabled; #ifdef CONFIG_SYSCTL static struct ctl_table kexec_core_sysctls[] = { { @@ -941,6 +942,16 @@ static struct ctl_table kexec_core_sysctls[] = { .extra1 = SYSCTL_ONE, .extra2 = SYSCTL_ONE, }, + { + .procname = "kexec_reboot_disabled", + .data = &kexec_reboot_disabled, + .maxlen = sizeof(int), + .mode = 0644, + /* only handle a transition from default "0" to "1" */ + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ONE, + .extra2 = SYSCTL_ONE, + }, { } }; @@ -1138,7 +1149,7 @@ int kernel_kexec(void) if (!kexec_trylock()) return -EBUSY; - if (!kexec_image) { + if (!kexec_image || kexec_reboot_disabled) { error = -EINVAL; goto Unlock; } diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c index 45637511e0de..583fba6de5cb 100644 --- a/kernel/kexec_file.c +++ b/kernel/kexec_file.c @@ -333,6 +333,11 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) return -EPERM; + /* Check if the system admin has disabled kexec reboot. */ + if (!(flags & (KEXEC_FILE_ON_CRASH | KEXEC_FILE_UNLOAD)) + && kexec_reboot_disabled) + return -EPERM; + /* Make sure we have a legal set of flags */ if (flags != (flags & KEXEC_FILE_FLAGS)) return -EINVAL;