From 371a5b494a7a0cb246a86e849b66ed022ef30c74 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Martin=20M=C3=B6hrmann?= Date: Sat, 12 Aug 2017 17:37:13 +0200 Subject: [PATCH] runtime: protect growslice against newcap*et.size overflow MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The check of uintptr(newcap) > maxSliceCap(et.size) in addition to capmem > _MaxMem is needed to prevent a reproducible overflow on 32bit architectures. On 64bit platforms this problem is less likely to occur as allocation of a sufficiently large array or slice to be append is likely to already exhaust available memory before the call to append can be made. Example program that without the fix in this CL does segfault on 386: type T [1<<27 + 1]int64 var d T var s []T func main() { s = append(s, d, d, d, d) print(len(s), "\n") } Fixes #21586 Change-Id: Ib4185435826ef43df71ba0f789e19f5bf9a347e6 Reviewed-on: https://go-review.googlesource.com/55133 Run-TryBot: Martin Möhrmann TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/slice.go | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/runtime/slice.go b/src/runtime/slice.go index f79aa02c3b..351fec067d 100644 --- a/src/runtime/slice.go +++ b/src/runtime/slice.go @@ -125,6 +125,7 @@ func growslice(et *_type, old slice, cap int) slice { } } + var overflow bool var lenmem, newlenmem, capmem uintptr const ptrSize = unsafe.Sizeof((*byte)(nil)) switch et.size { @@ -132,20 +133,37 @@ func growslice(et *_type, old slice, cap int) slice { lenmem = uintptr(old.len) newlenmem = uintptr(cap) capmem = roundupsize(uintptr(newcap)) + overflow = uintptr(newcap) > _MaxMem newcap = int(capmem) case ptrSize: lenmem = uintptr(old.len) * ptrSize newlenmem = uintptr(cap) * ptrSize capmem = roundupsize(uintptr(newcap) * ptrSize) + overflow = uintptr(newcap) > _MaxMem/ptrSize newcap = int(capmem / ptrSize) default: lenmem = uintptr(old.len) * et.size newlenmem = uintptr(cap) * et.size capmem = roundupsize(uintptr(newcap) * et.size) + overflow = uintptr(newcap) > maxSliceCap(et.size) newcap = int(capmem / et.size) } - if cap < old.cap || capmem > _MaxMem { + // The check of overflow (uintptr(newcap) > maxSliceCap(et.size)) + // in addition to capmem > _MaxMem is needed to prevent an overflow + // which can be used to trigger a segfault on 32bit architectures + // with this example program: + // + // type T [1<<27 + 1]int64 + // + // var d T + // var s []T + // + // func main() { + // s = append(s, d, d, d, d) + // print(len(s), "\n") + // } + if cap < old.cap || overflow || capmem > _MaxMem { panic(errorString("growslice: cap out of range")) } -- 2.48.1