/*
 * Distributed under the terms of the GNU General Public License v2
 * $Header: $
 *
 * This is a modified version of Hiroaki Etoh's stack smashing routines
 * initialy implemented for glibc by pappy@gentoo.org

 * Dec 14 2003 solar@gentoo.org
 * begin code cleanup for ssp helper functions.
 *
 * Mar 10 2004 -solar
 * Allows the user to choose 1 of 3 signals, to stop an offending program.
 * Attempt to open kernel pseudo random device before urandom.
 * Print semi verbose audit messages for logging systems.
 *
 */

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

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

#ifdef __PROPOLICE_BLOCK_SEGV__
#define SSP_SIGTYPE SIGSEGV
#elif __PROPOLICE_BLOCK_KILL__
#define SSP_SIGTYPE SIGKILL
#else
#define SSP_SIGTYPE SIGABRT
#endif

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

void __guard_setup(void)
{
   int fd;
   ssize_t size;

   if (__guard[0] != 0)
      return;

   /* 
    * Attempt to open kernel pseudo random device if one exists before 
    * opening urandom to avoid entropy depletion.
    * thanks to PaX Team for the idea.
    */
   if ((fd = open("/dev/prandom", 0)) == (-1))
      fd = open("/dev/urandom", 0);

   if (fd != (-1)) {
      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" 
    */
   *__guard = 0xff0a0000UL;
}

void __stack_smash_handler(char func[], int damaged)
{
#if defined (__GNU_LIBRARY__)
   extern char *__progname;
#else
   char *__progname = "";
#endif

#ifdef _POSIX_SOURCE
   sigset_t mask;
   struct sigaction sa;

   /* Block all signal handlers except signal type */
   sigfillset(&mask);
   sigdelset(&mask, SSP_SIGTYPE);
   sigprocmask(SIG_BLOCK, &mask, NULL);
#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,		/* nls anyone? */
	   "%s: stack smashing attack in function %s "
	   "pid=%d ppid=%d uid=%d euid=%d gid=%d egid=%d\n",
	   __progname, func, (int) getpid(), (int) getppid(),
	   (int) getuid(), (int) geteuid(), (int) getgid(),
	   (int) getegid());
   syslog(LOG_CRIT | LOG_AUTHPRIV,
	  "%s: stack smashing attack in function %s "
	  "pid=%d ppid=%d uid=%d euid=%d gid=%d egid=%d",
	  __progname, func, (int) getpid(), (int) getppid(),
	  (int) getuid(), (int) geteuid(), (int) getgid(),
	  (int) getegid());

#ifdef _POSIX_SOURCE
   /* Make sure the handler is associated correctly and block all signals */
   memset(&sa, 0, sizeof(struct sigaction));
   sigfillset(&sa.sa_mask);
   sa.sa_flags = 0;
   sa.sa_handler = SIG_DFL;
   sigaction(SSP_SIGTYPE, &sa, NULL);
   (void) kill(getpid(), SSP_SIGTYPE);
#endif

   _exit(127);
   while (1);
}
