Re: 2.2.1: memory corruption and SIGSEGV handlers.

Mark Hemment (markhe@SCO.com)
Mon, 1 Mar 1999 16:14:18 +0000 (GMT)


Hi Tigran,

Had a quick look at this.
A _possible_ reason for the problem is;

i) Page-fault to grow the stack (say the call to fprintf()
generates this)
ii) Size of stack has reached hard-limit, so calls
force_signal(SIGSEGV, tsk)
iii) Returning from the page-fault handler causes the signal
to be delivered.
iv) do_signal() sees a handler is installed and calls
handle_signal(), which calls setup_frame().
v) setup_frame() calls get_sigframe() to find the address to
build the frame at (the normal user-stack if altsigstack
isn't being used).
vi) access_ok() returns true as you're not running on an old
i386, so only the address limit is checked.
This doesn't seem to be a strong enough check. It is
possible there is not enough distance between the top
of stack and the hard stack size limit (ulimit) for a
full frame.
vii) If there isn't enough space, building up the stack frame
causes a page-fault, which cannot grow the stack (as the
limit has been reached).

Am I correct in my understanding at step vi)?
If so the fix would be another, stronger check in setup_frame() and
setup_rt_frame(). If there isn't enough distance, the handler should be
removed before delivering the signal (SIGSEGV - ie. drop core).

Mark

On Mon, 1 Mar 1999, Tigran Aivazian wrote:

> Hi guys,
>
> Below is a simple program that does this:
>
> 1. Registers a handler for SIGSEGV using sigaction(2) with no special
> flags.
>
> 2. Causes the first SIGSEGV to be sent by *(int *)0 = 0;
>
> 3. Inside the handler prints something and does *(int *)0 = 0;
>
> This results in a recursive invocation of the handler, which is
> reasonable.
>
> However, there are two problems I personally see here:
>
> a) eventually, the program hangs (presumably when we run out of user
> stack)
>
> b) if you, additionally do something like ulimit -sH 1 before running the
> program, it causes some memory (page cache?) corruption (i.e. next time
> you run gcc(1) to compile something you get Internal error: signal 11
> stuff).
>
> This is clearly wrong so someone should have a look at the different code
> paths corresponding to signal delivery in the case of kill(2) and via GP
> fault (trap handler). (i.e. if I replace *0 = 0 with kill(getpid(),
> SIGSEGV) everything is ok).
>
> Regards,
> ------
> Tigran A. Aivazian | http://www.sco.com
> Escalations Research Group | tel: +44-(0)1923-813796
> Santa Cruz Operation Ltd | http://www.aivazian.demon.co.uk
>
> #include <stdio.h>
> #include <signal.h>
> #include <unistd.h>
>
> int sig = SIGSEGV;
>
> void gotsig(int signo)
> {
> int stack;
> fprintf(stderr, "%d: signal%d (stack=%p) ",
> getpid(), signo, &stack);
> *(int *)0 = 0;
> }
>
> int main(int argc, char *argv[])
> {
> struct sigaction act;
> act.sa_handler = gotsig;
> sigemptyset(&act.sa_mask);
> act.sa_flags = 0;
> if ( -1 == sigaction(sig, &act, NULL)) {
> perror("sigaction()");
> exit(1);
> }
> *(int *)0 = 0;
> return 0;
> }
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.rutgers.edu
> Please read the FAQ at http://www.tux.org/lkml/

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/