Commit f7a667a0 authored by Eric Biggers's avatar Eric Biggers Committed by Andrew Morton
Browse files

kexec_file: use SHA-256 library API instead of crypto_shash API

This user of SHA-256 does not support any other algorithm, so the
crypto_shash abstraction provides no value.  Just use the SHA-256 library
API instead, which is much simpler and easier to use.

Tested with '/sbin/kexec --kexec-file-syscall'.

Link: https://lkml.kernel.org/r/20250428185721.844686-1-ebiggers@kernel.org


Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent c91d7862
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -38,8 +38,7 @@ config KEXEC
config KEXEC_FILE
	bool "Enable kexec file based system call"
	depends on ARCH_SUPPORTS_KEXEC_FILE
	select CRYPTO
	select CRYPTO_SHA256
	select CRYPTO_LIB_SHA256
	select KEXEC_CORE
	help
	  This is new version of kexec system call. This system call is
+15 −63
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@
#include <linux/list.h>
#include <linux/fs.h>
#include <linux/ima.h>
#include <crypto/hash.h>
#include <crypto/sha2.h>
#include <linux/elf.h>
#include <linux/elfcore.h>
@@ -712,11 +711,10 @@ int kexec_add_buffer(struct kexec_buf *kbuf)
/* Calculate and store the digest of segments */
static int kexec_calculate_store_digests(struct kimage *image)
{
	struct crypto_shash *tfm;
	struct shash_desc *desc;
	struct sha256_state state;
	int ret = 0, i, j, zero_buf_sz, sha_region_sz;
	size_t desc_size, nullsz;
	char *digest;
	size_t nullsz;
	u8 digest[SHA256_DIGEST_SIZE];
	void *zero_buf;
	struct kexec_sha_region *sha_regions;
	struct purgatory_info *pi = &image->purgatory_info;
@@ -727,37 +725,12 @@ static int kexec_calculate_store_digests(struct kimage *image)
	zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT);
	zero_buf_sz = PAGE_SIZE;

	tfm = crypto_alloc_shash("sha256", 0, 0);
	if (IS_ERR(tfm)) {
		ret = PTR_ERR(tfm);
		goto out;
	}

	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
	desc = kzalloc(desc_size, GFP_KERNEL);
	if (!desc) {
		ret = -ENOMEM;
		goto out_free_tfm;
	}

	sha_region_sz = KEXEC_SEGMENT_MAX * sizeof(struct kexec_sha_region);
	sha_regions = vzalloc(sha_region_sz);
	if (!sha_regions) {
		ret = -ENOMEM;
		goto out_free_desc;
	}

	desc->tfm   = tfm;

	ret = crypto_shash_init(desc);
	if (ret < 0)
		goto out_free_sha_regions;
	if (!sha_regions)
		return -ENOMEM;

	digest = kzalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
	if (!digest) {
		ret = -ENOMEM;
		goto out_free_sha_regions;
	}
	sha256_init(&state);

	for (j = i = 0; i < image->nr_segments; i++) {
		struct kexec_segment *ksegment;
@@ -776,10 +749,7 @@ static int kexec_calculate_store_digests(struct kimage *image)
		if (ksegment->kbuf == pi->purgatory_buf)
			continue;

		ret = crypto_shash_update(desc, ksegment->kbuf,
					  ksegment->bufsz);
		if (ret)
			break;
		sha256_update(&state, ksegment->kbuf, ksegment->bufsz);

		/*
		 * Assume rest of the buffer is filled with zero and
@@ -791,44 +761,26 @@ static int kexec_calculate_store_digests(struct kimage *image)

			if (bytes > zero_buf_sz)
				bytes = zero_buf_sz;
			ret = crypto_shash_update(desc, zero_buf, bytes);
			if (ret)
				break;
			sha256_update(&state, zero_buf, bytes);
			nullsz -= bytes;
		}

		if (ret)
			break;

		sha_regions[j].start = ksegment->mem;
		sha_regions[j].len = ksegment->memsz;
		j++;
	}

	if (!ret) {
		ret = crypto_shash_final(desc, digest);
		if (ret)
			goto out_free_digest;
	sha256_final(&state, digest);

	ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha_regions",
					     sha_regions, sha_region_sz, 0);
	if (ret)
			goto out_free_digest;
		goto out_free_sha_regions;

	ret = kexec_purgatory_get_set_symbol(image, "purgatory_sha256_digest",
					     digest, SHA256_DIGEST_SIZE, 0);
		if (ret)
			goto out_free_digest;
	}

out_free_digest:
	kfree(digest);
out_free_sha_regions:
	vfree(sha_regions);
out_free_desc:
	kfree(desc);
out_free_tfm:
	kfree(tfm);
out:
	return ret;
}