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

unwind_vdso.c (4351B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * unwind_vdso.c - tests unwind info for AT_SYSINFO in the vDSO
      4 * Copyright (c) 2014-2015 Andrew Lutomirski
      5 *
      6 * This tests __kernel_vsyscall's unwind info.
      7 */
      8
      9#define _GNU_SOURCE
     10
     11#include <features.h>
     12#include <stdio.h>
     13
     14#include "helpers.h"
     15
     16#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16
     17
     18int main()
     19{
     20	/* We need getauxval(). */
     21	printf("[SKIP]\tGLIBC before 2.16 cannot compile this test\n");
     22	return 0;
     23}
     24
     25#else
     26
     27#include <sys/time.h>
     28#include <stdlib.h>
     29#include <syscall.h>
     30#include <unistd.h>
     31#include <string.h>
     32#include <inttypes.h>
     33#include <sys/mman.h>
     34#include <signal.h>
     35#include <sys/ucontext.h>
     36#include <err.h>
     37#include <stddef.h>
     38#include <stdbool.h>
     39#include <sys/ptrace.h>
     40#include <sys/user.h>
     41#include <link.h>
     42#include <sys/auxv.h>
     43#include <dlfcn.h>
     44#include <unwind.h>
     45
     46static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
     47		       int flags)
     48{
     49	struct sigaction sa;
     50	memset(&sa, 0, sizeof(sa));
     51	sa.sa_sigaction = handler;
     52	sa.sa_flags = SA_SIGINFO | flags;
     53	sigemptyset(&sa.sa_mask);
     54	if (sigaction(sig, &sa, 0))
     55		err(1, "sigaction");
     56}
     57
     58static volatile sig_atomic_t nerrs;
     59static unsigned long sysinfo;
     60static bool got_sysinfo = false;
     61static unsigned long return_address;
     62
     63struct unwind_state {
     64	unsigned long ip;	/* trap source */
     65	int depth;		/* -1 until we hit the trap source */
     66};
     67
     68_Unwind_Reason_Code trace_fn(struct _Unwind_Context * ctx, void *opaque)
     69{
     70	struct unwind_state *state = opaque;
     71	unsigned long ip = _Unwind_GetIP(ctx);
     72
     73	if (state->depth == -1) {
     74		if (ip == state->ip)
     75			state->depth = 0;
     76		else
     77			return _URC_NO_REASON;	/* Not there yet */
     78	}
     79	printf("\t  0x%lx\n", ip);
     80
     81	if (ip == return_address) {
     82		/* Here we are. */
     83		unsigned long eax = _Unwind_GetGR(ctx, 0);
     84		unsigned long ecx = _Unwind_GetGR(ctx, 1);
     85		unsigned long edx = _Unwind_GetGR(ctx, 2);
     86		unsigned long ebx = _Unwind_GetGR(ctx, 3);
     87		unsigned long ebp = _Unwind_GetGR(ctx, 5);
     88		unsigned long esi = _Unwind_GetGR(ctx, 6);
     89		unsigned long edi = _Unwind_GetGR(ctx, 7);
     90		bool ok = (eax == SYS_getpid || eax == getpid()) &&
     91			ebx == 1 && ecx == 2 && edx == 3 &&
     92			esi == 4 && edi == 5 && ebp == 6;
     93
     94		if (!ok)
     95			nerrs++;
     96		printf("[%s]\t  NR = %ld, args = %ld, %ld, %ld, %ld, %ld, %ld\n",
     97		       (ok ? "OK" : "FAIL"),
     98		       eax, ebx, ecx, edx, esi, edi, ebp);
     99
    100		return _URC_NORMAL_STOP;
    101	} else {
    102		state->depth++;
    103		return _URC_NO_REASON;
    104	}
    105}
    106
    107static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
    108{
    109	ucontext_t *ctx = (ucontext_t *)ctx_void;
    110	struct unwind_state state;
    111	unsigned long ip = ctx->uc_mcontext.gregs[REG_EIP];
    112
    113	if (!got_sysinfo && ip == sysinfo) {
    114		got_sysinfo = true;
    115
    116		/* Find the return address. */
    117		return_address = *(unsigned long *)(unsigned long)ctx->uc_mcontext.gregs[REG_ESP];
    118
    119		printf("\tIn vsyscall at 0x%lx, returning to 0x%lx\n",
    120		       ip, return_address);
    121	}
    122
    123	if (!got_sysinfo)
    124		return;		/* Not there yet */
    125
    126	if (ip == return_address) {
    127		ctx->uc_mcontext.gregs[REG_EFL] &= ~X86_EFLAGS_TF;
    128		printf("\tVsyscall is done\n");
    129		return;
    130	}
    131
    132	printf("\tSIGTRAP at 0x%lx\n", ip);
    133
    134	state.ip = ip;
    135	state.depth = -1;
    136	_Unwind_Backtrace(trace_fn, &state);
    137}
    138
    139int main()
    140{
    141	sysinfo = getauxval(AT_SYSINFO);
    142	printf("\tAT_SYSINFO is 0x%lx\n", sysinfo);
    143
    144	Dl_info info;
    145	if (!dladdr((void *)sysinfo, &info)) {
    146		printf("[WARN]\tdladdr failed on AT_SYSINFO\n");
    147	} else {
    148		printf("[OK]\tAT_SYSINFO maps to %s, loaded at 0x%p\n",
    149		       info.dli_fname, info.dli_fbase);
    150	}
    151
    152	sethandler(SIGTRAP, sigtrap, 0);
    153
    154	syscall(SYS_getpid);  /* Force symbol binding without TF set. */
    155	printf("[RUN]\tSet TF and check a fast syscall\n");
    156	set_eflags(get_eflags() | X86_EFLAGS_TF);
    157	syscall(SYS_getpid, 1, 2, 3, 4, 5, 6);
    158	if (!got_sysinfo) {
    159		set_eflags(get_eflags() & ~X86_EFLAGS_TF);
    160
    161		/*
    162		 * The most likely cause of this is that you're on Debian or
    163		 * a Debian-based distro, you're missing libc6-i686, and you're
    164		 * affected by libc/19006 (https://sourceware.org/PR19006).
    165		 */
    166		printf("[WARN]\tsyscall(2) didn't enter AT_SYSINFO\n");
    167	}
    168
    169	if (get_eflags() & X86_EFLAGS_TF) {
    170		printf("[FAIL]\tTF is still set\n");
    171		nerrs++;
    172	}
    173
    174	if (nerrs) {
    175		printf("[FAIL]\tThere were errors\n");
    176		return 1;
    177	} else {
    178		printf("[OK]\tAll is well\n");
    179		return 0;
    180	}
    181}
    182
    183#endif	/* New enough libc */