Skip to content

Commit 6f327f7

Browse files
zhangfannieianlancetaylor
authored andcommitted
runtime, syscall: add calls to asan functions
Add explicit address sanitizer instrumentation to the runtime and syscall packages. The compiler does not instrument the runtime package. It does instrument the syscall package, but we need to add a couple of cases that it can't see. Refer to the implementation of the asan malloc runtime library, this patch also allocates extra memory as the redzone, around the returned memory region, and marks the redzone as unaddressable to detect the overflows or underflows. Updates #44853. Change-Id: I2753d1cc1296935a66bf521e31ce91e35fcdf798 Reviewed-on: https://go-review.googlesource.com/c/go/+/298614 Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Trust: fannie zhang <[email protected]>
1 parent 6f1e9a9 commit 6f327f7

18 files changed

+200
-3
lines changed

src/runtime/cgo_sigaction.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ func sigaction(sig uint32, new, old *sigactiont) {
2727
if msanenabled && new != nil {
2828
msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
2929
}
30-
30+
if asanenabled && new != nil {
31+
asanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
32+
}
3133
if _cgo_sigaction == nil || inForkedChild {
3234
sysSigaction(sig, new, old)
3335
} else {
@@ -79,6 +81,9 @@ func sigaction(sig uint32, new, old *sigactiont) {
7981
if msanenabled && old != nil {
8082
msanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
8183
}
84+
if asanenabled && old != nil {
85+
asanread(unsafe.Pointer(old), unsafe.Sizeof(*old))
86+
}
8287
}
8388

8489
// callCgoSigaction calls the sigaction function in the runtime/cgo package

src/runtime/iface.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,9 @@ func convT(t *_type, v unsafe.Pointer) unsafe.Pointer {
325325
if msanenabled {
326326
msanread(v, t.size)
327327
}
328+
if asanenabled {
329+
asanread(v, t.size)
330+
}
328331
x := mallocgc(t.size, t, true)
329332
typedmemmove(t, x, v)
330333
return x
@@ -337,6 +340,10 @@ func convTnoptr(t *_type, v unsafe.Pointer) unsafe.Pointer {
337340
if msanenabled {
338341
msanread(v, t.size)
339342
}
343+
if asanenabled {
344+
asanread(v, t.size)
345+
}
346+
340347
x := mallocgc(t.size, t, false)
341348
memmove(x, v, t.size)
342349
return x

src/runtime/malloc.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,14 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
908908
if size == 0 {
909909
return unsafe.Pointer(&zerobase)
910910
}
911+
userSize := size
912+
if asanenabled {
913+
// Refer to ASAN runtime library, the malloc() function allocates extra memory,
914+
// the redzone, around the user requested memory region. And the redzones are marked
915+
// as unaddressable. We perform the same operations in Go to detect the overflows or
916+
// underflows.
917+
size += computeRZlog(size)
918+
}
911919

912920
if debug.malloc {
913921
if debug.sbrk != 0 {
@@ -971,7 +979,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
971979
mp.mallocing = 1
972980

973981
shouldhelpgc := false
974-
dataSize := size
982+
dataSize := userSize
975983
c := getMCache(mp)
976984
if c == nil {
977985
throw("mallocgc called without a P or outside bootstrapping")
@@ -1138,6 +1146,17 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
11381146
msanmalloc(x, size)
11391147
}
11401148

1149+
if asanenabled {
1150+
// We should only read/write the memory with the size asked by the user.
1151+
// The rest of the allocated memory should be poisoned, so that we can report
1152+
// errors when accessing poisoned memory.
1153+
// The allocated memory is larger than required userSize, it will also include
1154+
// redzone and some other padding bytes.
1155+
rzBeg := unsafe.Add(x, userSize)
1156+
asanpoison(rzBeg, size-userSize)
1157+
asanunpoison(x, userSize)
1158+
}
1159+
11411160
if rate := MemProfileRate; rate > 0 {
11421161
// Note cache c only valid while m acquired; see #47302
11431162
if rate != 1 && size < c.nextSample {
@@ -1514,3 +1533,26 @@ type notInHeap struct{}
15141533
func (p *notInHeap) add(bytes uintptr) *notInHeap {
15151534
return (*notInHeap)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + bytes))
15161535
}
1536+
1537+
// computeRZlog computes the size of the redzone.
1538+
// Refer to the implementation of the compiler-rt.
1539+
func computeRZlog(userSize uintptr) uintptr {
1540+
switch {
1541+
case userSize <= (64 - 16):
1542+
return 16 << 0
1543+
case userSize <= (128 - 32):
1544+
return 16 << 1
1545+
case userSize <= (512 - 64):
1546+
return 16 << 2
1547+
case userSize <= (4096 - 128):
1548+
return 16 << 3
1549+
case userSize <= (1<<14)-256:
1550+
return 16 << 4
1551+
case userSize <= (1<<15)-512:
1552+
return 16 << 5
1553+
case userSize <= (1<<16)-1024:
1554+
return 16 << 6
1555+
default:
1556+
return 16 << 7
1557+
}
1558+
}

src/runtime/map.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
402402
if msanenabled && h != nil {
403403
msanread(key, t.key.size)
404404
}
405+
if asanenabled && h != nil {
406+
asanread(key, t.key.size)
407+
}
405408
if h == nil || h.count == 0 {
406409
if t.hashMightPanic() {
407410
t.hasher(key, 0) // see issue 23734
@@ -460,6 +463,9 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
460463
if msanenabled && h != nil {
461464
msanread(key, t.key.size)
462465
}
466+
if asanenabled && h != nil {
467+
asanread(key, t.key.size)
468+
}
463469
if h == nil || h.count == 0 {
464470
if t.hashMightPanic() {
465471
t.hasher(key, 0) // see issue 23734
@@ -582,6 +588,9 @@ func mapassign(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
582588
if msanenabled {
583589
msanread(key, t.key.size)
584590
}
591+
if asanenabled {
592+
asanread(key, t.key.size)
593+
}
585594
if h.flags&hashWriting != 0 {
586595
throw("concurrent map writes")
587596
}
@@ -693,6 +702,9 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
693702
if msanenabled && h != nil {
694703
msanread(key, t.key.size)
695704
}
705+
if asanenabled && h != nil {
706+
asanread(key, t.key.size)
707+
}
696708
if h == nil || h.count == 0 {
697709
if t.hashMightPanic() {
698710
t.hasher(key, 0) // see issue 23734

src/runtime/mbarrier.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
184184
msanwrite(dst, typ.size)
185185
msanread(src, typ.size)
186186
}
187+
if asanenabled {
188+
asanwrite(dst, typ.size)
189+
asanread(src, typ.size)
190+
}
187191
typedmemmove(typ, dst, src)
188192
}
189193

@@ -262,6 +266,10 @@ func typedslicecopy(typ *_type, dstPtr unsafe.Pointer, dstLen int, srcPtr unsafe
262266
msanwrite(dstPtr, uintptr(n)*typ.size)
263267
msanread(srcPtr, uintptr(n)*typ.size)
264268
}
269+
if asanenabled {
270+
asanwrite(dstPtr, uintptr(n)*typ.size)
271+
asanread(srcPtr, uintptr(n)*typ.size)
272+
}
265273

266274
if writeBarrier.cgo {
267275
cgoCheckSliceCopy(typ, dstPtr, srcPtr, n)

src/runtime/mgcsweep.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
563563
spanHasNoSpecials(s)
564564
}
565565

566-
if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled {
566+
if debug.allocfreetrace != 0 || debug.clobberfree != 0 || raceenabled || msanenabled || asanenabled {
567567
// Find all newly freed objects. This doesn't have to
568568
// efficient; allocfreetrace has massive overhead.
569569
mbits := s.markBitsForBase()
@@ -583,6 +583,9 @@ func (sl *sweepLocked) sweep(preserve bool) bool {
583583
if msanenabled {
584584
msanfree(unsafe.Pointer(x), size)
585585
}
586+
if asanenabled {
587+
asanpoison(unsafe.Pointer(x), size)
588+
}
586589
}
587590
mbits.advance()
588591
abits.advance()

src/runtime/mheap.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,6 +1419,12 @@ func (h *mheap) freeSpan(s *mspan) {
14191419
bytes := s.npages << _PageShift
14201420
msanfree(base, bytes)
14211421
}
1422+
if asanenabled {
1423+
// Tell asan that this entire span is no longer in use.
1424+
base := unsafe.Pointer(s.base())
1425+
bytes := s.npages << _PageShift
1426+
asanpoison(base, bytes)
1427+
}
14221428
h.freeSpanLocked(s, spanAllocHeap)
14231429
unlock(&h.lock)
14241430
})

src/runtime/mprof.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,9 @@ func record(r *MemProfileRecord, b *bucket) {
627627
if msanenabled {
628628
msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
629629
}
630+
if asanenabled {
631+
asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
632+
}
630633
copy(r.Stack0[:], b.stk())
631634
for i := int(b.nstk); i < len(r.Stack0); i++ {
632635
r.Stack0[i] = 0
@@ -680,6 +683,9 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool) {
680683
if msanenabled {
681684
msanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
682685
}
686+
if asanenabled {
687+
asanwrite(unsafe.Pointer(&r.Stack0[0]), unsafe.Sizeof(r.Stack0))
688+
}
683689
i := copy(r.Stack0[:], b.stk())
684690
for ; i < len(r.Stack0); i++ {
685691
r.Stack0[i] = 0

src/runtime/proc.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2233,6 +2233,9 @@ func newm1(mp *m) {
22332233
if msanenabled {
22342234
msanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
22352235
}
2236+
if asanenabled {
2237+
asanwrite(unsafe.Pointer(&ts), unsafe.Sizeof(ts))
2238+
}
22362239
execLock.rlock() // Prevent process clone.
22372240
asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
22382241
execLock.runlock()
@@ -4435,6 +4438,9 @@ retry:
44354438
if msanenabled {
44364439
msanmalloc(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
44374440
}
4441+
if asanenabled {
4442+
asanunpoison(unsafe.Pointer(gp.stack.lo), gp.stack.hi-gp.stack.lo)
4443+
}
44384444
}
44394445
return gp
44404446
}

src/runtime/select.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,13 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
406406
msanwrite(cas.elem, c.elemtype.size)
407407
}
408408
}
409+
if asanenabled {
410+
if casi < nsends {
411+
asanread(cas.elem, c.elemtype.size)
412+
} else if cas.elem != nil {
413+
asanwrite(cas.elem, c.elemtype.size)
414+
}
415+
}
409416

410417
selunlock(scases, lockorder)
411418
goto retc
@@ -421,6 +428,9 @@ bufrecv:
421428
if msanenabled && cas.elem != nil {
422429
msanwrite(cas.elem, c.elemtype.size)
423430
}
431+
if asanenabled && cas.elem != nil {
432+
asanwrite(cas.elem, c.elemtype.size)
433+
}
424434
recvOK = true
425435
qp = chanbuf(c, c.recvx)
426436
if cas.elem != nil {
@@ -444,6 +454,9 @@ bufsend:
444454
if msanenabled {
445455
msanread(cas.elem, c.elemtype.size)
446456
}
457+
if asanenabled {
458+
asanread(cas.elem, c.elemtype.size)
459+
}
447460
typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
448461
c.sendx++
449462
if c.sendx == c.dataqsiz {
@@ -482,6 +495,9 @@ send:
482495
if msanenabled {
483496
msanread(cas.elem, c.elemtype.size)
484497
}
498+
if asanenabled {
499+
asanread(cas.elem, c.elemtype.size)
500+
}
485501
send(c, sg, cas.elem, func() { selunlock(scases, lockorder) }, 2)
486502
if debugSelect {
487503
print("syncsend: cas0=", cas0, " c=", c, "\n")

src/runtime/slice.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsaf
7676
if msanenabled {
7777
msanread(from, copymem)
7878
}
79+
if asanenabled {
80+
asanread(from, copymem)
81+
}
7982

8083
memmove(to, from, copymem)
8184

@@ -168,6 +171,9 @@ func growslice(et *_type, old slice, cap int) slice {
168171
if msanenabled {
169172
msanread(old.array, uintptr(old.len*int(et.size)))
170173
}
174+
if asanenabled {
175+
asanread(old.array, uintptr(old.len*int(et.size)))
176+
}
171177

172178
if cap < old.cap {
173179
panic(errorString("growslice: cap out of range"))
@@ -311,6 +317,10 @@ func slicecopy(toPtr unsafe.Pointer, toLen int, fromPtr unsafe.Pointer, fromLen
311317
msanread(fromPtr, size)
312318
msanwrite(toPtr, size)
313319
}
320+
if asanenabled {
321+
asanread(fromPtr, size)
322+
asanwrite(toPtr, size)
323+
}
314324

315325
if size == 1 { // common case worth about 2x to do here
316326
// TODO: is this still worth it with new memmove impl?

src/runtime/stack.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,9 @@ func stackalloc(n uint32) stack {
424424
if msanenabled {
425425
msanmalloc(v, uintptr(n))
426426
}
427+
if asanenabled {
428+
asanunpoison(v, uintptr(n))
429+
}
427430
if stackDebug >= 1 {
428431
print(" allocated ", v, "\n")
429432
}
@@ -461,6 +464,9 @@ func stackfree(stk stack) {
461464
if msanenabled {
462465
msanfree(v, n)
463466
}
467+
if asanenabled {
468+
asanpoison(v, n)
469+
}
464470
if n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
465471
order := uint8(0)
466472
n2 := n

src/runtime/string.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ func slicebytetostring(buf *tmpBuf, ptr *byte, n int) (str string) {
9494
if msanenabled {
9595
msanread(unsafe.Pointer(ptr), uintptr(n))
9696
}
97+
if asanenabled {
98+
asanread(unsafe.Pointer(ptr), uintptr(n))
99+
}
97100
if n == 1 {
98101
p := unsafe.Pointer(&staticuint64s[*ptr])
99102
if goarch.BigEndian {
@@ -158,6 +161,9 @@ func slicebytetostringtmp(ptr *byte, n int) (str string) {
158161
if msanenabled && n > 0 {
159162
msanread(unsafe.Pointer(ptr), uintptr(n))
160163
}
164+
if asanenabled && n > 0 {
165+
asanread(unsafe.Pointer(ptr), uintptr(n))
166+
}
161167
stringStructOf(&str).str = unsafe.Pointer(ptr)
162168
stringStructOf(&str).len = n
163169
return
@@ -209,6 +215,9 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
209215
if msanenabled && len(a) > 0 {
210216
msanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
211217
}
218+
if asanenabled && len(a) > 0 {
219+
asanread(unsafe.Pointer(&a[0]), uintptr(len(a))*unsafe.Sizeof(a[0]))
220+
}
212221
var dum [4]byte
213222
size1 := 0
214223
for _, r := range a {

src/runtime/traceback.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,9 @@ func callCgoSymbolizer(arg *cgoSymbolizerArg) {
13901390
if msanenabled {
13911391
msanwrite(unsafe.Pointer(arg), unsafe.Sizeof(cgoSymbolizerArg{}))
13921392
}
1393+
if asanenabled {
1394+
asanwrite(unsafe.Pointer(arg), unsafe.Sizeof(cgoSymbolizerArg{}))
1395+
}
13931396
call(cgoSymbolizer, noescape(unsafe.Pointer(arg)))
13941397
}
13951398

@@ -1412,5 +1415,8 @@ func cgoContextPCs(ctxt uintptr, buf []uintptr) {
14121415
if msanenabled {
14131416
msanwrite(unsafe.Pointer(&arg), unsafe.Sizeof(arg))
14141417
}
1418+
if asanenabled {
1419+
asanwrite(unsafe.Pointer(&arg), unsafe.Sizeof(arg))
1420+
}
14151421
call(cgoTraceback, noescape(unsafe.Pointer(&arg)))
14161422
}

0 commit comments

Comments
 (0)