Home | History | Annotate | Download | only in lib
      1 /*
      2  * tools/testing/selftests/kvm/lib/elf.c
      3  *
      4  * Copyright (C) 2018, Google LLC.
      5  *
      6  * This work is licensed under the terms of the GNU GPL, version 2.
      7  */
      8 
      9 #include "test_util.h"
     10 
     11 #include <bits/endian.h>
     12 #include <linux/elf.h>
     13 
     14 #include "kvm_util.h"
     15 #include "kvm_util_internal.h"
     16 
     17 static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp)
     18 {
     19 	off_t offset_rv;
     20 
     21 	/* Open the ELF file. */
     22 	int fd;
     23 	fd = open(filename, O_RDONLY);
     24 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
     25 		"  filename: %s\n"
     26 		"  rv: %i errno: %i", filename, fd, errno);
     27 
     28 	/* Read in and validate ELF Identification Record.
     29 	 * The ELF Identification record is the first 16 (EI_NIDENT) bytes
     30 	 * of the ELF header, which is at the beginning of the ELF file.
     31 	 * For now it is only safe to read the first EI_NIDENT bytes.  Once
     32 	 * read and validated, the value of e_ehsize can be used to determine
     33 	 * the real size of the ELF header.
     34 	 */
     35 	unsigned char ident[EI_NIDENT];
     36 	test_read(fd, ident, sizeof(ident));
     37 	TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1)
     38 		&& (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3),
     39 		"ELF MAGIC Mismatch,\n"
     40 		"  filename: %s\n"
     41 		"  ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n"
     42 		"  Expected: %02x %02x %02x %02x",
     43 		filename,
     44 		ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3],
     45 		ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3);
     46 	TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64,
     47 		"Current implementation only able to handle ELFCLASS64,\n"
     48 		"  filename: %s\n"
     49 		"  ident[EI_CLASS]: %02x\n"
     50 		"  expected: %02x",
     51 		filename,
     52 		ident[EI_CLASS], ELFCLASS64);
     53 	TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN)
     54 			&& (ident[EI_DATA] == ELFDATA2LSB))
     55 		|| ((BYTE_ORDER == BIG_ENDIAN)
     56 			&& (ident[EI_DATA] == ELFDATA2MSB)), "Current "
     57 		"implementation only able to handle\n"
     58 		"cases where the host and ELF file endianness\n"
     59 		"is the same:\n"
     60 		"  host BYTE_ORDER: %u\n"
     61 		"  host LITTLE_ENDIAN: %u\n"
     62 		"  host BIG_ENDIAN: %u\n"
     63 		"  ident[EI_DATA]: %u\n"
     64 		"  ELFDATA2LSB: %u\n"
     65 		"  ELFDATA2MSB: %u",
     66 		BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN,
     67 		ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB);
     68 	TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT,
     69 		"Current implementation only able to handle current "
     70 		"ELF version,\n"
     71 		"  filename: %s\n"
     72 		"  ident[EI_VERSION]: %02x\n"
     73 		"  expected: %02x",
     74 		filename, ident[EI_VERSION], EV_CURRENT);
     75 
     76 	/* Read in the ELF header.
     77 	 * With the ELF Identification portion of the ELF header
     78 	 * validated, especially that the value at EI_VERSION is
     79 	 * as expected, it is now safe to read the entire ELF header.
     80 	 */
     81 	offset_rv = lseek(fd, 0, SEEK_SET);
     82 	TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n"
     83 		"  rv: %zi expected: %i", offset_rv, 0);
     84 	test_read(fd, hdrp, sizeof(*hdrp));
     85 	TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr),
     86 		"Unexpected physical header size,\n"
     87 		"  hdrp->e_phentsize: %x\n"
     88 		"  expected: %zx",
     89 		hdrp->e_phentsize, sizeof(Elf64_Phdr));
     90 	TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr),
     91 		"Unexpected section header size,\n"
     92 		"  hdrp->e_shentsize: %x\n"
     93 		"  expected: %zx",
     94 		hdrp->e_shentsize, sizeof(Elf64_Shdr));
     95 }
     96 
     97 /* VM ELF Load
     98  *
     99  * Input Args:
    100  *   filename - Path to ELF file
    101  *
    102  * Output Args: None
    103  *
    104  * Input/Output Args:
    105  *   vm - Pointer to opaque type that describes the VM.
    106  *
    107  * Return: None, TEST_ASSERT failures for all error conditions
    108  *
    109  * Loads the program image of the ELF file specified by filename,
    110  * into the virtual address space of the VM pointed to by vm.  On entry
    111  * the VM needs to not be using any of the virtual address space used
    112  * by the image and it needs to have sufficient available physical pages, to
    113  * back the virtual pages used to load the image.
    114  */
    115 void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename,
    116 	uint32_t data_memslot, uint32_t pgd_memslot)
    117 {
    118 	off_t offset, offset_rv;
    119 	Elf64_Ehdr hdr;
    120 
    121 	/* Open the ELF file. */
    122 	int fd;
    123 	fd = open(filename, O_RDONLY);
    124 	TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n"
    125 		"  filename: %s\n"
    126 		"  rv: %i errno: %i", filename, fd, errno);
    127 
    128 	/* Read in the ELF header. */
    129 	elfhdr_get(filename, &hdr);
    130 
    131 	/* For each program header.
    132 	 * The following ELF header members specify the location
    133 	 * and size of the program headers:
    134 	 *
    135 	 *   e_phoff - File offset to start of program headers
    136 	 *   e_phentsize - Size of each program header
    137 	 *   e_phnum - Number of program header entries
    138 	 */
    139 	for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) {
    140 		/* Seek to the beginning of the program header. */
    141 		offset = hdr.e_phoff + (n1 * hdr.e_phentsize);
    142 		offset_rv = lseek(fd, offset, SEEK_SET);
    143 		TEST_ASSERT(offset_rv == offset,
    144 			"Failed to seek to begining of program header %u,\n"
    145 			"  filename: %s\n"
    146 			"  rv: %jd errno: %i",
    147 			n1, filename, (intmax_t) offset_rv, errno);
    148 
    149 		/* Read in the program header. */
    150 		Elf64_Phdr phdr;
    151 		test_read(fd, &phdr, sizeof(phdr));
    152 
    153 		/* Skip if this header doesn't describe a loadable segment. */
    154 		if (phdr.p_type != PT_LOAD)
    155 			continue;
    156 
    157 		/* Allocate memory for this segment within the VM. */
    158 		TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment "
    159 			"memsize of 0,\n"
    160 			"  phdr index: %u p_memsz: 0x%" PRIx64,
    161 			n1, (uint64_t) phdr.p_memsz);
    162 		vm_vaddr_t seg_vstart = phdr.p_vaddr;
    163 		seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1);
    164 		vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1;
    165 		seg_vend |= vm->page_size - 1;
    166 		size_t seg_size = seg_vend - seg_vstart + 1;
    167 
    168 		vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart,
    169 			data_memslot, pgd_memslot);
    170 		TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate "
    171 			"virtual memory for segment at requested min addr,\n"
    172 			"  segment idx: %u\n"
    173 			"  seg_vstart: 0x%lx\n"
    174 			"  vaddr: 0x%lx",
    175 			n1, seg_vstart, vaddr);
    176 		memset(addr_gva2hva(vm, vaddr), 0, seg_size);
    177 		/* TODO(lhuemill): Set permissions of each memory segment
    178 		 * based on the least-significant 3 bits of phdr.p_flags.
    179 		 */
    180 
    181 		/* Load portion of initial state that is contained within
    182 		 * the ELF file.
    183 		 */
    184 		if (phdr.p_filesz) {
    185 			offset_rv = lseek(fd, phdr.p_offset, SEEK_SET);
    186 			TEST_ASSERT(offset_rv == phdr.p_offset,
    187 				"Seek to program segment offset failed,\n"
    188 				"  program header idx: %u errno: %i\n"
    189 				"  offset_rv: 0x%jx\n"
    190 				"  expected: 0x%jx\n",
    191 				n1, errno, (intmax_t) offset_rv,
    192 				(intmax_t) phdr.p_offset);
    193 			test_read(fd, addr_gva2hva(vm, phdr.p_vaddr),
    194 				phdr.p_filesz);
    195 		}
    196 	}
    197 }
    198