1023 lines · 25.4 KB · C
RawDownload
/* * kexec: kexec_file_load system call * * Copyright (C) 2014 Red Hat Inc. * Authors: *      Vivek Goyal <vgoyal@redhat.com> * * This source code is licensed under the GNU General Public License, * Version 2.  See the file COPYING for more details. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/capability.h>#include <linux/mm.h>#include <linux/file.h>#include <linux/slab.h>#include <linux/kexec.h>#include <linux/mutex.h>#include <linux/list.h>#include <linux/fs.h>#include <linux/ima.h>#include <crypto/hash.h>#include <crypto/sha.h>#include <linux/syscalls.h>#include <linux/vmalloc.h>#include "kexec_internal.h" static int kexec_calculate_store_digests(struct kimage *image); /* Architectures can provide this probe function */int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf,					 unsigned long buf_len){	return -ENOEXEC;} void * __weak arch_kexec_kernel_image_load(struct kimage *image){	return ERR_PTR(-ENOEXEC);} int __weak arch_kimage_file_post_load_cleanup(struct kimage *image){	return -EINVAL;} #ifdef CONFIG_KEXEC_VERIFY_SIGint __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf,					unsigned long buf_len){	return -EKEYREJECTED;}#endif /* Apply relocations of type RELA */int __weakarch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,				 unsigned int relsec){	pr_err("RELA relocation unsupported.\n");	return -ENOEXEC;} /* Apply relocations of type REL */int __weakarch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,			     unsigned int relsec){	pr_err("REL relocation unsupported.\n");	return -ENOEXEC;} /* * Free up memory used by kernel, initrd, and command line. This is temporary * memory allocation which is not needed any more after these buffers have * been loaded into separate segments and have been copied elsewhere. */void kimage_file_post_load_cleanup(struct kimage *image){	struct purgatory_info *pi = &image->purgatory_info; 	vfree(image->kernel_buf);	image->kernel_buf = NULL; 	vfree(image->initrd_buf);	image->initrd_buf = NULL; 	kfree(image->cmdline_buf);	image->cmdline_buf = NULL; 	vfree(pi->purgatory_buf);	pi->purgatory_buf = NULL; 	vfree(pi->sechdrs);	pi->sechdrs = NULL; 	/* See if architecture has anything to cleanup post load */	arch_kimage_file_post_load_cleanup(image); 	/*	 * Above call should have called into bootloader to free up	 * any data stored in kimage->image_loader_data. It should	 * be ok now to free it up.	 */	kfree(image->image_loader_data);	image->image_loader_data = NULL;} /* * In file mode list of segments is prepared by kernel. Copy relevant * data from user space, do error checking, prepare segment list */static intkimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,			     const char __user *cmdline_ptr,			     unsigned long cmdline_len, unsigned flags){	int ret = 0;	void *ldata;	loff_t size; 	ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf,				       &size, INT_MAX, READING_KEXEC_IMAGE);	if (ret)		return ret;	image->kernel_buf_len = size; 	/* IMA needs to pass the measurement list to the next kernel. */	ima_add_kexec_buffer(image); 	/* Call arch image probe handlers */	ret = arch_kexec_kernel_image_probe(image, image->kernel_buf,					    image->kernel_buf_len);	if (ret)		goto out; #ifdef CONFIG_KEXEC_VERIFY_SIG	ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,					   image->kernel_buf_len);	if (ret) {		pr_debug("kernel signature verification failed.\n");		goto out;	}	pr_debug("kernel signature verification successful.\n");#endif	/* It is possible that there no initramfs is being loaded */	if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {		ret = kernel_read_file_from_fd(initrd_fd, &image->initrd_buf,					       &size, INT_MAX,					       READING_KEXEC_INITRAMFS);		if (ret)			goto out;		image->initrd_buf_len = size;	} 	if (cmdline_len) {		image->cmdline_buf = memdup_user(cmdline_ptr, cmdline_len);		if (IS_ERR(image->cmdline_buf)) {			ret = PTR_ERR(image->cmdline_buf);			image->cmdline_buf = NULL;			goto out;		} 		image->cmdline_buf_len = cmdline_len; 		/* command line should be a string with last byte null */		if (image->cmdline_buf[cmdline_len - 1] != '\0') {			ret = -EINVAL;			goto out;		}	} 	/* Call arch image load handlers */	ldata = arch_kexec_kernel_image_load(image); 	if (IS_ERR(ldata)) {		ret = PTR_ERR(ldata);		goto out;	} 	image->image_loader_data = ldata;out:	/* In case of error, free up all allocated memory in this function */	if (ret)		kimage_file_post_load_cleanup(image);	return ret;} static intkimage_file_alloc_init(struct kimage **rimage, int kernel_fd,		       int initrd_fd, const char __user *cmdline_ptr,		       unsigned long cmdline_len, unsigned long flags){	int ret;	struct kimage *image;	bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH; 	image = do_kimage_alloc_init();	if (!image)		return -ENOMEM; 	image->file_mode = 1; 	if (kexec_on_panic) {		/* Enable special crash kernel control page alloc policy. */		image->control_page = crashk_res.start;		image->type = KEXEC_TYPE_CRASH;	} 	ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd,					   cmdline_ptr, cmdline_len, flags);	if (ret)		goto out_free_image; 	ret = sanity_check_segment_list(image);	if (ret)		goto out_free_post_load_bufs; 	ret = -ENOMEM;	image->control_code_page = kimage_alloc_control_pages(image,					   get_order(KEXEC_CONTROL_PAGE_SIZE));	if (!image->control_code_page) {		pr_err("Could not allocate control_code_buffer\n");		goto out_free_post_load_bufs;	} 	if (!kexec_on_panic) {		image->swap_page = kimage_alloc_control_pages(image, 0);		if (!image->swap_page) {			pr_err("Could not allocate swap buffer\n");			goto out_free_control_pages;		}	} 	*rimage = image;	return 0;out_free_control_pages:	kimage_free_page_list(&image->control_pages);out_free_post_load_bufs:	kimage_file_post_load_cleanup(image);out_free_image:	kfree(image);	return ret;} SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd,		unsigned long, cmdline_len, const char __user *, cmdline_ptr,		unsigned long, flags){	int ret = 0, i;	struct kimage **dest_image, *image; 	/* We only trust the superuser with rebooting the system. */	if (!capable(CAP_SYS_BOOT) || kexec_load_disabled)		return -EPERM; 	/* Make sure we have a legal set of flags */	if (flags != (flags & KEXEC_FILE_FLAGS))		return -EINVAL; 	image = NULL; 	if (!mutex_trylock(&kexec_mutex))		return -EBUSY; 	dest_image = &kexec_image;	if (flags & KEXEC_FILE_ON_CRASH) {		dest_image = &kexec_crash_image;		if (kexec_crash_image)			arch_kexec_unprotect_crashkres();	} 	if (flags & KEXEC_FILE_UNLOAD)		goto exchange; 	/*	 * In case of crash, new kernel gets loaded in reserved region. It is	 * same memory where old crash kernel might be loaded. Free any	 * current crash dump kernel before we corrupt it.	 */	if (flags & KEXEC_FILE_ON_CRASH)		kimage_free(xchg(&kexec_crash_image, NULL)); 	ret = kimage_file_alloc_init(&image, kernel_fd, initrd_fd, cmdline_ptr,				     cmdline_len, flags);	if (ret)		goto out; 	ret = machine_kexec_prepare(image);	if (ret)		goto out; 	/*	 * Some architecture(like S390) may touch the crash memory before	 * machine_kexec_prepare(), we must copy vmcoreinfo data after it.	 */	ret = kimage_crash_copy_vmcoreinfo(image);	if (ret)		goto out; 	ret = kexec_calculate_store_digests(image);	if (ret)		goto out; 	for (i = 0; i < image->nr_segments; i++) {		struct kexec_segment *ksegment; 		ksegment = &image->segment[i];		pr_debug("Loading segment %d: buf=0x%p bufsz=0x%zx mem=0x%lx memsz=0x%zx\n",			 i, ksegment->buf, ksegment->bufsz, ksegment->mem,			 ksegment->memsz); 		ret = kimage_load_segment(image, &image->segment[i]);		if (ret)			goto out;	} 	kimage_terminate(image); 	/*	 * Free up any temporary buffers allocated which are not needed	 * after image has been loaded	 */	kimage_file_post_load_cleanup(image);exchange:	image = xchg(dest_image, image);out:	if ((flags & KEXEC_FILE_ON_CRASH) && kexec_crash_image)		arch_kexec_protect_crashkres(); 	mutex_unlock(&kexec_mutex);	kimage_free(image);	return ret;} static int locate_mem_hole_top_down(unsigned long start, unsigned long end,				    struct kexec_buf *kbuf){	struct kimage *image = kbuf->image;	unsigned long temp_start, temp_end; 	temp_end = min(end, kbuf->buf_max);	temp_start = temp_end - kbuf->memsz; 	do {		/* align down start */		temp_start = temp_start & (~(kbuf->buf_align - 1)); 		if (temp_start < start || temp_start < kbuf->buf_min)			return 0; 		temp_end = temp_start + kbuf->memsz - 1; 		/*		 * Make sure this does not conflict with any of existing		 * segments		 */		if (kimage_is_destination_range(image, temp_start, temp_end)) {			temp_start = temp_start - PAGE_SIZE;			continue;		} 		/* We found a suitable memory range */		break;	} while (1); 	/* If we are here, we found a suitable memory range */	kbuf->mem = temp_start; 	/* Success, stop navigating through remaining System RAM ranges */	return 1;} static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end,				     struct kexec_buf *kbuf){	struct kimage *image = kbuf->image;	unsigned long temp_start, temp_end; 	temp_start = max(start, kbuf->buf_min); 	do {		temp_start = ALIGN(temp_start, kbuf->buf_align);		temp_end = temp_start + kbuf->memsz - 1; 		if (temp_end > end || temp_end > kbuf->buf_max)			return 0;		/*		 * Make sure this does not conflict with any of existing		 * segments		 */		if (kimage_is_destination_range(image, temp_start, temp_end)) {			temp_start = temp_start + PAGE_SIZE;			continue;		} 		/* We found a suitable memory range */		break;	} while (1); 	/* If we are here, we found a suitable memory range */	kbuf->mem = temp_start; 	/* Success, stop navigating through remaining System RAM ranges */	return 1;} static int locate_mem_hole_callback(u64 start, u64 end, void *arg){	struct kexec_buf *kbuf = (struct kexec_buf *)arg;	unsigned long sz = end - start + 1; 	/* Returning 0 will take to next memory range */	if (sz < kbuf->memsz)		return 0; 	if (end < kbuf->buf_min || start > kbuf->buf_max)		return 0; 	/*	 * Allocate memory top down with-in ram range. Otherwise bottom up	 * allocation.	 */	if (kbuf->top_down)		return locate_mem_hole_top_down(start, end, kbuf);	return locate_mem_hole_bottom_up(start, end, kbuf);} /** * arch_kexec_walk_mem - call func(data) on free memory regions * @kbuf:	Context info for the search. Also passed to @func. * @func:	Function to call for each memory region. * * Return: The memory walk will stop when func returns a non-zero value * and that value will be returned. If all free regions are visited without * func returning non-zero, then zero will be returned. */int __weak arch_kexec_walk_mem(struct kexec_buf *kbuf,			       int (*func)(u64, u64, void *)){	if (kbuf->image->type == KEXEC_TYPE_CRASH)		return walk_iomem_res_desc(crashk_res.desc,					   IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY,					   crashk_res.start, crashk_res.end,					   kbuf, func);	else		return walk_system_ram_res(0, ULONG_MAX, kbuf, func);} /** * kexec_locate_mem_hole - find free memory for the purgatory or the next kernel * @kbuf:	Parameters for the memory search. * * On success, kbuf->mem will have the start address of the memory region found. * * Return: 0 on success, negative errno on error. */int kexec_locate_mem_hole(struct kexec_buf *kbuf){	int ret; 	ret = arch_kexec_walk_mem(kbuf, locate_mem_hole_callback); 	return ret == 1 ? 0 : -EADDRNOTAVAIL;} /** * kexec_add_buffer - place a buffer in a kexec segment * @kbuf:	Buffer contents and memory parameters. * * This function assumes that kexec_mutex is held. * On successful return, @kbuf->mem will have the physical address of * the buffer in memory. * * Return: 0 on success, negative errno on error. */int kexec_add_buffer(struct kexec_buf *kbuf){ 	struct kexec_segment *ksegment;	int ret; 	/* Currently adding segment this way is allowed only in file mode */	if (!kbuf->image->file_mode)		return -EINVAL; 	if (kbuf->image->nr_segments >= KEXEC_SEGMENT_MAX)		return -EINVAL; 	/*	 * Make sure we are not trying to add buffer after allocating	 * control pages. All segments need to be placed first before	 * any control pages are allocated. As control page allocation	 * logic goes through list of segments to make sure there are	 * no destination overlaps.	 */	if (!list_empty(&kbuf->image->control_pages)) {		WARN_ON(1);		return -EINVAL;

Lines 1–500 of 1023.