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

rseq.c (3331B)


      1// SPDX-License-Identifier: LGPL-2.1
      2/*
      3 * rseq.c
      4 *
      5 * Copyright (C) 2016 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
      6 *
      7 * This library is free software; you can redistribute it and/or
      8 * modify it under the terms of the GNU Lesser General Public
      9 * License as published by the Free Software Foundation; only
     10 * version 2.1 of the License.
     11 *
     12 * This library is distributed in the hope that it will be useful,
     13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     15 * Lesser General Public License for more details.
     16 */
     17
     18#define _GNU_SOURCE
     19#include <errno.h>
     20#include <sched.h>
     21#include <stdio.h>
     22#include <stdlib.h>
     23#include <string.h>
     24#include <unistd.h>
     25#include <syscall.h>
     26#include <assert.h>
     27#include <signal.h>
     28#include <limits.h>
     29#include <dlfcn.h>
     30#include <stddef.h>
     31
     32#include "../kselftest.h"
     33#include "rseq.h"
     34
     35static const ptrdiff_t *libc_rseq_offset_p;
     36static const unsigned int *libc_rseq_size_p;
     37static const unsigned int *libc_rseq_flags_p;
     38
     39/* Offset from the thread pointer to the rseq area.  */
     40ptrdiff_t rseq_offset;
     41
     42/* Size of the registered rseq area.  0 if the registration was
     43   unsuccessful.  */
     44unsigned int rseq_size = -1U;
     45
     46/* Flags used during rseq registration.  */
     47unsigned int rseq_flags;
     48
     49static int rseq_ownership;
     50
     51static
     52__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = {
     53	.cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED,
     54};
     55
     56static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len,
     57		    int flags, uint32_t sig)
     58{
     59	return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
     60}
     61
     62int rseq_available(void)
     63{
     64	int rc;
     65
     66	rc = sys_rseq(NULL, 0, 0, 0);
     67	if (rc != -1)
     68		abort();
     69	switch (errno) {
     70	case ENOSYS:
     71		return 0;
     72	case EINVAL:
     73		return 1;
     74	default:
     75		abort();
     76	}
     77}
     78
     79int rseq_register_current_thread(void)
     80{
     81	int rc;
     82
     83	if (!rseq_ownership) {
     84		/* Treat libc's ownership as a successful registration. */
     85		return 0;
     86	}
     87	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG);
     88	if (rc)
     89		return -1;
     90	assert(rseq_current_cpu_raw() >= 0);
     91	return 0;
     92}
     93
     94int rseq_unregister_current_thread(void)
     95{
     96	int rc;
     97
     98	if (!rseq_ownership) {
     99		/* Treat libc's ownership as a successful unregistration. */
    100		return 0;
    101	}
    102	rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
    103	if (rc)
    104		return -1;
    105	return 0;
    106}
    107
    108static __attribute__((constructor))
    109void rseq_init(void)
    110{
    111	libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
    112	libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
    113	libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
    114	if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p) {
    115		/* rseq registration owned by glibc */
    116		rseq_offset = *libc_rseq_offset_p;
    117		rseq_size = *libc_rseq_size_p;
    118		rseq_flags = *libc_rseq_flags_p;
    119		return;
    120	}
    121	if (!rseq_available())
    122		return;
    123	rseq_ownership = 1;
    124	rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
    125	rseq_size = sizeof(struct rseq_abi);
    126	rseq_flags = 0;
    127}
    128
    129static __attribute__((destructor))
    130void rseq_exit(void)
    131{
    132	if (!rseq_ownership)
    133		return;
    134	rseq_offset = 0;
    135	rseq_size = -1U;
    136	rseq_ownership = 0;
    137}
    138
    139int32_t rseq_fallback_current_cpu(void)
    140{
    141	int32_t cpu;
    142
    143	cpu = sched_getcpu();
    144	if (cpu < 0) {
    145		perror("sched_getcpu()");
    146		abort();
    147	}
    148	return cpu;
    149}