]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: turn ASLR off for netbsd+race
authorKeith Randall <khr@golang.org>
Fri, 10 Apr 2020 21:07:13 +0000 (14:07 -0700)
committerKeith Randall <khr@golang.org>
Sat, 11 Apr 2020 15:42:09 +0000 (15:42 +0000)
The race detector can't handle ASLR (adddress space layout randomization).
On some platforms it can re-exec the binary with ASLR off. But not NetBSD.
For NetBSD we have to introduce a special ELF header note that tells
the kernel not to use ASLR.

This works fine for internal linking. For external linking it also works,
but "readelf -n" shows multiple notes in the resulting binary. Maybe the
last one wins? Not sure, but it appears to work.

Change-Id: I5fe6dd861e42a8293f64d0dacb166631ea670fcc
Reviewed-on: https://go-review.googlesource.com/c/go/+/227864
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Dmitry Vyukov <dvyukov@google.com>
src/cmd/link/internal/ld/elf.go

index e15f94d5e0b96e290391137e99c4bb9b226cfc6a..fbf91fd51fc0a76d68142ff39677d9d8f9f7d64f 100644 (file)
@@ -883,6 +883,25 @@ func elfwritenetbsdsig(out *OutBuf) int {
        return int(sh.size)
 }
 
+// The race detector can't handle ASLR (address space layout randomization).
+// ASLR is on by default for NetBSD, so we turn the ASLR off eplicitly
+// using a magic elf Note when building race binaries.
+
+func elfnetbsdpax(sh *ElfShdr, startva uint64, resoff uint64) int {
+       n := int(Rnd(4, 4) + Rnd(4, 4))
+       return elfnote(sh, startva, resoff, n)
+}
+
+func elfwritenetbsdpax(out *OutBuf) int {
+       sh := elfwritenotehdr(out, ".note.netbsd.pax", 4 /* length of PaX\x00 */, 4 /* length of flags */, 0x03 /* PaX type */)
+       if sh == nil {
+               return 0
+       }
+       out.Write([]byte("PaX\x00"))
+       out.Write32(0x20) // 0x20 = Force disable ASLR
+       return int(sh.size)
+}
+
 // OpenBSD Signature
 const (
        ELF_NOTE_OPENBSD_NAMESZ  = 8
@@ -1484,6 +1503,9 @@ func (ctxt *Link) doelf() {
        }
        if ctxt.IsNetbsd() {
                shstrtab.Addstring(".note.netbsd.ident")
+               if *flagRace {
+                       shstrtab.Addstring(".note.netbsd.pax")
+               }
        }
        if ctxt.IsOpenbsd() {
                shstrtab.Addstring(".note.openbsd.ident")
@@ -1821,6 +1843,14 @@ func Asmbelf(ctxt *Link, symo int64) {
 
        var pph *ElfPhdr
        var pnote *ElfPhdr
+       if *flagRace && ctxt.IsNetbsd() {
+               sh := elfshname(".note.netbsd.pax")
+               resoff -= int64(elfnetbsdpax(sh, uint64(startva), uint64(resoff)))
+               pnote = newElfPhdr()
+               pnote.type_ = PT_NOTE
+               pnote.flags = PF_R
+               phsh(pnote, sh)
+       }
        if ctxt.LinkMode == LinkExternal {
                /* skip program headers */
                eh.phoff = 0
@@ -2298,6 +2328,9 @@ elfobj:
                        a += int64(elfwritegobuildid(ctxt.Out))
                }
        }
+       if *flagRace && ctxt.IsNetbsd() {
+               a += int64(elfwritenetbsdpax(ctxt.Out))
+       }
 
        if a > elfreserve {
                Errorf(nil, "ELFRESERVE too small: %d > %d with %d text sections", a, elfreserve, numtext)