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

sysregs.c (5806B)


      1/*
      2 * Check emulated system register access for linux-user mode.
      3 *
      4 * See: https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
      5 *
      6 * Copyright (c) 2019 Linaro
      7 *
      8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9 * See the COPYING file in the top-level directory.
     10 *
     11 * SPDX-License-Identifier: GPL-2.0-or-later
     12 */
     13
     14#include <asm/hwcap.h>
     15#include <stdio.h>
     16#include <sys/auxv.h>
     17#include <signal.h>
     18#include <string.h>
     19#include <stdbool.h>
     20
     21#ifndef HWCAP_CPUID
     22#define HWCAP_CPUID (1 << 11)
     23#endif
     24
     25int failed_bit_count;
     26
     27/* Read and print system register `id' value */
     28#define get_cpu_reg(id) ({                                      \
     29            unsigned long __val = 0xdeadbeef;                   \
     30            asm("mrs %0, "#id : "=r" (__val));                  \
     31            printf("%-20s: 0x%016lx\n", #id, __val);            \
     32            __val;                                               \
     33        })
     34
     35/* As above but also check no bits outside of `mask' are set*/
     36#define get_cpu_reg_check_mask(id, mask) ({                     \
     37            unsigned long __cval = get_cpu_reg(id);             \
     38            unsigned long __extra = __cval & ~mask;             \
     39            if (__extra) {                                      \
     40                printf("%-20s: 0x%016lx\n", "  !!extra bits!!", __extra);   \
     41                failed_bit_count++;                            \
     42            }                                                   \
     43})
     44
     45/* As above but check RAZ */
     46#define get_cpu_reg_check_zero(id) ({                           \
     47            unsigned long __val = 0xdeadbeef;                   \
     48            asm("mrs %0, "#id : "=r" (__val));                  \
     49            if (__val) {                                        \
     50                printf("%-20s: 0x%016lx (not RAZ!)\n", #id, __val);        \
     51                failed_bit_count++;                            \
     52            }                                                   \
     53})
     54
     55/* Chunk up mask into 63:48, 47:32, 31:16, 15:0 to ease counting */
     56#define _m(a, b, c, d) (0x ## a ## b ## c ## d ##ULL)
     57
     58bool should_fail;
     59int should_fail_count;
     60int should_not_fail_count;
     61uintptr_t failed_pc[10];
     62
     63void sigill_handler(int signo, siginfo_t *si, void *data)
     64{
     65    ucontext_t *uc = (ucontext_t *)data;
     66
     67    if (should_fail) {
     68        should_fail_count++;
     69    } else {
     70        uintptr_t pc = (uintptr_t) uc->uc_mcontext.pc;
     71        failed_pc[should_not_fail_count++] =  pc;
     72    }
     73    uc->uc_mcontext.pc += 4;
     74}
     75
     76int main(void)
     77{
     78    struct sigaction sa;
     79
     80    /* Hook in a SIGILL handler */
     81    memset(&sa, 0, sizeof(struct sigaction));
     82    sa.sa_flags = SA_SIGINFO;
     83    sa.sa_sigaction = &sigill_handler;
     84    sigemptyset(&sa.sa_mask);
     85
     86    if (sigaction(SIGILL, &sa, 0) != 0) {
     87        perror("sigaction");
     88        return 1;
     89    }
     90
     91    /* Counter values have been exposed since Linux 4.12 */
     92    printf("Checking Counter registers\n");
     93
     94    get_cpu_reg(ctr_el0);
     95    get_cpu_reg(cntvct_el0);
     96    get_cpu_reg(cntfrq_el0);
     97
     98    /* HWCAP_CPUID indicates we can read feature registers, since Linux 4.11 */
     99    if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) {
    100        printf("CPUID registers unavailable\n");
    101        return 1;
    102    } else {
    103        printf("Checking CPUID registers\n");
    104    }
    105
    106    /*
    107     * Some registers only expose some bits to user-space. Anything
    108     * that is IMPDEF is exported as 0 to user-space. The _mask checks
    109     * assert no extra bits are set.
    110     *
    111     * This check is *not* comprehensive as some fields are set to
    112     * minimum valid fields - for the purposes of this check allowed
    113     * to have non-zero values.
    114     */
    115    get_cpu_reg_check_mask(id_aa64isar0_el1, _m(00ff,ffff,f0ff,fff0));
    116    get_cpu_reg_check_mask(id_aa64isar1_el1, _m(0000,00f0,ffff,ffff));
    117    /* TGran4 & TGran64 as pegged to -1 */
    118    get_cpu_reg_check_mask(id_aa64mmfr0_el1, _m(0000,0000,ff00,0000));
    119    get_cpu_reg_check_zero(id_aa64mmfr1_el1);
    120    /* EL1/EL0 reported as AA64 only */
    121    get_cpu_reg_check_mask(id_aa64pfr0_el1,  _m(000f,000f,00ff,0011));
    122    get_cpu_reg_check_mask(id_aa64pfr1_el1,  _m(0000,0000,0000,00f0));
    123    /* all hidden, DebugVer fixed to 0x6 (ARMv8 debug architecture) */
    124    get_cpu_reg_check_mask(id_aa64dfr0_el1,  _m(0000,0000,0000,0006));
    125    get_cpu_reg_check_zero(id_aa64dfr1_el1);
    126    get_cpu_reg_check_zero(id_aa64zfr0_el1);
    127
    128    get_cpu_reg_check_zero(id_aa64afr0_el1);
    129    get_cpu_reg_check_zero(id_aa64afr1_el1);
    130
    131    get_cpu_reg_check_mask(midr_el1,         _m(0000,0000,ffff,ffff));
    132    /* mpidr sets bit 31, everything else hidden */
    133    get_cpu_reg_check_mask(mpidr_el1,        _m(0000,0000,8000,0000));
    134    /* REVIDR is all IMPDEF so should be all zeros to user-space */
    135    get_cpu_reg_check_zero(revidr_el1);
    136
    137    /*
    138     * There are a block of more registers that are RAZ in the rest of
    139     * the Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7 space. However for
    140     * brevity we don't check stuff that is currently un-allocated
    141     * here. Feel free to add them ;-)
    142     */
    143
    144    printf("Remaining registers should fail\n");
    145    should_fail = true;
    146
    147    /* Unexposed register access causes SIGILL */
    148    get_cpu_reg(id_mmfr0_el1);
    149    get_cpu_reg(id_mmfr1_el1);
    150    get_cpu_reg(id_mmfr2_el1);
    151    get_cpu_reg(id_mmfr3_el1);
    152
    153    get_cpu_reg(mvfr0_el1);
    154    get_cpu_reg(mvfr1_el1);
    155
    156    if (should_not_fail_count > 0) {
    157        int i;
    158        for (i = 0; i < should_not_fail_count; i++) {
    159            uintptr_t pc = failed_pc[i];
    160            uint32_t insn = *(uint32_t *) pc;
    161            printf("insn %#x @ %#lx unexpected FAIL\n", insn, pc);
    162        }
    163        return 1;
    164    }
    165
    166    if (failed_bit_count > 0) {
    167        printf("Extra information leaked to user-space!\n");
    168        return 1;
    169    }
    170
    171    return should_fail_count == 6 ? 0 : 1;
    172}