1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Oxide Computer Company
14 */
15
16 #include <upanic.h>
17 #include <sys/random.h>
18
19 /*
20 * This provides an implementation of the stack protector functions that are
21 * expected by gcc's ssp implementation.
22 *
23 * We attempt to initialize the stack guard with random data, which is our best
24 * protection. If that fails, we'd like to have a guard that is still meaningful
25 * and not totally predictable. The original StackGuard paper suggests using a
26 * terminator canary. To make this a little more difficult, we also use a
27 * portion of the data from gethrtime().
28 *
29 * In a 32-bit environment, we only have four bytes worth of data. We use the
30 * lower two bytes of the gethrtime() value and then use pieces of the
31 * terminator canary, '\n\0'. In a 64-bit environment we use the full four byte
32 * terminator canary and then four bytes of gethrtime.
33 */
34
35 /*
36 * Use an array here so it's easier to get the length at compile time.
37 */
38 static const char ssp_msg[] = "*** stack smashing detected";
39
40 uintptr_t __stack_chk_guard;
41
42 void
ssp_init(void)43 ssp_init(void)
44 {
45 if (getrandom(&__stack_chk_guard, sizeof (__stack_chk_guard), 0) !=
46 sizeof (__stack_chk_guard)) {
47 /*
48 * This failed, attempt to get some data that might let us get
49 * off the ground.
50 */
51 hrtime_t t = gethrtime();
52 #ifdef _LP32
53 const uint16_t guard = '\n' << 8 | '\0';
54 __stack_chk_guard = guard << 16 | (uint16_t)t;
55 #else
56 const uint32_t guard = '\r' << 24 | '\n' << 16 | '\0' << 8 |
57 '\xff';
58 __stack_chk_guard = (uint64_t)guard << 32 | (uint32_t)t;
59 #endif
60 }
61 }
62
63 void
__stack_chk_fail(void)64 __stack_chk_fail(void)
65 {
66 upanic(ssp_msg, sizeof (ssp_msg));
67 }
68