1169719Skan/* $NetBSD: stack_protector.c,v 1.4 2006/11/22 17:23:25 christos Exp $	*/
2169719Skan/* $OpenBSD: stack_protector.c,v 1.10 2006/03/31 05:34:44 deraadt Exp $	*/
3169719Skan/*
4169719Skan * Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat.
5169719Skan * All rights reserved.
6169719Skan *
7169719Skan * Redistribution and use in source and binary forms, with or without
8169719Skan * modification, are permitted provided that the following conditions
9169719Skan * are met:
10169719Skan * 1. Redistributions of source code must retain the above copyright
11169719Skan *    notice, this list of conditions and the following disclaimer.
12169719Skan * 2. Redistributions in binary form must reproduce the above copyright
13169719Skan *    notice, this list of conditions and the following disclaimer in the
14169719Skan *    documentation and/or other materials provided with the distribution.
15169719Skan *
16169719Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17169719Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18169719Skan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19169719Skan * DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
20169719Skan * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21169719Skan * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22169719Skan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23169719Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24169719Skan * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25169719Skan * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26169719Skan * POSSIBILITY OF SUCH DAMAGE.
27169719Skan *
28169719Skan */
29169719Skan
30169719Skan#include <sys/cdefs.h>
31169719Skan__FBSDID("$FreeBSD$");
32169719Skan
33169719Skan#include <sys/param.h>
34169719Skan#include <sys/sysctl.h>
35169719Skan#include <sys/types.h>
36211416Skib#include <errno.h>
37211416Skib#include <link.h>
38169719Skan#include <signal.h>
39169719Skan#include <string.h>
40169719Skan#include <syslog.h>
41169719Skan#include <unistd.h>
42211416Skib#include "libc_private.h"
43169719Skan
44288105Sjlhextern int __sysctl(const int *name, u_int namelen, void *oldp,
45288105Sjlh    size_t *oldlenp, void *newp, size_t newlen);
46169719Skan
47169719Skanlong __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};
48169719Skanstatic void __guard_setup(void) __attribute__((__constructor__, __used__));
49169719Skanstatic void __fail(const char *);
50169719Skanvoid __stack_chk_fail(void);
51169719Skanvoid __chk_fail(void);
52169719Skan
53169719Skan/*LINTED used*/
54169719Skanstatic void
55169719Skan__guard_setup(void)
56169719Skan{
57288105Sjlh	static const int mib[2] = { CTL_KERN, KERN_ARND };
58169719Skan	size_t len;
59211416Skib	int error;
60169719Skan
61169719Skan	if (__stack_chk_guard[0] != 0)
62169719Skan		return;
63211416Skib	error = _elf_aux_info(AT_CANARY, __stack_chk_guard,
64211416Skib	    sizeof(__stack_chk_guard));
65211416Skib	if (error == 0 && __stack_chk_guard[0] != 0)
66211416Skib		return;
67169719Skan
68169719Skan	len = sizeof(__stack_chk_guard);
69288105Sjlh	if (__sysctl(mib, nitems(mib), __stack_chk_guard, &len, NULL, 0) ==
70288105Sjlh	    -1 || len != sizeof(__stack_chk_guard)) {
71169719Skan		/* If sysctl was unsuccessful, use the "terminator canary". */
72169719Skan		((unsigned char *)(void *)__stack_chk_guard)[0] = 0;
73169719Skan		((unsigned char *)(void *)__stack_chk_guard)[1] = 0;
74169719Skan		((unsigned char *)(void *)__stack_chk_guard)[2] = '\n';
75169719Skan		((unsigned char *)(void *)__stack_chk_guard)[3] = 255;
76169719Skan	}
77169719Skan}
78169719Skan
79169719Skan/*ARGSUSED*/
80169719Skanstatic void
81169719Skan__fail(const char *msg)
82169719Skan{
83169719Skan	struct sigaction sa;
84169719Skan	sigset_t mask;
85169719Skan
86169719Skan	/* Immediately block all signal handlers from running code */
87169719Skan	(void)sigfillset(&mask);
88169719Skan	(void)sigdelset(&mask, SIGABRT);
89169719Skan	(void)sigprocmask(SIG_BLOCK, &mask, NULL);
90169719Skan
91169719Skan	/* This may fail on a chroot jail... */
92213785Srpaulo	syslog(LOG_CRIT, "%s", msg);
93169719Skan
94169719Skan	(void)memset(&sa, 0, sizeof(sa));
95169719Skan	(void)sigemptyset(&sa.sa_mask);
96169719Skan	sa.sa_flags = 0;
97169719Skan	sa.sa_handler = SIG_DFL;
98169719Skan	(void)sigaction(SIGABRT, &sa, NULL);
99169719Skan	(void)kill(getpid(), SIGABRT);
100169719Skan	_exit(127);
101169719Skan}
102169719Skan
103169719Skanvoid
104169719Skan__stack_chk_fail(void)
105169719Skan{
106169719Skan	__fail("stack overflow detected; terminated");
107169719Skan}
108169719Skan
109169719Skanvoid
110169719Skan__chk_fail(void)
111169719Skan{
112169719Skan	__fail("buffer overflow detected; terminated");
113169719Skan}
114169719Skan
115211748Skib#ifndef PIC
116197277Skan__weak_reference(__stack_chk_fail, __stack_chk_fail_local);
117197277Skan#endif
118