cmd/link/internal/ld: revise recipe for ASLR enable on windows

When doing external linking on windows, the existing Go linker code
assumed that the external linker defaulted to "--no-dynamicbase" (if
no explicit option was given). This assumption doesn't hold for LLD,
which turns on "--dynamicbase" by default for 64-bit apps. Change the
linker to detect whether a more modern toolchain is in use and to
explicitly pass "--dynamicbase" either way , so as to take the
external linker default out of the equation. This also applies to the
"--high-entropy-va" option as well.

Updates #35006.

Change-Id: I3e12cf6d331c9d003e3d2bd566d45de5710588b9
Reviewed-on: https://go-review.googlesource.com/c/go/+/384156
Reviewed-by: Cherry Mui <cherryyz@google.com>
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Than McIntosh 2022-02-08 12:41:26 -05:00
parent f7670b9f94
commit cc3a3519af

View file

@ -1353,13 +1353,52 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Wl,-bbigtoc") argv = append(argv, "-Wl,-bbigtoc")
} }
// Enable ASLR on Windows. // Enable/disable ASLR on Windows.
addASLRargs := func(argv []string) []string { addASLRargs := func(argv []string, val bool) []string {
// Enable ASLR. // Old/ancient versions of GCC support "--dynamicbase" and
argv = append(argv, "-Wl,--dynamicbase") // "--high-entropy-va" but don't enable it by default. In
// addition, they don't accept "--disable-dynamicbase" or
// "--no-dynamicbase", so the only way to disable ASLR is to
// not pass any flags at all.
//
// More modern versions of GCC (and also clang) enable ASLR
// by default. With these compilers, however you can turn it
// off if you want using "--disable-dynamicbase" or
// "--no-dynamicbase".
//
// The strategy below is to try using "--disable-dynamicbase";
// if this succeeds, then assume we're working with more
// modern compilers and act accordingly. If it fails, assume
// an ancient compiler with ancient defaults.
var dbopt string
var heopt string
dbon := "--dynamicbase"
heon := "--high-entropy-va"
dboff := "--disable-dynamicbase"
heoff := "--disable-high-entropy-va"
if val {
dbopt = dbon
heopt = heon
} else {
// Test to see whether "--disable-dynamicbase" works.
newer := linkerFlagSupported(ctxt.Arch, argv[0], "", "-Wl,"+dboff)
if newer {
// Newer compiler, which supports both on/off options.
dbopt = dboff
heopt = heoff
} else {
// older toolchain: we have to say nothing in order to
// get a no-ASLR binary.
dbopt = ""
heopt = ""
}
}
if dbopt != "" {
argv = append(argv, "-Wl,"+dbopt)
}
// enable high-entropy ASLR on 64-bit. // enable high-entropy ASLR on 64-bit.
if ctxt.Arch.PtrSize >= 8 { if ctxt.Arch.PtrSize >= 8 && heopt != "" {
argv = append(argv, "-Wl,--high-entropy-va") argv = append(argv, "-Wl,"+heopt)
} }
return argv return argv
} }
@ -1376,7 +1415,7 @@ func (ctxt *Link) hostlink() {
switch ctxt.HeadType { switch ctxt.HeadType {
case objabi.Hdarwin, objabi.Haix: case objabi.Hdarwin, objabi.Haix:
case objabi.Hwindows: case objabi.Hwindows:
argv = addASLRargs(argv) argv = addASLRargs(argv, *flagAslr)
default: default:
// ELF. // ELF.
if ctxt.UseRelro() { if ctxt.UseRelro() {
@ -1393,9 +1432,7 @@ func (ctxt *Link) hostlink() {
} }
argv = append(argv, "-shared") argv = append(argv, "-shared")
if ctxt.HeadType == objabi.Hwindows { if ctxt.HeadType == objabi.Hwindows {
if *flagAslr { argv = addASLRargs(argv, *flagAslr)
argv = addASLRargs(argv)
}
} else { } else {
// Pass -z nodelete to mark the shared library as // Pass -z nodelete to mark the shared library as
// non-closeable: a dlclose will do nothing. // non-closeable: a dlclose will do nothing.