cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qemu_elf.c (3527B)


      1/*
      2 * Copyright (c) 2018 Virtuozzo International GmbH
      3 *
      4 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      5 *
      6 */
      7
      8#include "qemu/osdep.h"
      9#include "err.h"
     10#include "qemu_elf.h"
     11
     12#define QEMU_NOTE_NAME "QEMU"
     13
     14#ifndef ROUND_UP
     15#define ROUND_UP(n, d) (((n) + (d) - 1) & -(0 ? (n) : (d)))
     16#endif
     17
     18#ifndef DIV_ROUND_UP
     19#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
     20#endif
     21
     22#define ELF_NOTE_SIZE(hdr_size, name_size, desc_size)   \
     23    ((DIV_ROUND_UP((hdr_size), 4) +                     \
     24      DIV_ROUND_UP((name_size), 4) +                    \
     25      DIV_ROUND_UP((desc_size), 4)) * 4)
     26
     27int is_system(QEMUCPUState *s)
     28{
     29    return s->gs.base >> 63;
     30}
     31
     32static char *nhdr_get_name(Elf64_Nhdr *nhdr)
     33{
     34    return (char *)nhdr + ROUND_UP(sizeof(*nhdr), 4);
     35}
     36
     37static void *nhdr_get_desc(Elf64_Nhdr *nhdr)
     38{
     39    return nhdr_get_name(nhdr) + ROUND_UP(nhdr->n_namesz, 4);
     40}
     41
     42static Elf64_Nhdr *nhdr_get_next(Elf64_Nhdr *nhdr)
     43{
     44    return (void *)((uint8_t *)nhdr + ELF_NOTE_SIZE(sizeof(*nhdr),
     45                nhdr->n_namesz, nhdr->n_descsz));
     46}
     47
     48Elf64_Phdr *elf64_getphdr(void *map)
     49{
     50    Elf64_Ehdr *ehdr = map;
     51    Elf64_Phdr *phdr = (void *)((uint8_t *)map + ehdr->e_phoff);
     52
     53    return phdr;
     54}
     55
     56Elf64_Half elf_getphdrnum(void *map)
     57{
     58    Elf64_Ehdr *ehdr = map;
     59
     60    return ehdr->e_phnum;
     61}
     62
     63static int init_states(QEMU_Elf *qe)
     64{
     65    Elf64_Phdr *phdr = elf64_getphdr(qe->map);
     66    Elf64_Nhdr *start = (void *)((uint8_t *)qe->map + phdr[0].p_offset);
     67    Elf64_Nhdr *end = (void *)((uint8_t *)start + phdr[0].p_memsz);
     68    Elf64_Nhdr *nhdr;
     69    size_t cpu_nr = 0;
     70
     71    if (phdr[0].p_type != PT_NOTE) {
     72        eprintf("Failed to find PT_NOTE\n");
     73        return 1;
     74    }
     75
     76    qe->has_kernel_gs_base = 1;
     77
     78    for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
     79        if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
     80            QEMUCPUState *state = nhdr_get_desc(nhdr);
     81
     82            if (state->size < sizeof(*state)) {
     83                eprintf("CPU #%zu: QEMU CPU state size %u doesn't match\n",
     84                        cpu_nr, state->size);
     85                /*
     86                 * We assume either every QEMU CPU state has KERNEL_GS_BASE or
     87                 * no one has.
     88                 */
     89                qe->has_kernel_gs_base = 0;
     90            }
     91            cpu_nr++;
     92        }
     93    }
     94
     95    printf("%zu CPU states has been found\n", cpu_nr);
     96
     97    qe->state = malloc(sizeof(*qe->state) * cpu_nr);
     98    if (!qe->state) {
     99        return 1;
    100    }
    101
    102    cpu_nr = 0;
    103
    104    for (nhdr = start; nhdr < end; nhdr = nhdr_get_next(nhdr)) {
    105        if (!strcmp(nhdr_get_name(nhdr), QEMU_NOTE_NAME)) {
    106            qe->state[cpu_nr] = nhdr_get_desc(nhdr);
    107            cpu_nr++;
    108        }
    109    }
    110
    111    qe->state_nr = cpu_nr;
    112
    113    return 0;
    114}
    115
    116static void exit_states(QEMU_Elf *qe)
    117{
    118    free(qe->state);
    119}
    120
    121int QEMU_Elf_init(QEMU_Elf *qe, const char *filename)
    122{
    123    GError *gerr = NULL;
    124    int err = 0;
    125
    126    qe->gmf = g_mapped_file_new(filename, TRUE, &gerr);
    127    if (gerr) {
    128        eprintf("Failed to map ELF dump file \'%s\'\n", filename);
    129        g_error_free(gerr);
    130        return 1;
    131    }
    132
    133    qe->map = g_mapped_file_get_contents(qe->gmf);
    134    qe->size = g_mapped_file_get_length(qe->gmf);
    135
    136    if (init_states(qe)) {
    137        eprintf("Failed to extract QEMU CPU states\n");
    138        err = 1;
    139        goto out_unmap;
    140    }
    141
    142    return 0;
    143
    144out_unmap:
    145    g_mapped_file_unref(qe->gmf);
    146
    147    return err;
    148}
    149
    150void QEMU_Elf_exit(QEMU_Elf *qe)
    151{
    152    exit_states(qe);
    153    g_mapped_file_unref(qe->gmf);
    154}