From nobody Fri Nov 14 16:53:57 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C974C2B9A4 for ; Fri, 2 May 2025 01:13:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746148392; cv=none; b=S55ORvMkqoDxi7z7CYTLYKTNsELdaFukqLAPn5rRH/Uyo2JlZLdF7qltsLtSeJXnbT7PRN0pTZNQNg8DfqNhcRc4THq1/OjAexazZ9tpuQ2/l69OcFNoX+d4K69UlGQfOburdHmQcSd7wWQfWPtluuDnljWOhomodW2xbljULsY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1746148392; c=relaxed/simple; bh=ea9mZ0fMYc8H3dNJtS8bA7Qklp+AW/Cq46IXI50ntpU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=oJqadBZlXavagos6Olck9PvMtPAbKvTo7P9udCTWJ1TqN2EGl+0+xadk9xIT1DwUdrlJpQtRY7CsbqOOvPEgO5K/Z2rxXcA8ifTjN9X5okWCDjuSjOmJi5bs3b0RXIEbhXOLeu0WdAmD4u/09/THwXqNelS+NgrY5kKXX9z7vFw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=aMtxLCT5; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="aMtxLCT5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1746148387; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=vw3CvT79Q3cOVUn1o5X1aSl+i2HC2zO/yQ3kCtIdex0=; b=aMtxLCT5UCh7TA2VFHLx1vMWb0WNjHsvY3SuXL8HDoNs+8BxDlQtRVjYWaAtpHspI5tIYf KU/lpD/lTCBXbbo//PJisoaYv7vVxq03W+kH9YLbl2mKUt8S9FNfEN+oXf/7BZRQ90Iab6 Z7Khh9+Ylpa2r8tQH6uospwaHrN93tM= Received: from mail-pf1-f199.google.com (mail-pf1-f199.google.com [209.85.210.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-156-3JDyA1NbMCKjfcozmMtBxg-1; Thu, 01 May 2025 21:13:05 -0400 X-MC-Unique: 3JDyA1NbMCKjfcozmMtBxg-1 X-Mimecast-MFC-AGG-ID: 3JDyA1NbMCKjfcozmMtBxg_1746148383 Received: by mail-pf1-f199.google.com with SMTP id d2e1a72fcca58-73e0094706bso2250049b3a.3 for ; Thu, 01 May 2025 18:13:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1746148383; x=1746753183; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vw3CvT79Q3cOVUn1o5X1aSl+i2HC2zO/yQ3kCtIdex0=; b=fAkOUDktJr2FODDg9atkrLZGsWhDwNyHBsIP9O0FOf5lN96+dsJN5gqEKGH5lPEkbO bXX2043E9JKu9IwLoy3I/u50Bkn9MxcHbkXg8/yHFRlcxQZPGDAKIJqgtQNqQ3ULceTr TitQcsTo+XGOrN6svQbaBilG5Op3dzIhdRIuEuIkHScwmFOsmHyoMXpNymB+suo3k4pl toX6YLLCICikxu3CiB8ibHUyIsQugTgCA2r8JYkB8Djkp4FUkX5iO1zY3RZNTc9I67db tUvM8Lg2DqnvIsaf4l2bapfdourQzjMGb/RqvM/po2esWwDg/IhBGls99YJO4utYuSGS 5Q1A== X-Forwarded-Encrypted: i=1; AJvYcCX/RMkjNtSVADKIb+X7sK7bmeNMnJVIr+K5hiK130yiKTFskLwtLkDzK02vpFDrIMhhYuN1E3LMdBKzmxE=@vger.kernel.org X-Gm-Message-State: AOJu0Yxl58LEVAbfxHR2ErE/ZKfqeHOCiPMYBHrF9UUhcw8aSlBItOPj 0CVvJ4mxHxR3gI7DztYcV+ym2EVVi0/imSum6qDDcvfFK6sm5utiNjCMhi7K3GfWIg4sYLSMcWH UJPEA0Q3/bH/igivez2WN73vyuIA3QC/hvXCYTGFcrgILkabnOXQYi8TlZefsdw== X-Gm-Gg: ASbGncsG1rmYB+P2rGKCnlFOrdLTzUe1deaas/+9EQv/5z3GWlBIhkFB7QU4kQyB3oL kgy5LtDFjjULHoQsmv+Zstr0Q/W8TE4kPU1zFLyAuuOXAkePMkfsA/HjkLQ3VSmoljn9vF8camt d3dDjE2epgWYtwCHzk6hEYQd2lEyrEFhsKK8Y9U83d5/MJ8+O/MrvcSXweXHPPze7A0pR9yJ2ui 6dZM+nrjVJPQsAZbfQgITqUYX10SaDEY3l6qb0cNlgDzh3boLugkqddPAIObZ923BiQ/T+WzG9a TXw= X-Received: by 2002:a05:6a00:4098:b0:737:6e1f:29da with SMTP id d2e1a72fcca58-74058b1fd7dmr1448485b3a.21.1746148383166; Thu, 01 May 2025 18:13:03 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHuA9DqPILPKQxZdcEH9QQNdT7mY4hktCyGDXZmoD7ZwVzoWJjEAELCZGpGm7+EPHwHStwhEA== X-Received: by 2002:a05:6a00:4098:b0:737:6e1f:29da with SMTP id d2e1a72fcca58-74058b1fd7dmr1448445b3a.21.1746148382793; Thu, 01 May 2025 18:13:02 -0700 (PDT) Received: from localhost ([209.132.188.88]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-74058deb363sm342932b3a.73.2025.05.01.18.13.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 01 May 2025 18:13:02 -0700 (PDT) From: Coiby Xu To: kexec@lists.infradead.org Cc: Ondrej Kozina , Milan Broz , Thomas Staudt , =?UTF-8?q?Daniel=20P=20=2E=20Berrang=C3=A9?= , Kairui Song , Pingfan Liu , Baoquan He , Dave Young , linux-kernel@vger.kernel.org, x86@kernel.org, Dave Hansen , Vitaly Kuznetsov , Arnaud Lefebvre , Andrew Morton , Vivek Goyal , Jonathan Corbet , linux-doc@vger.kernel.org (open list:DOCUMENTATION) Subject: [PATCH v9 2/8] crash_dump: make dm crypt keys persist for the kdump kernel Date: Fri, 2 May 2025 09:12:36 +0800 Message-ID: <20250502011246.99238-3-coxu@redhat.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250502011246.99238-1-coxu@redhat.com> References: <20250502011246.99238-1-coxu@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable A configfs /sys/kernel/config/crash_dm_crypt_keys is provided for user space to make the dm crypt keys persist for the kdump kernel. Take the case of dumping to a LUKS-encrypted target as an example, here is the life cycle of the kdump copies of LUKS volume keys, 1. After the 1st kernel loads the initramfs during boot, systemd uses an user-input passphrase to de-crypt the LUKS volume keys or simply TPM-sealed volume keys and then save the volume keys to specified keyring (using the --link-vk-to-keyring API) and the keys will expire within specified time. 2. A user space tool (kdump initramfs loader like kdump-utils) create key items inside /sys/kernel/config/crash_dm_crypt_keys to inform the 1st kernel which keys are needed. 3. When the kdump initramfs is loaded by the kexec_file_load syscall, the 1st kernel will iterate created key items, save the keys to kdump reserved memory. 4. When the 1st kernel crashes and the kdump initramfs is booted, the kdump initramfs asks the kdump kernel to create a user key using the key stored in kdump reserved memory by writing yes to /sys/kernel/crash_dm_crypt_keys/restore. Then the LUKS encrypted device is unlocked with libcryptsetup's --volume-key-keyring API. 5. The system gets rebooted to the 1st kernel after dumping vmcore to the LUKS encrypted device is finished Eventually the keys have to stay in the kdump reserved memory for the kdump kernel to unlock encrypted volumes. During this process, some measures like letting the keys expire within specified time are desirable to reduce security risk. This patch assumes, 1) there are 128 LUKS devices at maximum to be unlocked thus MAX_KEY_NUM=3D128. 2) a key description won't exceed 128 bytes thus KEY_DESC_MAX_LEN=3D128. And here is a demo on how to interact with /sys/kernel/config/crash_dm_crypt_keys, # Add key #1 mkdir /sys/kernel/config/crash_dm_crypt_keys/7d26b7b4-e342-4d2d-b660-74= 26b0996720 # Add key #1's description echo cryptsetup:7d26b7b4-e342-4d2d-b660-7426b0996720 > /sys/kernel/conf= ig/crash_dm_crypt_keys/description # how many keys do we have now? cat /sys/kernel/config/crash_dm_crypt_keys/count 1 # Add key# 2 in the same way # how many keys do we have now? cat /sys/kernel/config/crash_dm_crypt_keys/count 2 # the tree structure of /crash_dm_crypt_keys configfs tree /sys/kernel/config/crash_dm_crypt_keys/ /sys/kernel/config/crash_dm_crypt_keys/ =E2=94=9C=E2=94=80=E2=94=80 7d26b7b4-e342-4d2d-b660-7426b0996720 =E2=94=82=C2=A0=C2=A0 =E2=94=94=E2=94=80=E2=94=80 description =E2=94=9C=E2=94=80=E2=94=80 count =E2=94=9C=E2=94=80=E2=94=80 fce2cd38-4d59-4317-8ce2-1fd24d52c46a =E2=94=82=C2=A0=C2=A0 =E2=94=94=E2=94=80=E2=94=80 description Signed-off-by: Coiby Xu Acked-by: Baoquan He --- Documentation/admin-guide/kdump/kdump.rst | 28 ++++ kernel/Kconfig.kexec | 11 ++ kernel/Makefile | 1 + kernel/crash_dump_dm_crypt.c | 154 ++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 kernel/crash_dump_dm_crypt.c diff --git a/Documentation/admin-guide/kdump/kdump.rst b/Documentation/admi= n-guide/kdump/kdump.rst index 1f7f14c6e184..b74d3bed8fff 100644 --- a/Documentation/admin-guide/kdump/kdump.rst +++ b/Documentation/admin-guide/kdump/kdump.rst @@ -547,6 +547,34 @@ from within add_taint() whenever the value set in this= bitmask matches with the bit flag being set by add_taint(). This will cause a kdump to occur at the add_taint()->panic() call. =20 +Write the dump file to encrypted disk volume +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +CONFIG_CRASH_DM_CRYPT can be enabled to support saving the dump file to an +encrypted disk volume. User space can interact with +/sys/kernel/config/crash_dm_crypt_keys for setup, + +1. Tell the first kernel what logon keys are needed to unlock the disk vol= umes, + # Add key #1 + mkdir /sys/kernel/config/crash_dm_crypt_keys/7d26b7b4-e342-4d2d-b660-7= 426b0996720 + # Add key #1's description + echo cryptsetup:7d26b7b4-e342-4d2d-b660-7426b0996720 > /sys/kernel/con= fig/crash_dm_crypt_keys/description + + # how many keys do we have now? + cat /sys/kernel/config/crash_dm_crypt_keys/count + 1 + + # Add key #2 in the same way + + # how many keys do we have now? + cat /sys/kernel/config/crash_dm_crypt_keys/count + 2 + +2. Load the dump-capture kernel + +3. After the dump-capture kerne get booted, restore the keys to user keyri= ng + echo yes > /sys/kernel/crash_dm_crypt_keys/restore + Contact =3D=3D=3D=3D=3D=3D=3D =20 diff --git a/kernel/Kconfig.kexec b/kernel/Kconfig.kexec index 4d111f871951..0a8fafd247d1 100644 --- a/kernel/Kconfig.kexec +++ b/kernel/Kconfig.kexec @@ -116,6 +116,17 @@ config CRASH_DUMP For s390, this option also enables zfcpdump. See also =20 +config CRASH_DM_CRYPT + bool "Support saving crash dump to dm-crypt encrypted volume" + depends on KEXEC_FILE + depends on CRASH_DUMP + depends on DM_CRYPT + depends on CONFIGFS_FS + help + With this option enabled, user space can intereact with + /sys/kernel/config/crash_dm_crypt_keys to make the dm crypt keys + persistent for the dump-capture kernel. + config CRASH_HOTPLUG bool "Update the crash elfcorehdr on system configuration changes" default y diff --git a/kernel/Makefile b/kernel/Makefile index 434929de17ef..c7d3793107e5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_VMCORE_INFO) +=3D vmcore_info.o elfcorehdr.o obj-$(CONFIG_CRASH_RESERVE) +=3D crash_reserve.o obj-$(CONFIG_KEXEC_CORE) +=3D kexec_core.o obj-$(CONFIG_CRASH_DUMP) +=3D crash_core.o +obj-$(CONFIG_CRASH_DM_CRYPT) +=3D crash_dump_dm_crypt.o obj-$(CONFIG_KEXEC) +=3D kexec.o obj-$(CONFIG_KEXEC_FILE) +=3D kexec_file.o obj-$(CONFIG_KEXEC_ELF) +=3D kexec_elf.o diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c new file mode 100644 index 000000000000..62a3c47d8b3b --- /dev/null +++ b/kernel/crash_dump_dm_crypt.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include +#include +#include +#include + +#define KEY_NUM_MAX 128 /* maximum dm crypt keys */ +#define KEY_DESC_MAX_LEN 128 /* maximum dm crypt key description size */ + +static unsigned int key_count; + +struct config_key { + struct config_item item; + const char *description; +}; + +static inline struct config_key *to_config_key(struct config_item *item) +{ + return container_of(item, struct config_key, item); +} + +static ssize_t config_key_description_show(struct config_item *item, char = *page) +{ + return sprintf(page, "%s\n", to_config_key(item)->description); +} + +static ssize_t config_key_description_store(struct config_item *item, + const char *page, size_t count) +{ + struct config_key *config_key =3D to_config_key(item); + size_t len; + int ret; + + ret =3D -EINVAL; + len =3D strcspn(page, "\n"); + + if (len > KEY_DESC_MAX_LEN) { + pr_err("The key description shouldn't exceed %u characters", KEY_DESC_MA= X_LEN); + return ret; + } + + if (!len) + return ret; + + kfree(config_key->description); + ret =3D -ENOMEM; + config_key->description =3D kmemdup_nul(page, len, GFP_KERNEL); + if (!config_key->description) + return ret; + + return count; +} + +CONFIGFS_ATTR(config_key_, description); + +static struct configfs_attribute *config_key_attrs[] =3D { + &config_key_attr_description, + NULL, +}; + +static void config_key_release(struct config_item *item) +{ + kfree(to_config_key(item)); + key_count--; +} + +static struct configfs_item_operations config_key_item_ops =3D { + .release =3D config_key_release, +}; + +static const struct config_item_type config_key_type =3D { + .ct_item_ops =3D &config_key_item_ops, + .ct_attrs =3D config_key_attrs, + .ct_owner =3D THIS_MODULE, +}; + +static struct config_item *config_keys_make_item(struct config_group *grou= p, + const char *name) +{ + struct config_key *config_key; + + if (key_count > KEY_NUM_MAX) { + pr_err("Only %u keys at maximum to be created\n", KEY_NUM_MAX); + return ERR_PTR(-EINVAL); + } + + config_key =3D kzalloc(sizeof(struct config_key), GFP_KERNEL); + if (!config_key) + return ERR_PTR(-ENOMEM); + + config_item_init_type_name(&config_key->item, name, &config_key_type); + + key_count++; + + return &config_key->item; +} + +static ssize_t config_keys_count_show(struct config_item *item, char *page) +{ + return sprintf(page, "%d\n", key_count); +} + +CONFIGFS_ATTR_RO(config_keys_, count); + +static struct configfs_attribute *config_keys_attrs[] =3D { + &config_keys_attr_count, + NULL, +}; + +/* + * Note that, since no extra work is required on ->drop_item(), + * no ->drop_item() is provided. + */ +static struct configfs_group_operations config_keys_group_ops =3D { + .make_item =3D config_keys_make_item, +}; + +static const struct config_item_type config_keys_type =3D { + .ct_group_ops =3D &config_keys_group_ops, + .ct_attrs =3D config_keys_attrs, + .ct_owner =3D THIS_MODULE, +}; + +static struct configfs_subsystem config_keys_subsys =3D { + .su_group =3D { + .cg_item =3D { + .ci_namebuf =3D "crash_dm_crypt_keys", + .ci_type =3D &config_keys_type, + }, + }, +}; + +static int __init configfs_dmcrypt_keys_init(void) +{ + int ret; + + config_group_init(&config_keys_subsys.su_group); + mutex_init(&config_keys_subsys.su_mutex); + ret =3D configfs_register_subsystem(&config_keys_subsys); + if (ret) { + pr_err("Error %d while registering subsystem %s\n", ret, + config_keys_subsys.su_group.cg_item.ci_namebuf); + goto out_unregister; + } + + return 0; + +out_unregister: + configfs_unregister_subsystem(&config_keys_subsys); + + return ret; +} + +module_init(configfs_dmcrypt_keys_init); --=20 2.49.0