From cc3a3519af5b8b4cf26bf27133675776fdfcaeb9 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Tue, 8 Feb 2022 12:41:26 -0500 Subject: [PATCH] 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 Trust: Than McIntosh Run-TryBot: Than McIntosh TryBot-Result: Gopher Robot --- src/cmd/link/internal/ld/lib.go | 57 +++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 6f9c7c2627..4295bb8656 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -1353,13 +1353,52 @@ func (ctxt *Link) hostlink() { argv = append(argv, "-Wl,-bbigtoc") } - // Enable ASLR on Windows. - addASLRargs := func(argv []string) []string { - // Enable ASLR. - argv = append(argv, "-Wl,--dynamicbase") + // Enable/disable ASLR on Windows. + addASLRargs := func(argv []string, val bool) []string { + // Old/ancient versions of GCC support "--dynamicbase" and + // "--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. - if ctxt.Arch.PtrSize >= 8 { - argv = append(argv, "-Wl,--high-entropy-va") + if ctxt.Arch.PtrSize >= 8 && heopt != "" { + argv = append(argv, "-Wl,"+heopt) } return argv } @@ -1376,7 +1415,7 @@ func (ctxt *Link) hostlink() { switch ctxt.HeadType { case objabi.Hdarwin, objabi.Haix: case objabi.Hwindows: - argv = addASLRargs(argv) + argv = addASLRargs(argv, *flagAslr) default: // ELF. if ctxt.UseRelro() { @@ -1393,9 +1432,7 @@ func (ctxt *Link) hostlink() { } argv = append(argv, "-shared") if ctxt.HeadType == objabi.Hwindows { - if *flagAslr { - argv = addASLRargs(argv) - } + argv = addASLRargs(argv, *flagAslr) } else { // Pass -z nodelete to mark the shared library as // non-closeable: a dlclose will do nothing. -- 2.50.0