0001
0002
0003
0004
0005
0006
0007
0008
0009 #define _GNU_SOURCE
0010
0011 #include <features.h>
0012 #include <stdio.h>
0013
0014 #include "helpers.h"
0015
0016 #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16
0017
0018 int main()
0019 {
0020
0021 printf("[SKIP]\tGLIBC before 2.16 cannot compile this test\n");
0022 return 0;
0023 }
0024
0025 #else
0026
0027 #include <sys/time.h>
0028 #include <stdlib.h>
0029 #include <syscall.h>
0030 #include <unistd.h>
0031 #include <string.h>
0032 #include <inttypes.h>
0033 #include <sys/mman.h>
0034 #include <signal.h>
0035 #include <sys/ucontext.h>
0036 #include <err.h>
0037 #include <stddef.h>
0038 #include <stdbool.h>
0039 #include <sys/ptrace.h>
0040 #include <sys/user.h>
0041 #include <link.h>
0042 #include <sys/auxv.h>
0043 #include <dlfcn.h>
0044 #include <unwind.h>
0045
0046 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0047 int flags)
0048 {
0049 struct sigaction sa;
0050 memset(&sa, 0, sizeof(sa));
0051 sa.sa_sigaction = handler;
0052 sa.sa_flags = SA_SIGINFO | flags;
0053 sigemptyset(&sa.sa_mask);
0054 if (sigaction(sig, &sa, 0))
0055 err(1, "sigaction");
0056 }
0057
0058 static volatile sig_atomic_t nerrs;
0059 static unsigned long sysinfo;
0060 static bool got_sysinfo = false;
0061 static unsigned long return_address;
0062
0063 struct unwind_state {
0064 unsigned long ip;
0065 int depth;
0066 };
0067
0068 _Unwind_Reason_Code trace_fn(struct _Unwind_Context * ctx, void *opaque)
0069 {
0070 struct unwind_state *state = opaque;
0071 unsigned long ip = _Unwind_GetIP(ctx);
0072
0073 if (state->depth == -1) {
0074 if (ip == state->ip)
0075 state->depth = 0;
0076 else
0077 return _URC_NO_REASON;
0078 }
0079 printf("\t 0x%lx\n", ip);
0080
0081 if (ip == return_address) {
0082
0083 unsigned long eax = _Unwind_GetGR(ctx, 0);
0084 unsigned long ecx = _Unwind_GetGR(ctx, 1);
0085 unsigned long edx = _Unwind_GetGR(ctx, 2);
0086 unsigned long ebx = _Unwind_GetGR(ctx, 3);
0087 unsigned long ebp = _Unwind_GetGR(ctx, 5);
0088 unsigned long esi = _Unwind_GetGR(ctx, 6);
0089 unsigned long edi = _Unwind_GetGR(ctx, 7);
0090 bool ok = (eax == SYS_getpid || eax == getpid()) &&
0091 ebx == 1 && ecx == 2 && edx == 3 &&
0092 esi == 4 && edi == 5 && ebp == 6;
0093
0094 if (!ok)
0095 nerrs++;
0096 printf("[%s]\t NR = %ld, args = %ld, %ld, %ld, %ld, %ld, %ld\n",
0097 (ok ? "OK" : "FAIL"),
0098 eax, ebx, ecx, edx, esi, edi, ebp);
0099
0100 return _URC_NORMAL_STOP;
0101 } else {
0102 state->depth++;
0103 return _URC_NO_REASON;
0104 }
0105 }
0106
0107 static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
0108 {
0109 ucontext_t *ctx = (ucontext_t *)ctx_void;
0110 struct unwind_state state;
0111 unsigned long ip = ctx->uc_mcontext.gregs[REG_EIP];
0112
0113 if (!got_sysinfo && ip == sysinfo) {
0114 got_sysinfo = true;
0115
0116
0117 return_address = *(unsigned long *)(unsigned long)ctx->uc_mcontext.gregs[REG_ESP];
0118
0119 printf("\tIn vsyscall at 0x%lx, returning to 0x%lx\n",
0120 ip, return_address);
0121 }
0122
0123 if (!got_sysinfo)
0124 return;
0125
0126 if (ip == return_address) {
0127 ctx->uc_mcontext.gregs[REG_EFL] &= ~X86_EFLAGS_TF;
0128 printf("\tVsyscall is done\n");
0129 return;
0130 }
0131
0132 printf("\tSIGTRAP at 0x%lx\n", ip);
0133
0134 state.ip = ip;
0135 state.depth = -1;
0136 _Unwind_Backtrace(trace_fn, &state);
0137 }
0138
0139 int main()
0140 {
0141 sysinfo = getauxval(AT_SYSINFO);
0142 printf("\tAT_SYSINFO is 0x%lx\n", sysinfo);
0143
0144 Dl_info info;
0145 if (!dladdr((void *)sysinfo, &info)) {
0146 printf("[WARN]\tdladdr failed on AT_SYSINFO\n");
0147 } else {
0148 printf("[OK]\tAT_SYSINFO maps to %s, loaded at 0x%p\n",
0149 info.dli_fname, info.dli_fbase);
0150 }
0151
0152 sethandler(SIGTRAP, sigtrap, 0);
0153
0154 syscall(SYS_getpid);
0155 printf("[RUN]\tSet TF and check a fast syscall\n");
0156 set_eflags(get_eflags() | X86_EFLAGS_TF);
0157 syscall(SYS_getpid, 1, 2, 3, 4, 5, 6);
0158 if (!got_sysinfo) {
0159 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
0160
0161
0162
0163
0164
0165
0166 printf("[WARN]\tsyscall(2) didn't enter AT_SYSINFO\n");
0167 }
0168
0169 if (get_eflags() & X86_EFLAGS_TF) {
0170 printf("[FAIL]\tTF is still set\n");
0171 nerrs++;
0172 }
0173
0174 if (nerrs) {
0175 printf("[FAIL]\tThere were errors\n");
0176 return 1;
0177 } else {
0178 printf("[OK]\tAll is well\n");
0179 return 0;
0180 }
0181 }
0182
0183 #endif