1
2
3
4
5
6
7
8
9
10
11
12
13
14 package secret
15
16 import (
17 "runtime"
18 "strings"
19 "testing"
20 "time"
21 "unsafe"
22 )
23
24 type secretType int64
25
26 const secretValue = 0x53c237_53c237
27
28
29 type S [100]secretType
30
31
32
33
34 func makeS() S {
35
36
37 var s S
38 for i := range s {
39 s[i] = secretValue
40 }
41 return s
42 }
43
44
45
46
47 func heapS() *S {
48
49 s := makeS()
50 return &s
51 }
52
53
54
55
56 func heapSTiny() *secretType {
57 s := new(secretType(secretValue))
58 return s
59 }
60
61
62
63
64
65 func TestHeap(t *testing.T) {
66 var u uintptr
67 Do(func() {
68 u = uintptr(unsafe.Pointer(heapS()))
69 })
70
71 runtime.GC()
72
73
74 checkRangeForSecret(t, u, u+unsafe.Sizeof(S{}))
75
76 checkStackForSecret(t)
77 }
78
79 func TestHeapTiny(t *testing.T) {
80 var u uintptr
81 Do(func() {
82 u = uintptr(unsafe.Pointer(heapSTiny()))
83 })
84 runtime.GC()
85
86
87 checkRangeForSecret(t, u, u+unsafe.Sizeof(secretType(0)))
88
89 checkStackForSecret(t)
90 }
91
92
93
94
95 func TestStack(t *testing.T) {
96 checkStackForSecret(t)
97
98 Do(func() {
99 s := makeS()
100 use(&s)
101 })
102
103 checkStackForSecret(t)
104 }
105
106
107 func use(s *S) {
108
109 }
110
111
112
113 func TestStackCopy(t *testing.T) {
114 checkStackForSecret(t)
115
116 var lo, hi uintptr
117 Do(func() {
118
119 s := makeS()
120 use(&s)
121
122 lo, hi = getStack()
123
124 growStack()
125 })
126 checkRangeForSecret(t, lo, hi)
127 checkStackForSecret(t)
128 }
129
130 func growStack() {
131 growStack1(1000)
132 }
133 func growStack1(n int) {
134 if n == 0 {
135 return
136 }
137 growStack1(n - 1)
138 }
139
140 func TestPanic(t *testing.T) {
141 checkStackForSecret(t)
142
143 defer func() {
144 checkStackForSecret(t)
145
146 p := recover()
147 if p == nil {
148 t.Errorf("panic squashed")
149 return
150 }
151 var e error
152 var ok bool
153 if e, ok = p.(error); !ok {
154 t.Errorf("panic not an error")
155 }
156 if !strings.Contains(e.Error(), "divide by zero") {
157 t.Errorf("panic not a divide by zero error: %s", e.Error())
158 }
159 var pcs [10]uintptr
160 n := runtime.Callers(0, pcs[:])
161 frames := runtime.CallersFrames(pcs[:n])
162 for {
163 frame, more := frames.Next()
164 if strings.Contains(frame.Function, "dividePanic") {
165 t.Errorf("secret function in traceback")
166 }
167 if !more {
168 break
169 }
170 }
171 }()
172 Do(dividePanic)
173 }
174
175 func dividePanic() {
176 s := makeS()
177 use(&s)
178 _ = 8 / zero
179 }
180
181 var zero int
182
183 func TestGoExit(t *testing.T) {
184 checkStackForSecret(t)
185
186 c := make(chan uintptr, 2)
187
188 go func() {
189
190 defer func() {
191
192
193 lo, hi := getStack()
194 c <- lo
195 c <- hi
196 }()
197 Do(func() {
198 s := makeS()
199 use(&s)
200
201
202
203 loadRegisters(unsafe.Pointer(&s))
204 runtime.Goexit()
205 })
206 t.Errorf("goexit didn't happen")
207 }()
208 lo := <-c
209 hi := <-c
210
211
212 time.Sleep(1 * time.Millisecond)
213
214 checkRangeForSecret(t, lo, hi)
215
216 var spillArea [64]secretType
217 n := spillRegisters(unsafe.Pointer(&spillArea))
218 if n > unsafe.Sizeof(spillArea) {
219 t.Fatalf("spill area overrun %d\n", n)
220 }
221 for i, v := range spillArea {
222 if v == secretValue {
223 t.Errorf("secret found in spill slot %d", i)
224 }
225 }
226 }
227
228 func checkStackForSecret(t *testing.T) {
229 t.Helper()
230 lo, hi := getStack()
231 checkRangeForSecret(t, lo, hi)
232 }
233 func checkRangeForSecret(t *testing.T, lo, hi uintptr) {
234 t.Helper()
235 for p := lo; p < hi; p += unsafe.Sizeof(secretType(0)) {
236 v := *(*secretType)(unsafe.Pointer(p))
237 if v == secretValue {
238 t.Errorf("secret found in [%x,%x] at %x", lo, hi, p)
239 }
240 }
241 }
242
243 func TestRegisters(t *testing.T) {
244 Do(func() {
245 s := makeS()
246 loadRegisters(unsafe.Pointer(&s))
247 })
248 var spillArea [64]secretType
249 n := spillRegisters(unsafe.Pointer(&spillArea))
250 if n > unsafe.Sizeof(spillArea) {
251 t.Fatalf("spill area overrun %d\n", n)
252 }
253 for i, v := range spillArea {
254 if v == secretValue {
255 t.Errorf("secret found in spill slot %d", i)
256 }
257 }
258 }
259
260 func TestSignalStacks(t *testing.T) {
261 Do(func() {
262 s := makeS()
263 loadRegisters(unsafe.Pointer(&s))
264
265
266 func() {
267 defer func() {
268 x := recover()
269 if x == nil {
270 panic("did not get panic")
271 }
272 }()
273 var p *int
274 *p = 20
275 }()
276 })
277
278
279 runtime.GC()
280 stk := make([]stack, 0, 100)
281 stk = appendSignalStacks(stk)
282 for _, s := range stk {
283 checkRangeForSecret(t, s.lo, s.hi)
284 }
285 }
286
287
288 func getStack() (uintptr, uintptr)
289
290
291
292 type stack struct {
293 lo uintptr
294 hi uintptr
295 }
296
297 func appendSignalStacks([]stack) []stack
298
View as plain text