diff --git a/src/runtime/defs_openbsd_386.h b/src/runtime/defs_openbsd_386.h index 6b77e0084a..c4b43ae2c8 100644 --- a/src/runtime/defs_openbsd_386.h +++ b/src/runtime/defs_openbsd_386.h @@ -14,6 +14,7 @@ enum { MAP_ANON = 0x1000, MAP_PRIVATE = 0x2, MAP_FIXED = 0x10, + MAP_STACK = 0x4000, MADV_FREE = 0x6, diff --git a/src/runtime/defs_openbsd_amd64.h b/src/runtime/defs_openbsd_amd64.h index 761e8e47df..263bfeb992 100644 --- a/src/runtime/defs_openbsd_amd64.h +++ b/src/runtime/defs_openbsd_amd64.h @@ -14,6 +14,7 @@ enum { MAP_ANON = 0x1000, MAP_PRIVATE = 0x2, MAP_FIXED = 0x10, + MAP_STACK = 0x4000, MADV_FREE = 0x6, diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h index adb8d3d677..f19751a0c5 100644 --- a/src/runtime/malloc.h +++ b/src/runtime/malloc.h @@ -197,6 +197,8 @@ struct MLink // if accessed. Used only for debugging the runtime. void* runtime·sysAlloc(uintptr nbytes, uint64 *stat); +void runtime·sysMarkStack(void *v, uintptr nbytes); +void runtime·sysUnmarkStack(void *v, uintptr nbytes); void runtime·SysFree(void *v, uintptr nbytes, uint64 *stat); void runtime·SysUnused(void *v, uintptr nbytes); void runtime·SysUsed(void *v, uintptr nbytes); diff --git a/src/runtime/mem_openbsd.c b/src/runtime/mem_openbsd.c index 31820e5170..ac3a2a565a 100644 --- a/src/runtime/mem_openbsd.c +++ b/src/runtime/mem_openbsd.c @@ -27,6 +27,29 @@ runtime·sysAlloc(uintptr n, uint64 *stat) return v; } +#pragma textflag NOSPLIT +void +runtime·sysMarkStack(void *v, uintptr n) +{ + void *p; + + // Stack regions on OpenBSD 6.4+ must be marked with MAP_STACK. + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_FIXED|MAP_STACK, -1, 0); + if (p == ((void *)-1) || p != v) + runtime·throw("runtime: failed to mark stack"); +} + +#pragma textflag NOSPLIT +void +runtime·sysUnmarkStack(void *v, uintptr n) +{ + void *p; + + p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); + if (p == ((void *)-1) || p != v) + runtime·throw("runtime: failed to unmark stack"); +} + void runtime·SysUnused(void *v, uintptr n) { diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c index eebaa13eea..e5484d993f 100644 --- a/src/runtime/os_openbsd.c +++ b/src/runtime/os_openbsd.c @@ -167,7 +167,10 @@ runtime·newosproc(M *mp, void *stk) param.tf_tcb = (byte*)&mp->tls[0]; param.tf_tid = (int32*)&mp->procid; - param.tf_stack = stk; + + // Stack pointer must point inside stack area (as marked with MAP_STACK), + // rather than at the top of it. + param.tf_stack = (void*)((uintptr)stk - sizeof(uintptr)); oset = runtime·sigprocmask(SIG_SETMASK, sigset_all); ret = runtime·tfork(¶m, sizeof(param), mp, mp->g0, runtime·mstart); diff --git a/src/runtime/stack.c b/src/runtime/stack.c index cb9557243b..88344d0fc1 100644 --- a/src/runtime/stack.c +++ b/src/runtime/stack.c @@ -71,6 +71,9 @@ poolalloc(uint8 order) runtime·throw("bad ref"); if(s->freelist != nil) runtime·throw("bad freelist"); +#ifdef GOOS_openbsd + runtime·sysMarkStack((void *)(s->start << PageShift), s->npages << PageShift); +#endif for(i = 0; i < StackCacheSize; i += FixedStack << order) { x = (MLink*)((s->start << PageShift) + i); x->next = s->freelist; @@ -110,6 +113,9 @@ poolfree(MLink *x, uint8 order) // span is completely free - return to heap runtime·MSpanList_Remove(s); s->freelist = nil; +#ifdef GOOS_openbsd + runtime·sysUnmarkStack((void *)(s->start << PageShift), s->npages << PageShift); +#endif runtime·MHeap_FreeStack(&runtime·mheap, s); } } @@ -246,6 +252,9 @@ runtime·stackalloc(uint32 n) s = runtime·MHeap_AllocStack(&runtime·mheap, ROUND(n, PageSize) >> PageShift); if(s == nil) runtime·throw("out of memory"); +#ifdef GOOS_openbsd + runtime·sysMarkStack((void *)(s->start << PageShift), s->npages << PageShift); +#endif v = (byte*)(s->start<start<start << PageShift), s->npages << PageShift); +#endif runtime·MHeap_FreeStack(&runtime·mheap, s); } }