summaryrefslogtreecommitdiff
blob: 0eac14f230fb65f9987a0a5046a9f1ee212e65ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
 * Distributed under the terms of the GNU General Public License v2
 * $Header: /var/cvsroot/gentoo-x86/sys-libs/uclibc/files/0.9.26/ssp.c,v 1.1 2005/01/12 03:51:45 vapier Exp $
 *
 * This is a modified version of Hiroaki Etoh's stack smashing routines
 * implemented for glibc.
 *
 * The following people have contributed input to this code.
 * Ned Ludd - <solar[@]gentoo.org>
 * Alexander Gabert - <pappy[@]gentoo.org>
 * The PaX Team - <pageexec[@]freemail.hu>
 * Peter S. Mazinger - <ps.m[@]gmx.net>
 * Yoann Vandoorselaere - <yoann[@]prelude-ids.org>
 * Robert Connolly - <robert[@]linuxfromscratch.org>
 * Cory Visi <cory@visi.name>
 *
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/sysctl.h>

#ifndef _PATH_LOG
#define _PATH_LOG "/dev/log"
#endif

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

unsigned long __guard = 0UL;

void
__guard_setup (void)
{
  size_t size;
#ifdef HAVE_DEV_ERANDOM
  int mib[3];
#endif

  if (__guard != 0UL)
    return;

#ifndef __SSP_QUICK_CANARY__
#ifdef HAVE_DEV_ERANDOM
  /* Random is another depth in Linux, hence an array of 3. */
  mib[0] = CTL_KERN;
  mib[1] = KERN_RANDOM;
  mib[2] = RANDOM_ERANDOM;

  size = sizeof (unsigned long);
  if (__sysctl (mib, 3, &__guard, &size, NULL, 0) != (-1))
    if (__guard != 0UL)
      return;
#endif
  /* 
   * Attempt to open kernel pseudo random device if one exists before 
   * opening urandom to avoid system entropy depletion.
   */
  {
    int fd;
#ifdef HAVE_DEV_ERANDOM
    if ((fd = open ("/dev/erandom", O_RDONLY)) == (-1))
#endif
      fd = open ("/dev/urandom", O_RDONLY);
    if (fd != (-1))
      {
	size = read (fd, (char *) &__guard, sizeof (__guard));
	close (fd);
	if (size == sizeof (__guard))
	  return;
      }
  }
#endif

  /* If sysctl was unsuccessful, use the "terminator canary". */
  __guard = 0xFF0A0D00UL;

  {
    /* Everything failed? Or we are using a weakened model of the 
     * terminator canary */
    struct timeval tv;

    gettimeofday (&tv, NULL);
    __guard ^= tv.tv_usec ^ tv.tv_sec;
  }
}

void
__stack_smash_handler (char func[], int damaged)
{
  struct sockaddr_un sock;	/* AF_UNIX address of local logger */
  struct sigaction sa;
  const char message[] = ": stack smashing attack in function ";
  int bufsz, len, log;
  char buf[512];
  extern char *__progname;

  sigset_t mask;
  sigfillset (&mask);

  sigdelset (&mask, SSP_SIGTYPE);	/* Block all signal handlers */
  sigprocmask (SIG_BLOCK, &mask, NULL);	/* except SIGABRT */

  bufsz = sizeof (buf);
  strcpy (buf, "<2>");
  len = 3;

  strncat (buf, __progname, sizeof (buf) - 4);
  len = strlen (buf);

  if (bufsz > len)
    {
      strncat (buf, message, bufsz - len - 1);
      len = strlen (buf);
    }
  if (bufsz > len)
    {
      strncat (buf, func, bufsz - len - 1);
      len = strlen (buf);
    }

  /* print error message */
  write (STDERR_FILENO, buf + 3, len - 3);
  write (STDERR_FILENO, "()\n", 3);
  if ((log = socket (AF_UNIX, SOCK_DGRAM, 0)) != -1)
    {
      /* Send "found" message to the "/dev/log" path */
      sock.sun_family = AF_UNIX;
      (void) strncpy (sock.sun_path, _PATH_LOG, sizeof (sock.sun_path) - 1);
      sock.sun_path[sizeof (sock.sun_path) - 1] = '\0';
      sendto (log, buf, len, 0, (struct sockaddr *) &sock, sizeof (sock));
    }

  /* Make sure the default handler is associated with the our signal handler */

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