lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Fri, 05 Sep 2008 13:49:06 -0700
From:	Alin Jula <alin.jula@....com>
To:	Mikael Pettersson <mikpe@...uu.se>
Cc:	linux-kernel@...r.kernel.org
Subject: Re: sigaction with SA_SIGINFO does not pass the correct return
	context

Thanks for the pointers, Mikael. I appreciate it.

Alin


On Thu, 2008-09-04 at 09:33 +0200, Mikael Pettersson wrote:
> Alin Jula writes:
>  > Summary: sigaction with SG_SIGINFO passes the incorrect context on
>  > OpenSuse (kernels 2.6.16.21-0.8-smp and 2.6.25.11-0.1-default).
>  > However, it passes the correct one on Ubuntu (kernel
>  > 2.6.24-19-generic).
>  > 
>  > I'm trying to catch the SIGSEGV signal, do something, and then return
>  > control back to the application. I use "sigaction" with the SA_SIGINFO
>  > flag. This flags allows a handler to be called upon a signal, and it
>  > should (POSIX defined) also provide the context of the thread when the
>  > signal was issued. The problem is that the right context does _not_ work
>  > on OpenSuse, but it works on Ubuntu.
>  > 
>  > So I was wondering if there is a specific action that one needs to take
>  > on OpenSuse when dealing with this issue, or if there is a bug in the
>  > kernel/opensuse ?
>  > 
>  > On Ubuntu (kernel 2.6.24-19-generic), sigaction correctly provides the
>  > context of the thread that raised the signal. However, on two other
>  > installations of OpenSuse (kernels 2.6.16.21-0.8-smp and
>  > 2.6.25.11-0.1-default), sigaction provides a different context.
>  > 
>  > Below is the code example, with its summary. 4KB get allocated with
>  > mmap, with "not to be accessed" protection. A write to this memory chunk
>  > raises a SIGSEGV signal. This signal is then caught, and the memory
>  > protection is changed to read+write. Then, the control is given back to
>  > the instruction that raised this signal, and the application should
>  > proceed from there. The code works on Ubuntu, but on the both OpenSuse
>  > installations that I tried (see above for kernels), the context passed
>  > by sigaction is the context of the handler instead of the instruction
>  > that raised the signal.
>  > 
>  > Here is the code:
>  >        #include <unistd.h>
>  >        #include <signal.h>
>  >        #include <stdio.h>
>  >        #include <stdlib.h>
>  >        #include <sys/mman.h>
>  >        #include <ucontext.h>
>  >        
>  >        #define handle_error(msg) \
>  >            do { perror(msg); exit(EXIT_FAILURE); } while (0)
>  > 
>  > 
>  >        ucontext_t context_trigger, context_sig;
>  >        struct sigaction sa_new, sa_old;     
>  > 
>  >        static void
>  >        handler(int sig, siginfo_t *si, void *context)
>  >        {
>  >        if ((sig == SIGSEGV) || (sig == SIGBUS) )
>  >        	{
>  >            printf("\nGot SIGSEGV or SIGBUS at address: 0x%lx and context
>  > =%lx\n",(long) si->si_addr, context);
>  > 
>  > 	   if (mprotect(si->si_addr, 4096 ,PROT_READ | PROT_WRITE) == -1)
>  > 	   	handle_error("mprotect failed from the handler");
>  > 	   else
>  > 	   	printf("\nmprotect set the protection to RW\n");
>  >  
>  > #if 1
>  > 	  // The intention here is to switch back to the context that signaled
>  > the SIGSEGV. Unfortunately, it does not 
>  > 	  // do that. Instead, it switches the context back to the handler
>  > function, in a recursive call.
>  >        	   swapcontext(&context_sig, (ucontext_t*)context);
>  > #else
>  > 	   // Manually set the context to the point previous to accessing the
>  > memory. This works !
>  >        	   swapcontext(&context_sig, &context_trigger);
>  > #endif
>  > 	}
>  > 
>  >        }
>  > 
>  >        int
>  >        main(int argc, char *argv[])
>  >        {
>  > 	   /* Set the handler */
>  >            sa_new.sa_flags = SA_SIGINFO;
>  >            sigemptyset(&sa_new.sa_mask);
>  >            sa_new.sa_sigaction = handler;
>  >            if (sigaction(SIGSEGV, &sa_new, &sa_old) == -1)
>  >                handle_error("sigaction");
>  > 
>  > 
>  >            /* Allocate 4096 bytes with initial protection PROT_NONE */
>  > 
>  >            char* p = (char*)mmap(0,4096,PROT_NONE, MAP_ANONYMOUS |
>  > MAP_PRIVATE, -1, 0);
>  >            if (p ==  MAP_FAILED)
>  >                handle_error("mmap");
>  > 
>  > 	   getcontext(&context_trigger);
>  > 	   
>  > 	   /* Access the protected memory, which will raise a SIGSEGV or SIGBUS
>  > */
>  >            *(p) = 'a';
>  >                
>  >            printf("\nSuccess\n");    
>  >            exit(EXIT_SUCCESS);
>  >        }
>  > 
>  > 
>  > Any help/pointer would be greatly appreciated.
> 
> Your're doing this all wrong.
> 
> An SA_SIGINFO signal handler gets a pointer to the faulting context
> in its third parameter. To modify it you assign fields in it, e.g.
> the program counter. Then you return from the signal handler. Upon
> return the kernel reloads this possibly modified context.
> 
> If you don't modify it the faulting instruction will usually be
> rexecuted (though x87 fp exceptions are delayed so the original
> faulting instruction will be skipped). In your simple example all
> you need to do is to mprotect the page and return without changing
> the context.
> 
> Last time I checked getcontext/swapcontext weren't system calls,
> so what they do is up to whetever libc your code is linked to.
> 
> For examples of FP signal handlers look in the runtime system of
> the Erlang/OTP system, and I'm sure lots of garbage collectors and
> distributed shared memory systems out there use sigsegv handlers.
> 
> Finally, a distro specific problem should be taken up with that
> distro.
> 
> /Mikael
> ( mikpe at acumem dot com )

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

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ