cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

misc.c (12604B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * misc.c
      4 *
      5 * This is a collection of several routines used to extract the kernel
      6 * which includes KASLR relocation, decompression, ELF parsing, and
      7 * relocation processing. Additionally included are the screen and serial
      8 * output functions and related debugging support functions.
      9 *
     10 * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
     11 * puts by Nick Holloway 1993, better puts by Martin Mares 1995
     12 * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
     13 */
     14
     15#include "misc.h"
     16#include "error.h"
     17#include "pgtable.h"
     18#include "../string.h"
     19#include "../voffset.h"
     20#include <asm/bootparam_utils.h>
     21
     22/*
     23 * WARNING!!
     24 * This code is compiled with -fPIC and it is relocated dynamically at
     25 * run time, but no relocation processing is performed. This means that
     26 * it is not safe to place pointers in static structures.
     27 */
     28
     29/* Macros used by the included decompressor code below. */
     30#define STATIC		static
     31/* Define an externally visible malloc()/free(). */
     32#define MALLOC_VISIBLE
     33#include <linux/decompress/mm.h>
     34
     35/*
     36 * Provide definitions of memzero and memmove as some of the decompressors will
     37 * try to define their own functions if these are not defined as macros.
     38 */
     39#define memzero(s, n)	memset((s), 0, (n))
     40#ifndef memmove
     41#define memmove		memmove
     42/* Functions used by the included decompressor code below. */
     43void *memmove(void *dest, const void *src, size_t n);
     44#endif
     45
     46/*
     47 * This is set up by the setup-routine at boot-time
     48 */
     49struct boot_params *boot_params;
     50
     51struct port_io_ops pio_ops;
     52
     53memptr free_mem_ptr;
     54memptr free_mem_end_ptr;
     55
     56static char *vidmem;
     57static int vidport;
     58
     59/* These might be accessed before .bss is cleared, so use .data instead. */
     60static int lines __section(".data");
     61static int cols __section(".data");
     62
     63#ifdef CONFIG_KERNEL_GZIP
     64#include "../../../../lib/decompress_inflate.c"
     65#endif
     66
     67#ifdef CONFIG_KERNEL_BZIP2
     68#include "../../../../lib/decompress_bunzip2.c"
     69#endif
     70
     71#ifdef CONFIG_KERNEL_LZMA
     72#include "../../../../lib/decompress_unlzma.c"
     73#endif
     74
     75#ifdef CONFIG_KERNEL_XZ
     76#include "../../../../lib/decompress_unxz.c"
     77#endif
     78
     79#ifdef CONFIG_KERNEL_LZO
     80#include "../../../../lib/decompress_unlzo.c"
     81#endif
     82
     83#ifdef CONFIG_KERNEL_LZ4
     84#include "../../../../lib/decompress_unlz4.c"
     85#endif
     86
     87#ifdef CONFIG_KERNEL_ZSTD
     88#include "../../../../lib/decompress_unzstd.c"
     89#endif
     90/*
     91 * NOTE: When adding a new decompressor, please update the analysis in
     92 * ../header.S.
     93 */
     94
     95static void scroll(void)
     96{
     97	int i;
     98
     99	memmove(vidmem, vidmem + cols * 2, (lines - 1) * cols * 2);
    100	for (i = (lines - 1) * cols * 2; i < lines * cols * 2; i += 2)
    101		vidmem[i] = ' ';
    102}
    103
    104#define XMTRDY          0x20
    105
    106#define TXR             0       /*  Transmit register (WRITE) */
    107#define LSR             5       /*  Line Status               */
    108static void serial_putchar(int ch)
    109{
    110	unsigned timeout = 0xffff;
    111
    112	while ((inb(early_serial_base + LSR) & XMTRDY) == 0 && --timeout)
    113		cpu_relax();
    114
    115	outb(ch, early_serial_base + TXR);
    116}
    117
    118void __putstr(const char *s)
    119{
    120	int x, y, pos;
    121	char c;
    122
    123	if (early_serial_base) {
    124		const char *str = s;
    125		while (*str) {
    126			if (*str == '\n')
    127				serial_putchar('\r');
    128			serial_putchar(*str++);
    129		}
    130	}
    131
    132	if (lines == 0 || cols == 0)
    133		return;
    134
    135	x = boot_params->screen_info.orig_x;
    136	y = boot_params->screen_info.orig_y;
    137
    138	while ((c = *s++) != '\0') {
    139		if (c == '\n') {
    140			x = 0;
    141			if (++y >= lines) {
    142				scroll();
    143				y--;
    144			}
    145		} else {
    146			vidmem[(x + cols * y) * 2] = c;
    147			if (++x >= cols) {
    148				x = 0;
    149				if (++y >= lines) {
    150					scroll();
    151					y--;
    152				}
    153			}
    154		}
    155	}
    156
    157	boot_params->screen_info.orig_x = x;
    158	boot_params->screen_info.orig_y = y;
    159
    160	pos = (x + cols * y) * 2;	/* Update cursor position */
    161	outb(14, vidport);
    162	outb(0xff & (pos >> 9), vidport+1);
    163	outb(15, vidport);
    164	outb(0xff & (pos >> 1), vidport+1);
    165}
    166
    167void __puthex(unsigned long value)
    168{
    169	char alpha[2] = "0";
    170	int bits;
    171
    172	for (bits = sizeof(value) * 8 - 4; bits >= 0; bits -= 4) {
    173		unsigned long digit = (value >> bits) & 0xf;
    174
    175		if (digit < 0xA)
    176			alpha[0] = '0' + digit;
    177		else
    178			alpha[0] = 'a' + (digit - 0xA);
    179
    180		__putstr(alpha);
    181	}
    182}
    183
    184#ifdef CONFIG_X86_NEED_RELOCS
    185static void handle_relocations(void *output, unsigned long output_len,
    186			       unsigned long virt_addr)
    187{
    188	int *reloc;
    189	unsigned long delta, map, ptr;
    190	unsigned long min_addr = (unsigned long)output;
    191	unsigned long max_addr = min_addr + (VO___bss_start - VO__text);
    192
    193	/*
    194	 * Calculate the delta between where vmlinux was linked to load
    195	 * and where it was actually loaded.
    196	 */
    197	delta = min_addr - LOAD_PHYSICAL_ADDR;
    198
    199	/*
    200	 * The kernel contains a table of relocation addresses. Those
    201	 * addresses have the final load address of the kernel in virtual
    202	 * memory. We are currently working in the self map. So we need to
    203	 * create an adjustment for kernel memory addresses to the self map.
    204	 * This will involve subtracting out the base address of the kernel.
    205	 */
    206	map = delta - __START_KERNEL_map;
    207
    208	/*
    209	 * 32-bit always performs relocations. 64-bit relocations are only
    210	 * needed if KASLR has chosen a different starting address offset
    211	 * from __START_KERNEL_map.
    212	 */
    213	if (IS_ENABLED(CONFIG_X86_64))
    214		delta = virt_addr - LOAD_PHYSICAL_ADDR;
    215
    216	if (!delta) {
    217		debug_putstr("No relocation needed... ");
    218		return;
    219	}
    220	debug_putstr("Performing relocations... ");
    221
    222	/*
    223	 * Process relocations: 32 bit relocations first then 64 bit after.
    224	 * Three sets of binary relocations are added to the end of the kernel
    225	 * before compression. Each relocation table entry is the kernel
    226	 * address of the location which needs to be updated stored as a
    227	 * 32-bit value which is sign extended to 64 bits.
    228	 *
    229	 * Format is:
    230	 *
    231	 * kernel bits...
    232	 * 0 - zero terminator for 64 bit relocations
    233	 * 64 bit relocation repeated
    234	 * 0 - zero terminator for inverse 32 bit relocations
    235	 * 32 bit inverse relocation repeated
    236	 * 0 - zero terminator for 32 bit relocations
    237	 * 32 bit relocation repeated
    238	 *
    239	 * So we work backwards from the end of the decompressed image.
    240	 */
    241	for (reloc = output + output_len - sizeof(*reloc); *reloc; reloc--) {
    242		long extended = *reloc;
    243		extended += map;
    244
    245		ptr = (unsigned long)extended;
    246		if (ptr < min_addr || ptr > max_addr)
    247			error("32-bit relocation outside of kernel!\n");
    248
    249		*(uint32_t *)ptr += delta;
    250	}
    251#ifdef CONFIG_X86_64
    252	while (*--reloc) {
    253		long extended = *reloc;
    254		extended += map;
    255
    256		ptr = (unsigned long)extended;
    257		if (ptr < min_addr || ptr > max_addr)
    258			error("inverse 32-bit relocation outside of kernel!\n");
    259
    260		*(int32_t *)ptr -= delta;
    261	}
    262	for (reloc--; *reloc; reloc--) {
    263		long extended = *reloc;
    264		extended += map;
    265
    266		ptr = (unsigned long)extended;
    267		if (ptr < min_addr || ptr > max_addr)
    268			error("64-bit relocation outside of kernel!\n");
    269
    270		*(uint64_t *)ptr += delta;
    271	}
    272#endif
    273}
    274#else
    275static inline void handle_relocations(void *output, unsigned long output_len,
    276				      unsigned long virt_addr)
    277{ }
    278#endif
    279
    280static void parse_elf(void *output)
    281{
    282#ifdef CONFIG_X86_64
    283	Elf64_Ehdr ehdr;
    284	Elf64_Phdr *phdrs, *phdr;
    285#else
    286	Elf32_Ehdr ehdr;
    287	Elf32_Phdr *phdrs, *phdr;
    288#endif
    289	void *dest;
    290	int i;
    291
    292	memcpy(&ehdr, output, sizeof(ehdr));
    293	if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
    294	   ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
    295	   ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
    296	   ehdr.e_ident[EI_MAG3] != ELFMAG3) {
    297		error("Kernel is not a valid ELF file");
    298		return;
    299	}
    300
    301	debug_putstr("Parsing ELF... ");
    302
    303	phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
    304	if (!phdrs)
    305		error("Failed to allocate space for phdrs");
    306
    307	memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
    308
    309	for (i = 0; i < ehdr.e_phnum; i++) {
    310		phdr = &phdrs[i];
    311
    312		switch (phdr->p_type) {
    313		case PT_LOAD:
    314#ifdef CONFIG_X86_64
    315			if ((phdr->p_align % 0x200000) != 0)
    316				error("Alignment of LOAD segment isn't multiple of 2MB");
    317#endif
    318#ifdef CONFIG_RELOCATABLE
    319			dest = output;
    320			dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR);
    321#else
    322			dest = (void *)(phdr->p_paddr);
    323#endif
    324			memmove(dest, output + phdr->p_offset, phdr->p_filesz);
    325			break;
    326		default: /* Ignore other PT_* */ break;
    327		}
    328	}
    329
    330	free(phdrs);
    331}
    332
    333/*
    334 * The compressed kernel image (ZO), has been moved so that its position
    335 * is against the end of the buffer used to hold the uncompressed kernel
    336 * image (VO) and the execution environment (.bss, .brk), which makes sure
    337 * there is room to do the in-place decompression. (See header.S for the
    338 * calculations.)
    339 *
    340 *                             |-----compressed kernel image------|
    341 *                             V                                  V
    342 * 0                       extract_offset                      +INIT_SIZE
    343 * |-----------|---------------|-------------------------|--------|
    344 *             |               |                         |        |
    345 *           VO__text      startup_32 of ZO          VO__end    ZO__end
    346 *             ^                                         ^
    347 *             |-------uncompressed kernel image---------|
    348 *
    349 */
    350asmlinkage __visible void *extract_kernel(void *rmode, memptr heap,
    351				  unsigned char *input_data,
    352				  unsigned long input_len,
    353				  unsigned char *output,
    354				  unsigned long output_len)
    355{
    356	const unsigned long kernel_total_size = VO__end - VO__text;
    357	unsigned long virt_addr = LOAD_PHYSICAL_ADDR;
    358	unsigned long needed_size;
    359
    360	/* Retain x86 boot parameters pointer passed from startup_32/64. */
    361	boot_params = rmode;
    362
    363	/* Clear flags intended for solely in-kernel use. */
    364	boot_params->hdr.loadflags &= ~KASLR_FLAG;
    365
    366	sanitize_boot_params(boot_params);
    367
    368	if (boot_params->screen_info.orig_video_mode == 7) {
    369		vidmem = (char *) 0xb0000;
    370		vidport = 0x3b4;
    371	} else {
    372		vidmem = (char *) 0xb8000;
    373		vidport = 0x3d4;
    374	}
    375
    376	lines = boot_params->screen_info.orig_video_lines;
    377	cols = boot_params->screen_info.orig_video_cols;
    378
    379	init_default_io_ops();
    380
    381	/*
    382	 * Detect TDX guest environment.
    383	 *
    384	 * It has to be done before console_init() in order to use
    385	 * paravirtualized port I/O operations if needed.
    386	 */
    387	early_tdx_detect();
    388
    389	console_init();
    390
    391	/*
    392	 * Save RSDP address for later use. Have this after console_init()
    393	 * so that early debugging output from the RSDP parsing code can be
    394	 * collected.
    395	 */
    396	boot_params->acpi_rsdp_addr = get_rsdp_addr();
    397
    398	debug_putstr("early console in extract_kernel\n");
    399
    400	free_mem_ptr     = heap;	/* Heap */
    401	free_mem_end_ptr = heap + BOOT_HEAP_SIZE;
    402
    403	/*
    404	 * The memory hole needed for the kernel is the larger of either
    405	 * the entire decompressed kernel plus relocation table, or the
    406	 * entire decompressed kernel plus .bss and .brk sections.
    407	 *
    408	 * On X86_64, the memory is mapped with PMD pages. Round the
    409	 * size up so that the full extent of PMD pages mapped is
    410	 * included in the check against the valid memory table
    411	 * entries. This ensures the full mapped area is usable RAM
    412	 * and doesn't include any reserved areas.
    413	 */
    414	needed_size = max(output_len, kernel_total_size);
    415#ifdef CONFIG_X86_64
    416	needed_size = ALIGN(needed_size, MIN_KERNEL_ALIGN);
    417#endif
    418
    419	/* Report initial kernel position details. */
    420	debug_putaddr(input_data);
    421	debug_putaddr(input_len);
    422	debug_putaddr(output);
    423	debug_putaddr(output_len);
    424	debug_putaddr(kernel_total_size);
    425	debug_putaddr(needed_size);
    426
    427#ifdef CONFIG_X86_64
    428	/* Report address of 32-bit trampoline */
    429	debug_putaddr(trampoline_32bit);
    430#endif
    431
    432	choose_random_location((unsigned long)input_data, input_len,
    433				(unsigned long *)&output,
    434				needed_size,
    435				&virt_addr);
    436
    437	/* Validate memory location choices. */
    438	if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1))
    439		error("Destination physical address inappropriately aligned");
    440	if (virt_addr & (MIN_KERNEL_ALIGN - 1))
    441		error("Destination virtual address inappropriately aligned");
    442#ifdef CONFIG_X86_64
    443	if (heap > 0x3fffffffffffUL)
    444		error("Destination address too large");
    445	if (virt_addr + max(output_len, kernel_total_size) > KERNEL_IMAGE_SIZE)
    446		error("Destination virtual address is beyond the kernel mapping area");
    447#else
    448	if (heap > ((-__PAGE_OFFSET-(128<<20)-1) & 0x7fffffff))
    449		error("Destination address too large");
    450#endif
    451#ifndef CONFIG_RELOCATABLE
    452	if (virt_addr != LOAD_PHYSICAL_ADDR)
    453		error("Destination virtual address changed when not relocatable");
    454#endif
    455
    456	debug_putstr("\nDecompressing Linux... ");
    457	__decompress(input_data, input_len, NULL, NULL, output, output_len,
    458			NULL, error);
    459	parse_elf(output);
    460	handle_relocations(output, output_len, virt_addr);
    461	debug_putstr("done.\nBooting the kernel.\n");
    462
    463	/* Disable exception handling before booting the kernel */
    464	cleanup_exception_handling();
    465
    466	return output;
    467}
    468
    469void fortify_panic(const char *name)
    470{
    471	error("detected buffer overflow");
    472}