Skip to content

Commit 043f112

Browse files
committed
runtime: reset write barrier buffer on all flush paths
Currently, wbBufFlush does nothing if the goroutine is dying on the assumption that the system is crashing anyway and running the write barrier may crash it even more. However, it fails to reset the buffer's "next" pointer. As a result, if there are later write barriers on the same P, the write barrier will overflow the write barrier buffer and start corrupting other fields in the P or other heap objects. Often, this corrupts fields in the next allocated P since they tend to be together in the heap. Fix this by always resetting the buffer's "next" pointer, even if we're not doing anything with the pointers in the buffer. Updates #22987 and #22988. (May fix; it's hard to say.) Change-Id: I82c11ea2d399e1658531c3e8065445a66b7282b2 Reviewed-on: https://go-review.googlesource.com/83016 Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Rick Hudson <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]>
1 parent 3675bff commit 043f112

File tree

1 file changed

+14
-2
lines changed

1 file changed

+14
-2
lines changed

src/runtime/mwbbuf.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ func (b *wbBuf) reset() {
9595
}
9696
}
9797

98+
// discard resets b's next pointer, but not its end pointer.
99+
//
100+
// This must be nosplit because it's called by wbBufFlush.
101+
//
102+
//go:nosplit
103+
func (b *wbBuf) discard() {
104+
b.next = uintptr(unsafe.Pointer(&b.buf[0]))
105+
}
106+
98107
// putFast adds old and new to the write barrier buffer and returns
99108
// false if a flush is necessary. Callers should use this as:
100109
//
@@ -143,10 +152,14 @@ func (b *wbBuf) putFast(old, new uintptr) bool {
143152
//go:nowritebarrierrec
144153
//go:nosplit
145154
func wbBufFlush(dst *uintptr, src uintptr) {
155+
// Note: Every possible return from this function must reset
156+
// the buffer's next pointer to prevent buffer overflow.
157+
146158
if getg().m.dying > 0 {
147159
// We're going down. Not much point in write barriers
148160
// and this way we can allow write barriers in the
149161
// panic path.
162+
getg().m.p.ptr().wbBuf.discard()
150163
return
151164
}
152165

@@ -156,8 +169,7 @@ func wbBufFlush(dst *uintptr, src uintptr) {
156169
cgoCheckWriteBarrier(dst, src)
157170
if !writeBarrier.needed {
158171
// We were only called for cgocheck.
159-
b := &getg().m.p.ptr().wbBuf
160-
b.next = uintptr(unsafe.Pointer(&b.buf[0]))
172+
getg().m.p.ptr().wbBuf.discard()
161173
return
162174
}
163175
}

0 commit comments

Comments
 (0)