You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
4.7 KiB
209 lines
4.7 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*
|
|
* This application tests the behavior when a signal is delivered on a
|
|
* bad application stack or when a signal handler returns from a bad
|
|
* application stack. In both cases, Pin (or the kernel) tries to
|
|
* read or write a signal context frame from inaccessible memory, and
|
|
* this causes an error.
|
|
*
|
|
* This application tests several variants if this situation. See the
|
|
* comments in the makefile, which describe each variant that is tested.
|
|
*/
|
|
|
|
// features.h does not exist on FreeBSD
|
|
#ifdef TARGET_LINUX
|
|
// features initializes the system's state, including the state of __USE_GNU
|
|
#include <features.h>
|
|
#endif
|
|
|
|
// If __USE_GNU is defined, we don't need to do anything.
|
|
// If we defined it ourselves, we need to undefine it later.
|
|
#ifndef __USE_GNU
|
|
# define __USE_GNU
|
|
# define APP_UNDEF_USE_GNU
|
|
#endif
|
|
|
|
#if defined(TARGET_MAC)
|
|
# include <sys/ucontext.h>
|
|
#else
|
|
# include <ucontext.h>
|
|
#endif
|
|
|
|
// If we defined __USE_GNU ourselves, we need to undefine it here.
|
|
#ifdef APP_UNDEF_USE_GNU
|
|
# undef __USE_GNU
|
|
# undef APP_UNDEF_USE_GNU
|
|
#endif
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
|
|
static void Usage();
|
|
static void Handle(int, siginfo_t *, void *);
|
|
extern void DoILLOnBadStack();
|
|
extern int DoSigreturnOnBadStack();
|
|
|
|
int DoSigill = 0;
|
|
int DoAltStack = 0;
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct sigaction act;
|
|
stack_t ss;
|
|
|
|
|
|
if (argc != 3)
|
|
{
|
|
Usage();
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[1], "sigill") == 0)
|
|
{
|
|
DoSigill = 1;
|
|
}
|
|
else if (strcmp(argv[1], "sigreturn") == 0)
|
|
{
|
|
DoSigill = 0;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
return 1;
|
|
}
|
|
if (strcmp(argv[2], "altstack") == 0)
|
|
{
|
|
DoAltStack = 1;
|
|
}
|
|
else if (strcmp(argv[2], "noaltstack") == 0)
|
|
{
|
|
DoAltStack = 0;
|
|
}
|
|
else
|
|
{
|
|
Usage();
|
|
return 1;
|
|
}
|
|
|
|
if (DoAltStack)
|
|
{
|
|
ss.ss_sp = malloc(SIGSTKSZ);
|
|
ss.ss_flags = 0;
|
|
ss.ss_size = SIGSTKSZ;
|
|
if (sigaltstack(&ss, 0) != 0)
|
|
{
|
|
printf("Failed to set alternate stack\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
act.sa_sigaction = Handle;
|
|
act.sa_flags = (DoAltStack) ? (SA_ONSTACK | SA_SIGINFO) : (SA_SIGINFO);
|
|
sigemptyset(&act.sa_mask);
|
|
if (sigaction(SIGSEGV, &act, 0) != 0)
|
|
{
|
|
printf("Unable to set SEGV handler\n");
|
|
return 1;
|
|
}
|
|
|
|
if (DoSigill)
|
|
{
|
|
act.sa_sigaction = Handle;
|
|
#if defined(TARGET_MAC)
|
|
act.sa_flags = (DoAltStack) ? (SA_ONSTACK | SA_SIGINFO) : (SA_SIGINFO);
|
|
#else
|
|
act.sa_flags = SA_SIGINFO;
|
|
#endif
|
|
sigemptyset(&act.sa_mask);
|
|
if (sigaction(SIGILL, &act, 0) != 0)
|
|
{
|
|
printf("Unable to set ILL handler\n");
|
|
return 1;
|
|
}
|
|
|
|
DoILLOnBadStack();
|
|
}
|
|
else
|
|
{
|
|
int err = DoSigreturnOnBadStack();
|
|
switch (err)
|
|
{
|
|
case EFAULT:
|
|
printf("Sigreturn returned EFAULT\n");
|
|
break;
|
|
default:
|
|
printf("Sigreturn returned <error %d>\n", err);
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf("Returning normally\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void Usage()
|
|
{
|
|
printf("Usage: bad-stack {sigill | sigreturn} {altstack | noaltstack}\n");
|
|
}
|
|
|
|
|
|
static void Handle(int sig, siginfo_t *info, void *v)
|
|
{
|
|
ucontext_t *ctxt = v;
|
|
|
|
switch (sig)
|
|
{
|
|
case SIGSEGV:
|
|
printf("Got signal SEGV\n");
|
|
break;
|
|
case SIGILL:
|
|
printf("Got signal ILL\n");
|
|
break;
|
|
default:
|
|
printf("Got signal <%d>\n", sig);
|
|
break;
|
|
}
|
|
|
|
if (DoSigill)
|
|
{
|
|
/*
|
|
* Skip over the UD2 instruction.
|
|
*/
|
|
#if defined(TARGET_LINUX) && defined(TARGET_IA32)
|
|
ctxt->uc_mcontext.gregs[REG_EIP] += 2;
|
|
#elif defined(TARGET_LINUX) && defined(TARGET_IA32E)
|
|
ctxt->uc_mcontext.gregs[REG_RIP] += 2;
|
|
#elif defined(TARGET_BSD) && defined(TARGET_IA32)
|
|
ctxt->uc_mcontext.mc_eip += 2;
|
|
#elif defined(TARGET_BSD) && defined(TARGET_IA32E)
|
|
ctxt->uc_mcontext.mc_rip += 2;
|
|
#elif defined(TARGET_MAC) && defined(TARGET_IA32)
|
|
ctxt->uc_mcontext->__ss.__eip += 2;
|
|
#elif defined(TARGET_MAC) && defined(TARGET_IA32E)
|
|
ctxt->uc_mcontext->__ss.__rip += 2;
|
|
#else
|
|
#error "Undefined code"
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
exit(0);
|
|
}
|
|
}
|