As part of windows/arm support, in CL125468 cmd/ld has learnt how to generate dynamic base executables, that is binaries that can be relocated at any virtual memory address. This allows the Windows kernel to turn on ASLR.
The support has been activated only on windows/arm. It should be activated also on amd64 and x86, so that Go binaries on Windows can benefit from ASLR.
/cc @alexbrainman
Change https://golang.org/cl/152759 mentions this issue: cmd/link: include relocs on Windows on all architectures
I'm assuming this is still unplanned, and not scheduled for 1.14? Is there anything I could do to help get this merged in, the CL looks very straightforward, I guess just the original submitter of the CL hasn't replied in months?
When the trybots were run for the CL mentioned above, the CL failed on Windows systems. Somebody will need to debug that.
I'm assuming this is still unplanned, and not scheduled for 1.14? Is there anything I could do to help get this merged in, the CL looks very straightforward, I guess just the original submitter of the CL hasn't replied in months?
I would like this implemented.
And we don't need John to finish his CL. We could create a new CL.
@capnspacehook, why do you want this change? How will you use it?
The only issue is still bothering me. I think this change should be default, not hidden behind "never used during day to day work" flag. Otherwise people will never use this facility.
On the other hand, having Go code always load at the same address is often useful when debugging.
Perhaps we should make this default, and allow for some go command flag to make Go code use fixed addresses. John's CL selected to use -buildmode=pie vs -buildmode=exe to control this. But -buildmode=exe is default on windows now. Should we make -buildmode=pie default on windows? I think it will be confusing to windows users. They don't know what pie is comparing to exe. Ian?
/cc @zx2c4 for input.
Thank you.
Alex
Indeed this should be turned on by default. Most debuggers and reverse engineering tools can rebase fine and figure stuff out. Recent versions of IDA Pro do this a lot faster than it used to be too.
Indeed this should be turned on by default. Most debuggers and reverse engineering tools can rebase fine and figure stuff out.
I am fine with that, if others do not object.
@ianlancetaylor , if we want to make all Windows executables use random addresses ( https://en.wikipedia.org/wiki/Address_space_layout_randomization ) by default, do we need proposal here?
Thank you.
Alex
It doesn't need a proposal, but I'm not sure it's the right thing to do. What do other compilers do? In particular, what do GCC and clang do?
@alexbrainman I am really interested in the added security benefits of PIE windows executables; as you mentioned ASLR and inhibiting reverse engineering more.
As for what to do, I agree that PIE mode for Windows executables should be default. But I think using the pie and exe buildmodes would be confusing, maybe buildmode=exe would stay the default when GOOS=windows, but a flag could be introduced that makes binaries load at a fixed address for debugging?
@alexbrainman I am really interested in the added security benefits of PIE windows executables; as you mentioned ASLR and inhibiting reverse engineering more.
ASLR, yes. "Inhibiting reverse engineering" - what?
Sorry, I just meant ASLR will make reverse engineering a bit more difficult, if I understand correctly. Now that I think about it, I think I got RE mixed up with binary exploitation... my bad
What do other compilers do? In particular, what do GCC and clang do?
I do not know about clang. But I tried Mingw GCC C, and Microsoft C and C#.
According to https://stackoverflow.com/questions/8554014/how-to-know-whether-a-dll-uses-aslr-or-not
GCC does not produce ASLR binaries by default:
C:\>dumpbin /headers mingw.exe | sed "/OPTIONAL HEADER VALUES/,+30!d"
OPTIONAL HEADER VALUES
20B magic # (PE32+)
2.30 linker version
1E00 size of code
3800 size of initialized data
A00 size of uninitialized data
14E0 entry point (00000000004014E0)
1000 base of code
400000 image base (0000000000400000 to 0000000000411FFF)
1000 section alignment
200 file alignment
4.00 operating system version
0.00 image version
5.02 subsystem version
0 Win32 version
12000 size of image
400 size of headers
1B418 checksum
3 subsystem (Windows CUI)
0 DLL characteristics
200000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
0 [ 0] RVA [size] of Export Directory
8000 [ 7C4] RVA [size] of Import Directory
0 [ 0] RVA [size] of Resource Directory
5000 [ 27C] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
C:\>
But both Microsoft C and C# both generate ASLR by default:
C:\>dumpbin /headers ms_c.exe | sed "/OPTIONAL HEADER VALUES/,+30!d"
OPTIONAL HEADER VALUES
20B magic # (PE32+)
14.16 linker version
13200 size of code
D200 size of initialized data
0 size of uninitialized data
1388 entry point (0000000140001388)
1000 base of code
140000000 image base (0000000140000000 to 0000000140023FFF)
1000 section alignment
200 file alignment
6.00 operating system version
0.00 image version
6.00 subsystem version
0 Win32 version
24000 size of image
400 size of headers
0 checksum
3 subsystem (Windows CUI)
8160 DLL characteristics
High Entropy Virtual Addresses
Dynamic base
NX compatible
Terminal Server Aware
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
0 [ 0] RVA [size] of Export Directory
C:\>dumpbin /headers ms_csc.exe | sed "/OPTIONAL HEADER VALUES/,+30!d"
OPTIONAL HEADER VALUES
10B magic # (PE32)
48.00 linker version
600 size of code
800 size of initialized data
0 size of uninitialized data
24DE entry point (004024DE)
2000 base of code
4000 base of data
400000 image base (00400000 to 00407FFF)
2000 section alignment
200 file alignment
4.00 operating system version
0.00 image version
4.00 subsystem version
0 Win32 version
8000 size of image
200 size of headers
0 checksum
3 subsystem (Windows CUI)
8540 DLL characteristics
Dynamic base
NX compatible
No structured exception handler
Terminal Server Aware
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
C:\>
Alex
Took a bunch of flags to do it: https://git.zx2c4.com/wireguard-windows/diff/Makefile?id=7b6fcc0184e58626007b581be04ac7f5312861ea Using export-all-symbols is a nasty hack; tor works around it a bit more elegantly: https://gitweb.torproject.org/builders/tor-browser-build.git/tree/projects/binutils/enable-reloc-section-ld.patch I'll see if we can get that added to the musl.cc toolchain. CC @zv-io
The result:

I rebuilt a few of the musl.cc toolchains with this patch applied on top of the current musl.cc binutils 2.33.1. Please test and confirm this works, and if so, this patch will be included in subsequent releases. I won't be updating this comment when that happens; check the homepage.
If GCC doesn't generate PIE by default, it's not obvious to me that go should. Clearly we should make sure that go build -buildmode=pie builds a PIE. But I don't yet see why go build (which for a main package is equivalent to go build -buildmode=exe) should build a PIE.
The question here is not whether PIE is more secure. It's what the default behavior should be.
If GCC doesn't generate PIE by default, it's not obvious to me that go should.
I don't think you should dismiss the fact that Microsoft compilers do generate PIE by default. Most Windows executables are built by Microsoft tools.
Clearly we should make sure that
go build -buildmode=piebuilds a PIE.
Sure, we could do that. But I don't see why Go developers would use this command option. ASLR is supposed to help make Windows more secure. Developers don't care about their users OS security. It is OS admin responsibility to make system secure. Developers will use whatever default build mode is.
Also current windows-arm version of Go already uses PIE by default
https://go-review.googlesource.com/c/go/+/125648
I think our current go command flags are just confusing in that area.
Alex
The question here is not whether PIE is more secure. It's what the default behavior should be.
I can't see a compelling reason _at all_ not to produce PIE executables for all Go users, vanilla and cgo, as the default option. Sure we can have a switch to disable PIE for the weird cases where people don't want it, but as @alexbrainman points out, PIE (and DEP, for that matter) is the default situation on Windows since a very long time. Differing from that and providing a less secure experience with Go out of the box is bad news. The fact that Go was producing 90s-style executables by default certainly caught me by surprise.
Alright, WireGuard for Windows 0.0.35, just now released to users, enables DEP and high-entropy ASLR, on both amd64 and 386. I'll report back if anybody indicates awful breakage -- the largeish userbase is usually pretty reactive. I suspect things will be mostly okay.
@alexbrainman Fair enough.
Does anybody think it would be a bad idea to change the default to be PIE on Windows?
Does anybody have a suggestion as to how it should work? Would we keep the current -buildmode options and change the default for a main package to be -buildmode=pie, while -buildmode=exe would continue to build a non-PIE?
Probably the question of the default should be a separate issue.
ARM does it unconditionally. What if we just did it that way?
Or do you think providing the option is important?
Change https://golang.org/cl/203602 mentions this issue: cmd/link: enable ASLR on Windows executables
Does anybody think it would be a bad idea to change the default to be PIE on Windows?
I think we should create new proposal for that, and see what happens.
The only downside I see, we might discover some bugs.
Does anybody have a suggestion as to how it should work? Would we keep the current
-buildmodeoptions and change the default for a main package to be-buildmode=pie, while-buildmode=exewould continue to build a non-PIE?
That sounds good to me. As long as -buildmode=pie is the default, and users don't need to type it, I think we will be alright.
ARM does it unconditionally. What if we just did it that way?
Or do you think providing the option is important?
I have an impression that we don't have choice for ARM.
And I think it is important, that we have easy way to disable ASLR if required. I would use that myself while debugging. And, if we follow Ian's suggestion, it is just -buildmode=exe option away.
Alex
AFAIK, Windows ARM bins have to be relocatable. And I think Ian's suggestion makes a lot of sense
Probably the question of the default should be a separate issue.
Done: #35192
Change https://golang.org/cl/203602 mentions this issue:
cmd/link: enable ASLR on Windows executables
This CL is now called "cmd/link: allow ASLR on Windows executables", and I've moved the default stuff to https://go-review.googlesource.com/c/go/+/203606 for discussion in https://github.com/golang/go/issues/35192 .
Change https://golang.org/cl/214397 mentions this issue: cmd/go, cmd/link: implement -buildmode=pie on windows
Most helpful comment
I don't think you should dismiss the fact that Microsoft compilers do generate PIE by default. Most Windows executables are built by Microsoft tools.
Sure, we could do that. But I don't see why Go developers would use this command option. ASLR is supposed to help make Windows more secure. Developers don't care about their users OS security. It is OS admin responsibility to make system secure. Developers will use whatever default build mode is.
Also current windows-arm version of Go already uses PIE by default
https://go-review.googlesource.com/c/go/+/125648
I think our current go command flags are just confusing in that area.
Alex