1*6a59053bSAlex Wilson /*
2*6a59053bSAlex Wilson * This file and its contents are supplied under the terms of the
3*6a59053bSAlex Wilson * Common Development and Distribution License ("CDDL"), version 1.0.
4*6a59053bSAlex Wilson * You may only use this file in accordance with the terms of version
5*6a59053bSAlex Wilson * 1.0 of the CDDL.
6*6a59053bSAlex Wilson *
7*6a59053bSAlex Wilson * A full copy of the text of the CDDL should have accompanied this
8*6a59053bSAlex Wilson * source. A copy of the CDDL is also available via the Internet at
9*6a59053bSAlex Wilson * http://www.illumos.org/license/CDDL.
10*6a59053bSAlex Wilson */
11*6a59053bSAlex Wilson /*
12*6a59053bSAlex Wilson * Copyright 2015 Alex Wilson, the University of Queensland
13*6a59053bSAlex Wilson * Use is subject to license terms.
14*6a59053bSAlex Wilson */
15*6a59053bSAlex Wilson
16*6a59053bSAlex Wilson /*
17*6a59053bSAlex Wilson * Support functions for stack smashing protection (-fstack-protector
18*6a59053bSAlex Wilson * and family)
19*6a59053bSAlex Wilson *
20*6a59053bSAlex Wilson * The principle behind SSP is to place a "canary" value on the stack
21*6a59053bSAlex Wilson * just below the arguments to a given function (which are in turn
22*6a59053bSAlex Wilson * below the previous %rbp and return pointer). We write it onto the
23*6a59053bSAlex Wilson * stack at the start of a function, and then at the end just before
24*6a59053bSAlex Wilson * we execute "leave" and "ret", we check that the value is still there.
25*6a59053bSAlex Wilson *
26*6a59053bSAlex Wilson * If the check fails, we jump immediately to a handler (which typically
27*6a59053bSAlex Wilson * just executes panic() straight away).
28*6a59053bSAlex Wilson *
29*6a59053bSAlex Wilson * Since an attacker will not know the value of the "canary", they will
30*6a59053bSAlex Wilson * not be able to repair it correctly when overwriting the stack (and in
31*6a59053bSAlex Wilson * almost all cases they must overwrite the canary to get to the return
32*6a59053bSAlex Wilson * pointer), and the check will fail (and safely panic) instead of
33*6a59053bSAlex Wilson * letting them gain control over %rip in a kernel thread.
34*6a59053bSAlex Wilson *
35*6a59053bSAlex Wilson * To debugging tools the canary just looks like another local variable
36*6a59053bSAlex Wilson * (since it's placed below the normal argument space), and so there
37*6a59053bSAlex Wilson * should be minimal/no impact on things that try to parse the
38*6a59053bSAlex Wilson * function preamble.
39*6a59053bSAlex Wilson *
40*6a59053bSAlex Wilson * Of course, adding these guards to every single function does not come
41*6a59053bSAlex Wilson * without a price in performance, so normally only a subset of functions
42*6a59053bSAlex Wilson * in a given program are guarded. Selecting which subset, and adding the
43*6a59053bSAlex Wilson * guards is all handled automatically by the compiler.
44*6a59053bSAlex Wilson *
45*6a59053bSAlex Wilson * There are 3 (or 4) major relevant compiler options in GCC:
46*6a59053bSAlex Wilson * * -fstack-protector
47*6a59053bSAlex Wilson * * -fstack-protector-strong (only in GCC >= 4.9)
48*6a59053bSAlex Wilson * * -fstack-protector-all
49*6a59053bSAlex Wilson * * -fno-stack-protector
50*6a59053bSAlex Wilson *
51*6a59053bSAlex Wilson * The only differences between -fstack-protector, -strong and -all is in
52*6a59053bSAlex Wilson * which functions are selected for adding guards.
53*6a59053bSAlex Wilson *
54*6a59053bSAlex Wilson * -fstack-protector adds guards to functions that make use of a stack-
55*6a59053bSAlex Wilson * allocated char array (or aggregate containing one) of at least 8 bytes
56*6a59053bSAlex Wilson * in length.
57*6a59053bSAlex Wilson *
58*6a59053bSAlex Wilson * -fstack-protector-strong adds guards everywhere -fstack-protector
59*6a59053bSAlex Wilson * does, and also adds guards to all functions that take or pass an address
60*6a59053bSAlex Wilson * to a stack-allocated array of any type (eg arr, &arr[1] etc), as well as
61*6a59053bSAlex Wilson * functions containing certain kinds of pointer arithmetic.
62*6a59053bSAlex Wilson *
63*6a59053bSAlex Wilson * -fstack-protector-all (as the name suggests) adds guards to every single
64*6a59053bSAlex Wilson * function.
65*6a59053bSAlex Wilson *
66*6a59053bSAlex Wilson * There is also another variant, in the ProPolice patches which are used
67*6a59053bSAlex Wilson * by some members of the BSD family (eg OpenBSD), which also guards any
68*6a59053bSAlex Wilson * functions that store function pointers on the stack, as well as a few
69*6a59053bSAlex Wilson * other heuristics (like re-ordering variables so arrays are as close as
70*6a59053bSAlex Wilson * possible to the canary)
71*6a59053bSAlex Wilson */
72*6a59053bSAlex Wilson
73*6a59053bSAlex Wilson #include <sys/types.h>
74*6a59053bSAlex Wilson #include <sys/cmn_err.h>
75*6a59053bSAlex Wilson #include <sys/time.h>
76*6a59053bSAlex Wilson #include <sys/note.h>
77*6a59053bSAlex Wilson
78*6a59053bSAlex Wilson /*
79*6a59053bSAlex Wilson * The symbol __stack_chk_guard contains the magic guard value used
80*6a59053bSAlex Wilson * to check stack integrity before returning from selected functions.
81*6a59053bSAlex Wilson *
82*6a59053bSAlex Wilson * Its value is set at startup to a "random" number -- this does not have
83*6a59053bSAlex Wilson * to be cryptographically secure, but it does have to be done before
84*6a59053bSAlex Wilson * calling any C functions that the stack guards may have been generated
85*6a59053bSAlex Wilson * for.
86*6a59053bSAlex Wilson *
87*6a59053bSAlex Wilson * For this reason, the uts/i86pc/os directory is always built *without*
88*6a59053bSAlex Wilson * stack protection enabled so that we can bootstrap.
89*6a59053bSAlex Wilson */
90*6a59053bSAlex Wilson
91*6a59053bSAlex Wilson uintptr_t __stack_chk_guard = 0;
92*6a59053bSAlex Wilson
93*6a59053bSAlex Wilson /*
94*6a59053bSAlex Wilson * The function __stack_chk_fail is called whenever a guard check fails.
95*6a59053bSAlex Wilson */
96*6a59053bSAlex Wilson void
__stack_chk_fail(void)97*6a59053bSAlex Wilson __stack_chk_fail(void)
98*6a59053bSAlex Wilson {
99*6a59053bSAlex Wilson /*
100*6a59053bSAlex Wilson * Currently we just panic, but some more debug info could be useful.
101*6a59053bSAlex Wilson * Note that we absolutely cannot trust any part of our stack at this
102*6a59053bSAlex Wilson * point (we already know there's an attack in progress).
103*6a59053bSAlex Wilson */
104*6a59053bSAlex Wilson panic("Stack smashing detected");
105*6a59053bSAlex Wilson }
106*6a59053bSAlex Wilson
107*6a59053bSAlex Wilson static void salsa_hash(unsigned int *);
108*6a59053bSAlex Wilson
109*6a59053bSAlex Wilson #ifdef __sparc
110*6a59053bSAlex Wilson extern uint64_t ultra_gettick(void);
111*6a59053bSAlex Wilson #define SSP_GET_TICK ultra_gettick
112*6a59053bSAlex Wilson #else
113*6a59053bSAlex Wilson extern hrtime_t tsc_read(void);
114*6a59053bSAlex Wilson #define SSP_GET_TICK tsc_read
115*6a59053bSAlex Wilson #endif /* __sparc */
116*6a59053bSAlex Wilson
117*6a59053bSAlex Wilson /* called from os/startup.c */
118*6a59053bSAlex Wilson void
ssp_init(void)119*6a59053bSAlex Wilson ssp_init(void)
120*6a59053bSAlex Wilson {
121*6a59053bSAlex Wilson int i;
122*6a59053bSAlex Wilson
123*6a59053bSAlex Wilson if (__stack_chk_guard == 0) {
124*6a59053bSAlex Wilson union {
125*6a59053bSAlex Wilson unsigned int state[16];
126*6a59053bSAlex Wilson hrtime_t ts[8];
127*6a59053bSAlex Wilson uintptr_t g;
128*6a59053bSAlex Wilson } s;
129*6a59053bSAlex Wilson
130*6a59053bSAlex Wilson for (i = 0; i < 8; ++i)
131*6a59053bSAlex Wilson s.ts[i] = SSP_GET_TICK();
132*6a59053bSAlex Wilson
133*6a59053bSAlex Wilson salsa_hash(s.state);
134*6a59053bSAlex Wilson
135*6a59053bSAlex Wilson __stack_chk_guard = s.g;
136*6a59053bSAlex Wilson }
137*6a59053bSAlex Wilson }
138*6a59053bSAlex Wilson
139*6a59053bSAlex Wilson /*
140*6a59053bSAlex Wilson * Stealing the chacha/salsa hash function. It's simple, fast and
141*6a59053bSAlex Wilson * public domain. We don't need/want the full cipher (which would
142*6a59053bSAlex Wilson * belong in crypto) and we can't use the fully fledged PRNG
143*6a59053bSAlex Wilson * framework either, since ssp_init has to be called extremely
144*6a59053bSAlex Wilson * early in startup.
145*6a59053bSAlex Wilson *
146*6a59053bSAlex Wilson * Since we don't have to be cryptographically secure, just using
147*6a59053bSAlex Wilson * this to hash some high res timer values should be good enough.
148*6a59053bSAlex Wilson */
149*6a59053bSAlex Wilson #define QR(a, b, c, d) do { \
150*6a59053bSAlex Wilson a += b; d ^= a; d <<= 16; \
151*6a59053bSAlex Wilson c += d; b ^= c; b <<= 12; \
152*6a59053bSAlex Wilson a += b; d ^= a; d <<= 8; \
153*6a59053bSAlex Wilson c += d; b ^= c; b <<= 7; \
154*6a59053bSAlex Wilson _NOTE(CONSTANTCONDITION) \
155*6a59053bSAlex Wilson } while (0)
156*6a59053bSAlex Wilson
157*6a59053bSAlex Wilson static inline void
salsa_dr(unsigned int * state)158*6a59053bSAlex Wilson salsa_dr(unsigned int *state)
159*6a59053bSAlex Wilson {
160*6a59053bSAlex Wilson QR(state[0], state[4], state[ 8], state[12]);
161*6a59053bSAlex Wilson QR(state[1], state[5], state[ 9], state[13]);
162*6a59053bSAlex Wilson QR(state[2], state[6], state[10], state[14]);
163*6a59053bSAlex Wilson QR(state[3], state[7], state[11], state[15]);
164*6a59053bSAlex Wilson QR(state[0], state[5], state[10], state[15]);
165*6a59053bSAlex Wilson QR(state[1], state[6], state[11], state[12]);
166*6a59053bSAlex Wilson QR(state[2], state[7], state[ 8], state[13]);
167*6a59053bSAlex Wilson QR(state[3], state[4], state[ 9], state[14]);
168*6a59053bSAlex Wilson }
169*6a59053bSAlex Wilson
170*6a59053bSAlex Wilson static void
salsa_hash(unsigned int * state)171*6a59053bSAlex Wilson salsa_hash(unsigned int *state)
172*6a59053bSAlex Wilson {
173*6a59053bSAlex Wilson /* 10x applications of salsa doubleround */
174*6a59053bSAlex Wilson salsa_dr(state);
175*6a59053bSAlex Wilson salsa_dr(state);
176*6a59053bSAlex Wilson salsa_dr(state);
177*6a59053bSAlex Wilson salsa_dr(state);
178*6a59053bSAlex Wilson salsa_dr(state);
179*6a59053bSAlex Wilson salsa_dr(state);
180*6a59053bSAlex Wilson salsa_dr(state);
181*6a59053bSAlex Wilson salsa_dr(state);
182*6a59053bSAlex Wilson salsa_dr(state);
183*6a59053bSAlex Wilson salsa_dr(state);
184*6a59053bSAlex Wilson }
185