/*
 Distributed under the terms of the GNU General Public License v2
 $Header: $

- This is a modified version of Hiroaki Etoh's stack smashing routines
- implemented for glibc by pappy@gentoo.org

- (Dec 14 2003 solar@gentoo.org)
- A SEGV is better to send to the process vs ABRT
- Needed for core dumping and actually being able to fix bugs.
- If EBUG_SSP on x86 is defined then we dump extended base pointer trace to stderr.

*/

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

#ifdef _POSIX_SOURCE
#include <signal.h>
#endif

#include <syslog.h>


long __guard[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };

void __guard_setup(void)
{
   int fd;

   if (__guard[0] != 0)
      return;
   fd = open("/dev/urandom", 0);
   if (fd != -1) {
      ssize_t size = read(fd, (char *) &__guard, sizeof(__guard));

      close(fd);
      if (size == sizeof(__guard))
	 return;
   }
   /* If a random generator can't be used, the protector switches the guard
    * to the "terminator canary" */
   ((char *) __guard)[0] = 0;
   ((char *) __guard)[1] = 0;
   ((char *) __guard)[2] = '\n';
   ((char *) __guard)[3] = 255;
}

void __stack_smash_handler(char func[], int damaged)
{
#if defined(__GNUC__) && defined(__i386__) && defined(EBUG_SSP)
   unsigned int *ebp, i;

   /* save the extended base pointer right away */
 __asm__("movl %%ebp, %0":"=g"(ebp));

   fprintf(stderr, "SSP Trace:\n");
   for (i = 0;
	(*ebp > (unsigned int) ebp) &&
	(*ebp < (0x3FffFF | (unsigned int) ebp));
	ebp = (unsigned int *) *ebp, i++)
      fprintf(stderr, "\t#%-2d 0x%08X\n", i, *(ebp + 1));
#endif

#if defined (__GNU_LIBRARY__)
   extern char *__progname;
#else
   char *__progname = "";
#endif

#ifdef _POSIX_SOURCE
   sigset_t mask;

   sigfillset(&mask);
   sigdelset(&mask, SIGSEGV);	/* Block all signal handlers */
   sigprocmask(SIG_BLOCK, &mask, NULL);	/* except SIGSEGV */
#endif
   /*
    * print error message
    * please drop a mail to yoann at prelude-ids.org if you change the
    * message, so that prelude-lml signature can be updated.
    */
   fprintf(stderr,
	   "%s: stack smashing attack in function %s pid=%d uid=%d euid=%d gid=%d egid=%d\n",
	   __progname, func, (int) getpid(), (int) getuid(),
	   (int) geteuid(), (int) getgid(), (int) getegid());

   syslog(LOG_CRIT | LOG_AUTHPRIV,
	  "%s: stack smashing attack in function %s pid=%d uid=%d euid=%d gid=%d egid=%d",
	  __progname, func, (int) getpid(), (int) getuid(),
	  (int) geteuid(), (int) getgid(), (int) getegid());

#ifdef _POSIX_SOURCE
   {				/* Make sure the default handler is associated with SIGSEGV */
      struct sigaction sa;

      memset(&sa, 0, sizeof(struct sigaction));
      sigfillset(&sa.sa_mask);	/* Block all signals */
      sa.sa_flags = 0;
      sa.sa_handler = SIG_DFL;
      sigaction(SIGSEGV, &sa, NULL);
      (void) kill(getpid(), SIGSEGV);
   }
#endif
   _exit(127);
}
