diff mbox series

[v1,01/10] ssp: add APIs for Stack Smashing Protection (-fstack-protector*)

Message ID 20171101045246.16596-2-yselkowi@redhat.com
State New
Headers show
Series Add Stack Smashing Protection and Object Size Checking | expand

Commit Message

Yaakov Selkowitz Nov. 1, 2017, 4:52 a.m. UTC
Compiling with any of the -fstack-protector flags requires the
__stack_chk_guard data import (which needs to be initialized) and the
__stack_chk_fail{,_local} functions.  While GCC's own libssp can provide
these, it is better that we provide these ourselves.  The header is from
NetBSD but the implementation is custom due to NetBSD's implementation
being OS-specific.

Signed-off-by: Yaakov Selkowitz <yselkowi@redhat.com>

---
 newlib/libc/include/ssp/ssp.h     | 93 +++++++++++++++++++++++++++++++++++++++
 newlib/libc/ssp/stack_protector.c | 46 +++++++++++++++++++
 2 files changed, 139 insertions(+)
 create mode 100644 newlib/libc/include/ssp/ssp.h
 create mode 100644 newlib/libc/ssp/stack_protector.c

-- 
2.14.3
diff mbox series

Patch

diff --git a/newlib/libc/include/ssp/ssp.h b/newlib/libc/include/ssp/ssp.h
new file mode 100644
index 000000000..14409c1ec
--- /dev/null
+++ b/newlib/libc/include/ssp/ssp.h
@@ -0,0 +1,93 @@ 
+/*	$NetBSD: ssp.h,v 1.13 2015/09/03 20:43:47 plunky Exp $	*/
+
+/*-
+ * Copyright (c) 2006, 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _SSP_SSP_H_
+#define _SSP_SSP_H_
+
+#include <sys/cdefs.h>
+
+#ifndef __RENAME
+#define __RENAME(__f) __asm__(__ASMNAME (#__f))
+#endif
+
+#if !defined(__cplusplus)
+# if _FORTIFY_SOURCE > 0 && !defined(__lint__) && \
+     (__OPTIMIZE__ > 0 || defined(__clang__)) && __GNUC_PREREQ__(4, 1)
+#  if _FORTIFY_SOURCE > 1
+#   define __SSP_FORTIFY_LEVEL 2
+#  else
+#   define __SSP_FORTIFY_LEVEL 1
+#  endif
+# else
+#  define __SSP_FORTIFY_LEVEL 0
+# endif
+#else
+# define __SSP_FORTIFY_LEVEL 0
+#endif
+
+/* __ssp_real is used by the implementation in libc */
+#if __SSP_FORTIFY_LEVEL == 0
+#define __ssp_real_(fun)	fun
+#else
+#define __ssp_real_(fun)	__ssp_real_ ## fun
+#endif
+#define __ssp_real(fun)		__ssp_real_(fun)
+
+#define __ssp_inline static __inline __attribute__((__always_inline__))
+
+#define __ssp_bos(ptr) __builtin_object_size(ptr, __SSP_FORTIFY_LEVEL > 1)
+#define __ssp_bos0(ptr) __builtin_object_size(ptr, 0)
+
+#define __ssp_check(buf, len, bos) \
+	if (bos(buf) != (size_t)-1 && len > bos(buf)) \
+		__chk_fail()
+#define __ssp_redirect_raw(rtype, fun, symbol, args, call, cond, bos) \
+rtype __ssp_real_(fun) args __RENAME(symbol); \
+__ssp_inline rtype fun args __RENAME(__ssp_protected_ ## fun); \
+__ssp_inline rtype fun args { \
+	if (cond) \
+		__ssp_check(__buf, __len, bos); \
+	return __ssp_real_(fun) call; \
+}
+
+#define __ssp_redirect(rtype, fun, args, call) \
+    __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos)
+#define __ssp_redirect0(rtype, fun, args, call) \
+    __ssp_redirect_raw(rtype, fun, fun, args, call, 1, __ssp_bos0)
+
+#define __ssp_overlap(a, b, l) \
+    (((a) <= (b) && (b) < (a) + (l)) || ((b) <= (a) && (a) < (b) + (l)))
+
+__BEGIN_DECLS
+void __stack_chk_fail(void) __dead2;
+void __chk_fail(void) __dead2;
+__END_DECLS
+
+#endif /* _SSP_SSP_H_ */
diff --git a/newlib/libc/ssp/stack_protector.c b/newlib/libc/ssp/stack_protector.c
new file mode 100644
index 000000000..608f79753
--- /dev/null
+++ b/newlib/libc/ssp/stack_protector.c
@@ -0,0 +1,46 @@ 
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <ssp/ssp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+uintptr_t __stack_chk_guard = 0;
+
+void
+__attribute__((__constructor__))
+__stack_chk_init (void)
+{
+  if (__stack_chk_guard != 0)
+    return;
+
+#if defined(__CYGWIN__) || defined(__rtems__)
+  arc4random_buf(&__stack_chk_guard, sizeof(__stack_chk_guard));
+#else
+  /* If getentropy is not available, use the "terminator canary". */
+  ((unsigned char *)&__stack_chk_guard)[0] = 0;
+  ((unsigned char *)&__stack_chk_guard)[1] = 0;
+  ((unsigned char *)&__stack_chk_guard)[2] = '\n';
+  ((unsigned char *)&__stack_chk_guard)[3] = 255;
+#endif
+}
+
+void
+__attribute__((__noreturn__))
+__stack_chk_fail (void)
+{
+  char msg[] = "*** stack smashing detected ***: terminated\n";
+  write (2, msg, strlen (msg));
+  raise (SIGABRT);
+  _exit (127);
+}
+
+#ifdef __ELF__
+void
+__attribute__((visibility ("hidden")))
+__stack_chk_fail_local(void)
+{
+	__stack_chk_fail();
+}
+#endif