|
From: John R.
|
>>struct stack_layout
>>{
>> void *ret_addr;
>> int i;
>> char *str;
>> char buf[16];
>> unsigned long ebp;
>> unsigned long eip;
>>};
>>
>>void handler_new( int signo, siginfo_t* xx, void* uc)
>>{
>> ucontext_t* ctx = (ucontext_t*)uc;
>> struct stack_layout* stack;
>> printf("in handler2, setting EIP to %p\n", (void*)&diversion);
>> stack = (struct stack_layout*)ctx->uc_mcontext.gregs[REG_ESP];
>>
>> stack--; /* push the stack_layout structure */
[snip]
> How do you know it is OK to overwrite the top of the
> kernel-constructed signal frame with your struct stack_layout?
It's **very** dirty, but it looks like it does "work" on recent Linux.
Look in linux-2.6.15/arch/i386/kernel/sigframe.h:
struct rt_sigframe
{
char __user *pretcode;
int sig;
struct siginfo __user *pinfo;
void __user *puc;
struct siginfo info;
struct ucontext uc;
struct _fpstate fpstate;
char retcode[8];
};
and in linux-2.6.15/include/asm-i386/sigcontext.h:
struct _fpstate {
/* Regular FPU environment */
unsigned long cw;
unsigned long sw;
unsigned long tag;
unsigned long ipoff;
unsigned long cssel;
unsigned long dataoff;
unsigned long datasel;
struct _fpreg _st[8];
unsigned short status;
unsigned short magic; /* 0xffff = regular FPU data only */
/* FXSR FPU environment */
unsigned long _fxsr_env[6]; /* FXSR FPU env is ignored */
unsigned long mxcsr;
unsigned long reserved;
struct _fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
struct _xmmreg _xmm[8];
unsigned long padding[56];
};
and the comment in linux-2.6.15/arch/i386/kernel/signal.c:
/*
* This is movl $,%eax ; int $0x80
*
* WE DO NOT USE IT ANY MORE! It's only left here for historical
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
err |= __put_user(0xb8, (char __user *)(frame->retcode+0));
err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1));
err |= __put_user(0x80cd, (short __user *)(frame->retcode+5));
So the 8 bytes of retcode is "available", as is the 4*56 bytes of
_fpstate.padding, assuming the space for the FXSR FPU environment
really is present. If so, then no "important" data gets overwritten
because sizeof(struct stack_layout) < (8 + 4*56) .
If the kernel actually pushes only struct sigframe (not struct rt_sigframe),
then you're much more likely to be in trouble:
struct sigframe
{
char __user *pretcode;
int sig;
struct sigcontext sc;
struct _fpstate fpstate;
unsigned long extramask[_NSIG_WORDS-1];
char retcode[8];
};
where _NSIG_WORDS equals 2. extramask[0] holds the bits for
the second (and last) group of 32 signals, and will be overwritten.
This can lead to _extremely_ hard-to-diagnose random behavior.
Notice that struct sigframe contains no siginfo; SA_SIGINFO was
omitted when asking the kernel to establish the handler.
This report:
rt_sigframe and vDSO inhibit virtualization of signal handling
https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=180351
might be of interest. Among other things: with the latest glibc-2.3.90
and Fedora Core kernel vDSO, then it is hard to avoid a race if you're
mucking with the frame when a pthread_cond_wait() gets canceled.
[snip]
> - changing %ESP inside the signal handler is likely to cause memcheck to
> emit lots of bogus messages, and these may be difficult to get rid of
> (changing %ESP is really asking for trouble from memcheck :-)
Any emulator must give special consideration to return from signal,
including noticing when %esp changes "unexpectedly."
--
|