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

coroutine-sigaltstack.c (8989B)


      1/*
      2 * sigaltstack coroutine initialization code
      3 *
      4 * Copyright (C) 2006  Anthony Liguori <anthony@codemonkey.ws>
      5 * Copyright (C) 2011  Kevin Wolf <kwolf@redhat.com>
      6 * Copyright (C) 2012  Alex Barcelo <abarcelo@ac.upc.edu>
      7** This file is partly based on pth_mctx.c, from the GNU Portable Threads
      8**  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com>
      9 *
     10 * This library is free software; you can redistribute it and/or
     11 * modify it under the terms of the GNU Lesser General Public
     12 * License as published by the Free Software Foundation; either
     13 * version 2.1 of the License, or (at your option) any later version.
     14 *
     15 * This library is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     18 * Lesser General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU Lesser General Public
     21 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
     22 */
     23
     24/* XXX Is there a nicer way to disable glibc's stack check for longjmp? */
     25#ifdef _FORTIFY_SOURCE
     26#undef _FORTIFY_SOURCE
     27#endif
     28#include "qemu/osdep.h"
     29#include <pthread.h>
     30#include "qemu-common.h"
     31#include "qemu/coroutine_int.h"
     32
     33#ifdef CONFIG_SAFESTACK
     34#error "SafeStack is not compatible with code run in alternate signal stacks"
     35#endif
     36
     37typedef struct {
     38    Coroutine base;
     39    void *stack;
     40    size_t stack_size;
     41    sigjmp_buf env;
     42} CoroutineSigAltStack;
     43
     44/**
     45 * Per-thread coroutine bookkeeping
     46 */
     47typedef struct {
     48    /** Currently executing coroutine */
     49    Coroutine *current;
     50
     51    /** The default coroutine */
     52    CoroutineSigAltStack leader;
     53
     54    /** Information for the signal handler (trampoline) */
     55    sigjmp_buf tr_reenter;
     56    volatile sig_atomic_t tr_called;
     57    void *tr_handler;
     58} CoroutineThreadState;
     59
     60static pthread_key_t thread_state_key;
     61
     62static CoroutineThreadState *coroutine_get_thread_state(void)
     63{
     64    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
     65
     66    if (!s) {
     67        s = g_malloc0(sizeof(*s));
     68        s->current = &s->leader.base;
     69        pthread_setspecific(thread_state_key, s);
     70    }
     71    return s;
     72}
     73
     74static void qemu_coroutine_thread_cleanup(void *opaque)
     75{
     76    CoroutineThreadState *s = opaque;
     77
     78    g_free(s);
     79}
     80
     81static void __attribute__((constructor)) coroutine_init(void)
     82{
     83    int ret;
     84
     85    ret = pthread_key_create(&thread_state_key, qemu_coroutine_thread_cleanup);
     86    if (ret != 0) {
     87        fprintf(stderr, "unable to create leader key: %s\n", strerror(errno));
     88        abort();
     89    }
     90}
     91
     92/* "boot" function
     93 * This is what starts the coroutine, is called from the trampoline
     94 * (from the signal handler when it is not signal handling, read ahead
     95 * for more information).
     96 */
     97static void coroutine_bootstrap(CoroutineSigAltStack *self, Coroutine *co)
     98{
     99    /* Initialize longjmp environment and switch back the caller */
    100    if (!sigsetjmp(self->env, 0)) {
    101        siglongjmp(*(sigjmp_buf *)co->entry_arg, 1);
    102    }
    103
    104    while (true) {
    105        co->entry(co->entry_arg);
    106        qemu_coroutine_switch(co, co->caller, COROUTINE_TERMINATE);
    107    }
    108}
    109
    110/*
    111 * This is used as the signal handler. This is called with the brand new stack
    112 * (thanks to sigaltstack). We have to return, given that this is a signal
    113 * handler and the sigmask and some other things are changed.
    114 */
    115static void coroutine_trampoline(int signal)
    116{
    117    CoroutineSigAltStack *self;
    118    Coroutine *co;
    119    CoroutineThreadState *coTS;
    120
    121    /* Get the thread specific information */
    122    coTS = coroutine_get_thread_state();
    123    self = coTS->tr_handler;
    124    coTS->tr_called = 1;
    125    co = &self->base;
    126
    127    /*
    128     * Here we have to do a bit of a ping pong between the caller, given that
    129     * this is a signal handler and we have to do a return "soon". Then the
    130     * caller can reestablish everything and do a siglongjmp here again.
    131     */
    132    if (!sigsetjmp(coTS->tr_reenter, 0)) {
    133        return;
    134    }
    135
    136    /*
    137     * Ok, the caller has siglongjmp'ed back to us, so now prepare
    138     * us for the real machine state switching. We have to jump
    139     * into another function here to get a new stack context for
    140     * the auto variables (which have to be auto-variables
    141     * because the start of the thread happens later). Else with
    142     * PIC (i.e. Position Independent Code which is used when PTH
    143     * is built as a shared library) most platforms would
    144     * horrible core dump as experience showed.
    145     */
    146    coroutine_bootstrap(self, co);
    147}
    148
    149Coroutine *qemu_coroutine_new(void)
    150{
    151    CoroutineSigAltStack *co;
    152    CoroutineThreadState *coTS;
    153    struct sigaction sa;
    154    struct sigaction osa;
    155    stack_t ss;
    156    stack_t oss;
    157    sigset_t sigs;
    158    sigset_t osigs;
    159    sigjmp_buf old_env;
    160    static pthread_mutex_t sigusr2_mutex = PTHREAD_MUTEX_INITIALIZER;
    161
    162    /* The way to manipulate stack is with the sigaltstack function. We
    163     * prepare a stack, with it delivering a signal to ourselves and then
    164     * put sigsetjmp/siglongjmp where needed.
    165     * This has been done keeping coroutine-ucontext as a model and with the
    166     * pth ideas (GNU Portable Threads). See coroutine-ucontext for the basics
    167     * of the coroutines and see pth_mctx.c (from the pth project) for the
    168     * sigaltstack way of manipulating stacks.
    169     */
    170
    171    co = g_malloc0(sizeof(*co));
    172    co->stack_size = COROUTINE_STACK_SIZE;
    173    co->stack = qemu_alloc_stack(&co->stack_size);
    174    co->base.entry_arg = &old_env; /* stash away our jmp_buf */
    175
    176    coTS = coroutine_get_thread_state();
    177    coTS->tr_handler = co;
    178
    179    /*
    180     * Preserve the SIGUSR2 signal state, block SIGUSR2,
    181     * and establish our signal handler. The signal will
    182     * later transfer control onto the signal stack.
    183     */
    184    sigemptyset(&sigs);
    185    sigaddset(&sigs, SIGUSR2);
    186    pthread_sigmask(SIG_BLOCK, &sigs, &osigs);
    187    sa.sa_handler = coroutine_trampoline;
    188    sigfillset(&sa.sa_mask);
    189    sa.sa_flags = SA_ONSTACK;
    190
    191    /*
    192     * sigaction() is a process-global operation.  We must not run
    193     * this code in multiple threads at once.
    194     */
    195    pthread_mutex_lock(&sigusr2_mutex);
    196    if (sigaction(SIGUSR2, &sa, &osa) != 0) {
    197        abort();
    198    }
    199
    200    /*
    201     * Set the new stack.
    202     */
    203    ss.ss_sp = co->stack;
    204    ss.ss_size = co->stack_size;
    205    ss.ss_flags = 0;
    206    if (sigaltstack(&ss, &oss) < 0) {
    207        abort();
    208    }
    209
    210    /*
    211     * Now transfer control onto the signal stack and set it up.
    212     * It will return immediately via "return" after the sigsetjmp()
    213     * was performed. Be careful here with race conditions.  The
    214     * signal can be delivered the first time sigsuspend() is
    215     * called.
    216     */
    217    coTS->tr_called = 0;
    218    pthread_kill(pthread_self(), SIGUSR2);
    219    sigfillset(&sigs);
    220    sigdelset(&sigs, SIGUSR2);
    221    while (!coTS->tr_called) {
    222        sigsuspend(&sigs);
    223    }
    224
    225    /*
    226     * Inform the system that we are back off the signal stack by
    227     * removing the alternative signal stack. Be careful here: It
    228     * first has to be disabled, before it can be removed.
    229     */
    230    sigaltstack(NULL, &ss);
    231    ss.ss_flags = SS_DISABLE;
    232    if (sigaltstack(&ss, NULL) < 0) {
    233        abort();
    234    }
    235    sigaltstack(NULL, &ss);
    236    if (!(oss.ss_flags & SS_DISABLE)) {
    237        sigaltstack(&oss, NULL);
    238    }
    239
    240    /*
    241     * Restore the old SIGUSR2 signal handler and mask
    242     */
    243    sigaction(SIGUSR2, &osa, NULL);
    244    pthread_mutex_unlock(&sigusr2_mutex);
    245
    246    pthread_sigmask(SIG_SETMASK, &osigs, NULL);
    247
    248    /*
    249     * Now enter the trampoline again, but this time not as a signal
    250     * handler. Instead we jump into it directly. The functionally
    251     * redundant ping-pong pointer arithmetic is necessary to avoid
    252     * type-conversion warnings related to the `volatile' qualifier and
    253     * the fact that `jmp_buf' usually is an array type.
    254     */
    255    if (!sigsetjmp(old_env, 0)) {
    256        siglongjmp(coTS->tr_reenter, 1);
    257    }
    258
    259    /*
    260     * Ok, we returned again, so now we're finished
    261     */
    262
    263    return &co->base;
    264}
    265
    266void qemu_coroutine_delete(Coroutine *co_)
    267{
    268    CoroutineSigAltStack *co = DO_UPCAST(CoroutineSigAltStack, base, co_);
    269
    270    qemu_free_stack(co->stack, co->stack_size);
    271    g_free(co);
    272}
    273
    274CoroutineAction qemu_coroutine_switch(Coroutine *from_, Coroutine *to_,
    275                                      CoroutineAction action)
    276{
    277    CoroutineSigAltStack *from = DO_UPCAST(CoroutineSigAltStack, base, from_);
    278    CoroutineSigAltStack *to = DO_UPCAST(CoroutineSigAltStack, base, to_);
    279    CoroutineThreadState *s = coroutine_get_thread_state();
    280    int ret;
    281
    282    s->current = to_;
    283
    284    ret = sigsetjmp(from->env, 0);
    285    if (ret == 0) {
    286        siglongjmp(to->env, action);
    287    }
    288    return ret;
    289}
    290
    291Coroutine *qemu_coroutine_self(void)
    292{
    293    CoroutineThreadState *s = coroutine_get_thread_state();
    294
    295    return s->current;
    296}
    297
    298bool qemu_in_coroutine(void)
    299{
    300    CoroutineThreadState *s = pthread_getspecific(thread_state_key);
    301
    302    return s && s->current->caller;
    303}
    304