Commit 7af6e3fe authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull integrity updates from Mimi Zohar:
 "Carrying the IMA measurement list across kexec is not a new feature,
  but is updated to address a couple of issues:

   - Carrying the IMA measurement list across kexec required knowing
     apriori all the file measurements between the "kexec load" and
     "kexec execute" in order to measure them before the "kexec load".
     Any delay between the "kexec load" and "kexec exec" exacerbated the
     problem.

   - Any file measurements post "kexec load" were not carried across
     kexec, resulting in the measurement list being out of sync with the
     TPM PCR.

  With these changes, the buffer for the IMA measurement list is still
  allocated at "kexec load", but copying the IMA measurement list is
  deferred to after quiescing the TPM.

  Two new kexec critical data records are defined"

* tag 'integrity-v6.16' of git://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity:
  ima: do not copy measurement list to kdump kernel
  ima: measure kexec load and exec events as critical data
  ima: make the kexec extra memory configurable
  ima: verify if the segment size has changed
  ima: kexec: move IMA log copy from kexec load to execute
  ima: kexec: define functions to copy IMA log at soft boot
  ima: kexec: skip IMA segment validation after kexec soft reboot
  kexec: define functions to map and unmap segments
  ima: define and call ima_alloc_kexec_file_buf()
  ima: rename variable the seq_file "file" to "ima_kexec_file"
parents cbaed2f5 fe3aebf2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ static inline void ima_appraise_parse_cmdline(void) {}

#ifdef CONFIG_IMA_KEXEC
extern void ima_add_kexec_buffer(struct kimage *image);
extern void ima_kexec_post_load(struct kimage *image);
#else
static inline void ima_kexec_post_load(struct kimage *image) {}
#endif

#else
+9 −0
Original line number Diff line number Diff line
@@ -369,6 +369,9 @@ struct kimage {

	phys_addr_t ima_buffer_addr;
	size_t ima_buffer_size;

	unsigned long ima_segment_index;
	bool is_ima_segment_index_set;
#endif

	/* Core ELF header buffer */
@@ -474,13 +477,19 @@ extern bool kexec_file_dbg_print;
#define kexec_dprintk(fmt, arg...) \
        do { if (kexec_file_dbg_print) pr_info(fmt, ##arg); } while (0)

extern void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size);
extern void kimage_unmap_segment(void *buffer);
#else /* !CONFIG_KEXEC_CORE */
struct pt_regs;
struct task_struct;
struct kimage;
static inline void __crash_kexec(struct pt_regs *regs) { }
static inline void crash_kexec(struct pt_regs *regs) { }
static inline int kexec_should_crash(struct task_struct *p) { return 0; }
static inline int kexec_crash_loaded(void) { return 0; }
static inline void *kimage_map_segment(struct kimage *image, unsigned long addr, unsigned long size)
{ return NULL; }
static inline void kimage_unmap_segment(void *buffer) { }
#define kexec_in_progress false
#endif /* CONFIG_KEXEC_CORE */

+54 −0
Original line number Diff line number Diff line
@@ -877,6 +877,60 @@ int kimage_load_segment(struct kimage *image,
	return result;
}

void *kimage_map_segment(struct kimage *image,
			 unsigned long addr, unsigned long size)
{
	unsigned long src_page_addr, dest_page_addr = 0;
	unsigned long eaddr = addr + size;
	kimage_entry_t *ptr, entry;
	struct page **src_pages;
	unsigned int npages;
	void *vaddr = NULL;
	int i;

	/*
	 * Collect the source pages and map them in a contiguous VA range.
	 */
	npages = PFN_UP(eaddr) - PFN_DOWN(addr);
	src_pages = kmalloc_array(npages, sizeof(*src_pages), GFP_KERNEL);
	if (!src_pages) {
		pr_err("Could not allocate ima pages array.\n");
		return NULL;
	}

	i = 0;
	for_each_kimage_entry(image, ptr, entry) {
		if (entry & IND_DESTINATION) {
			dest_page_addr = entry & PAGE_MASK;
		} else if (entry & IND_SOURCE) {
			if (dest_page_addr >= addr && dest_page_addr < eaddr) {
				src_page_addr = entry & PAGE_MASK;
				src_pages[i++] =
					virt_to_page(__va(src_page_addr));
				if (i == npages)
					break;
				dest_page_addr += PAGE_SIZE;
			}
		}
	}

	/* Sanity check. */
	WARN_ON(i < npages);

	vaddr = vmap(src_pages, npages, VM_MAP, PAGE_KERNEL);
	kfree(src_pages);

	if (!vaddr)
		pr_err("Could not map ima buffer.\n");

	return vaddr;
}

void kimage_unmap_segment(void *segment_buffer)
{
	vunmap(segment_buffer);
}

struct kexec_load_limit {
	/* Mutex protects the limit count. */
	struct mutex mutex;
+32 −1
Original line number Diff line number Diff line
@@ -38,6 +38,21 @@ void set_kexec_sig_enforced(void)
}
#endif

#ifdef CONFIG_IMA_KEXEC
static bool check_ima_segment_index(struct kimage *image, int i)
{
	if (image->is_ima_segment_index_set && i == image->ima_segment_index)
		return true;
	else
		return false;
}
#else
static bool check_ima_segment_index(struct kimage *image, int i)
{
	return false;
}
#endif

static int kexec_calculate_store_digests(struct kimage *image);

/* Maximum size in bytes for kernel/initrd files. */
@@ -186,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
@@ -413,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;

@@ -776,6 +800,13 @@ static int kexec_calculate_store_digests(struct kimage *image)
		if (ksegment->kbuf == pi->purgatory_buf)
			continue;

		/*
		 * Skip the segment if ima_segment_index is set and matches
		 * the current index
		 */
		if (check_ima_segment_index(image, i))
			continue;

		ret = crypto_shash_update(desc, ksegment->kbuf,
					  ksegment->bufsz);
		if (ret)
+11 −0
Original line number Diff line number Diff line
@@ -321,4 +321,15 @@ config IMA_DISABLE_HTABLE
	help
	   This option disables htable to allow measurement of duplicate records.

config IMA_KEXEC_EXTRA_MEMORY_KB
	int "Extra memory for IMA measurements added during kexec soft reboot"
	range 0 40
	depends on IMA_KEXEC
	default 0
	help
	  IMA_KEXEC_EXTRA_MEMORY_KB determines the extra memory to be
	  allocated (in kb) for IMA measurements added during kexec soft reboot.
	  If set to the default value of 0, an extra half page of memory for those
	  additional measurements will be allocated.

endif
Loading