/ sys / OpenBSD / stack_protector.c
stack_protector.c
  1  /*	$OpenBSD: stack_protector.c,v 1.10 2006/03/31 05:34:44 deraadt Exp $	*/
  2  
  3  /*
  4   * Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat.
  5   * All rights reserved.
  6   *
  7   * Redistribution and use in source and binary forms, with or without
  8   * modification, are permitted provided that the following conditions
  9   * are met:
 10   * 1. Redistributions of source code must retain the above copyright
 11   *    notice, this list of conditions and the following disclaimer.
 12   * 2. Redistributions in binary form must reproduce the above copyright
 13   *    notice, this list of conditions and the following disclaimer in the
 14   *    documentation and/or other materials provided with the distribution.
 15   *
 16   * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 17   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 19   * DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
 20   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 22   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 23   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 24   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 25   * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 26   * POSSIBILITY OF SUCH DAMAGE.
 27   *
 28   */
 29  
 30  #include <sys/param.h>
 31  #include <signal.h>
 32  #include <string.h>
 33  #include <stdlib.h>
 34  #include <unistd.h>
 35  #include <sys/types.h>
 36  #include <fcntl.h>
 37  #if __has_include(<CrashReporterClient.h>)
 38  #include <CrashReporterClient.h>
 39  #else
 40  #define CRSetCrashLogMessage(...)
 41  #endif
 42  #include "libproc.h"
 43  #include "_simple.h"
 44  
 45  #define	GUARD_MAX 8
 46  long __stack_chk_guard[GUARD_MAX] = {0, 0, 0, 0, 0, 0, 0, 0};
 47  void __abort(void) __cold __dead2;
 48  void __guard_setup(const char *apple[]) __attribute__ ((visibility ("hidden")));
 49  void __stack_chk_fail(void);
 50  
 51  static void
 52  __guard_from_kernel(const char *str)
 53  {
 54  	unsigned long long val;
 55  	char tmp[20], *p;
 56  	int idx = 0;
 57  
 58  	/* Skip over the 'stack_guard=' key to the list of values */
 59  	str = strchr(str, '=');
 60  	if (str == NULL)
 61  		return;
 62  	str++;
 63  
 64  	while (str && idx < GUARD_MAX) {
 65  		/*
 66  		 * Pull the next numeric string out of the list and convert it to
 67  		 * a real number.
 68  		 */
 69  		strlcpy(tmp, str, 20);
 70  		p = strchr(tmp, ',');
 71  		if (p)
 72  			*p = '\0';
 73  		val = strtoull(tmp, NULL, 0);
 74  		__stack_chk_guard[idx] = (long)(val & ((unsigned long) -1));
 75  		idx++;
 76  		if ((str = strchr(str, ',')) != NULL)
 77  			str++;
 78  	}
 79  }
 80  
 81  void
 82  __guard_setup(const char *apple[])
 83  {
 84  	int fd;
 85  	size_t len;
 86  	const char **p;
 87  
 88  	if (__stack_chk_guard[0] != 0)
 89  		return;
 90  
 91  	for (p = apple; p && *p; p++) {
 92  		if (strstr(*p, "stack_guard") == *p) {
 93  			__guard_from_kernel(*p);
 94  			bzero((void*)*p, strlen(*p));
 95  			if (__stack_chk_guard[0] != 0) {
 96  				return;
 97  			}
 98  		}
 99  	}
100  
101  	fd = open ("/dev/urandom", 0);
102  	if (fd != -1) {
103  		len = read (fd, (char*)&__stack_chk_guard, sizeof(__stack_chk_guard));
104  		close(fd);
105  		if (len == sizeof(__stack_chk_guard) && 
106                      *__stack_chk_guard != 0)
107  			return;
108  	}
109  
110  	/* If If a random generator can't be used, the protector switches the guard
111             to the "terminator canary" */
112  	((unsigned char *)__stack_chk_guard)[0] = 0;
113  	((unsigned char *)__stack_chk_guard)[1] = 0;
114  	((unsigned char *)__stack_chk_guard)[2] = '\n';
115  	((unsigned char *)__stack_chk_guard)[3] = 255;
116  }
117  
118  static const char *stackoverflow_msg = "stack buffer overflow";
119  
120  void
121  __stack_chk_fail()
122  {
123  	CRSetCrashLogMessage(stackoverflow_msg);
124  
125  	/* This may fail on a chroot jail... */
126  	char prog[2*MAXCOMLEN+1] = {0};
127  	proc_name(getpid(), prog, 2*MAXCOMLEN);
128  	prog[2*MAXCOMLEN] = 0;
129  	_simple_asl_log_prog(ASL_LEVEL_CRIT, "user", stackoverflow_msg, prog);
130  
131  	__abort();
132  }