Commit 9f0ec4b1 authored by Steven Chen's avatar Steven Chen Committed by Mimi Zohar
Browse files

ima: kexec: move IMA log copy from kexec load to execute



The IMA log is currently copied to the new kernel during kexec 'load' using
ima_dump_measurement_list(). However, the IMA measurement list copied at
kexec 'load' may result in loss of IMA measurements records that only
occurred after the kexec 'load'. Move the IMA measurement list log copy
from kexec 'load' to 'execute'

Make the kexec_segment_size variable a local static variable within the
file, so it can be accessed during both kexec 'load' and 'execute'.

Define kexec_post_load() as a wrapper for calling ima_kexec_post_load() and
machine_kexec_post_load().  Replace the existing direct call to
machine_kexec_post_load() with kexec_post_load().

When there is insufficient memory to copy all the measurement logs, copy as
much of the measurement list as possible.

Co-developed-by: default avatarTushar Sugandhi <tusharsu@linux.microsoft.com>
Signed-off-by: default avatarTushar Sugandhi <tusharsu@linux.microsoft.com>
Cc: Eric Biederman <ebiederm@xmission.com>
Cc: Baoquan He <bhe@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Dave Young <dyoung@redhat.com>
Signed-off-by: default avatarSteven Chen <chenste@linux.microsoft.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com> # ppc64/kvm
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
parent f18e502d
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -201,6 +201,15 @@ kimage_validate_signature(struct kimage *image)
}
#endif

static int kexec_post_load(struct kimage *image, unsigned long flags)
{
#ifdef CONFIG_IMA_KEXEC
	if (!(flags & KEXEC_FILE_ON_CRASH))
		ima_kexec_post_load(image);
#endif
	return machine_kexec_post_load(image);
}

/*
 * In file mode list of segments is prepared by kernel. Copy relevant
 * data from user space, do error checking, prepare segment list
@@ -428,7 +437,7 @@ SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,

	kimage_terminate(image);

	ret = machine_kexec_post_load(image);
	ret = kexec_post_load(image, flags);
	if (ret)
		goto out;

+29 −14
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#ifdef CONFIG_IMA_KEXEC
static bool ima_kexec_update_registered;
static struct seq_file ima_kexec_file;
static size_t kexec_segment_size;
static void *ima_kexec_buffer;

static void ima_free_kexec_file_buf(struct seq_file *sf)
@@ -72,9 +73,6 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,
		}
	}

	if (ret < 0)
		goto out;

	/*
	 * fill in reserved space with some buffer details
	 * (eg. version, buffer size, number of measurements)
@@ -94,7 +92,7 @@ static int ima_dump_measurement_list(unsigned long *buffer_size, void **buffer,

	*buffer_size = ima_kexec_file.count;
	*buffer = ima_kexec_file.buf;
out:

	return ret;
}

@@ -112,9 +110,8 @@ void ima_add_kexec_buffer(struct kimage *image)
	unsigned long binary_runtime_size;

	/* use more understandable variable names than defined in kbuf */
	size_t kexec_buffer_size = 0;
	void *kexec_buffer = NULL;
	size_t kexec_buffer_size;
	size_t kexec_segment_size;
	int ret;

	/*
@@ -139,13 +136,6 @@ void ima_add_kexec_buffer(struct kimage *image)
		return;
	}

	ima_dump_measurement_list(&kexec_buffer_size, &kexec_buffer,
				  kexec_segment_size);
	if (!kexec_buffer) {
		pr_err("Not enough memory for the kexec measurement buffer.\n");
		return;
	}

	kbuf.buffer = kexec_buffer;
	kbuf.bufsz = kexec_buffer_size;
	kbuf.memsz = kexec_segment_size;
@@ -173,7 +163,32 @@ void ima_add_kexec_buffer(struct kimage *image)
static int ima_update_kexec_buffer(struct notifier_block *self,
				   unsigned long action, void *data)
{
	return NOTIFY_OK;
	size_t buf_size = 0;
	int ret = NOTIFY_OK;
	void *buf = NULL;

	if (!kexec_in_progress) {
		pr_info("No kexec in progress.\n");
		return ret;
	}

	if (!ima_kexec_buffer) {
		pr_err("Kexec buffer not set.\n");
		return ret;
	}

	ret = ima_dump_measurement_list(&buf_size, &buf, kexec_segment_size);

	if (ret)
		pr_err("Dump measurements failed. Error:%d\n", ret);

	if (buf_size != 0)
		memcpy(ima_kexec_buffer, buf, buf_size);

	kimage_unmap_segment(ima_kexec_buffer);
	ima_kexec_buffer = NULL;

	return ret;
}

static struct notifier_block update_buffer_nb = {