golang/go

cmd/dist: build cmd with CGO_ENABLED=0, so cmd/go uses pure Go net resolver

rsc opened this issue · 12 comments

rsc commented

Now that we've removed the .a files from the distribution, the only possible leakage of the host build environment into Go Linux releases is the dynamic libc.so.6 path embedded in the command binaries that use the network (only bin/go and pkg/tool/goos_goarch/pprof, I believe).

I wonder whether we should build cmd with CGO_ENABLED=0 so that we end up with purely static cmd/go and cmd/pprof binaries. This would apply to all systems, but since we are planning to cross-compile non-Linux distributions and Mac and Windows don't use cgo anyway for net, the only effect would be on Linux.

We default to the cgo-based net so that people with strange /etc/resolv.conf can still resolve the names they need to resolve. But perhaps that is more for local names like mDNS and such rather than the standard internet names that cmd/go needs.

Does anyone see anything that would break if we made the go command always use the pure Go net resolver?

Would this cause go install cmd to install a different cmd/go from what make.bash produces?
That might be ok, but we would probably at least have to update some tests that assume it is a no-op.

(But it also might provide a reasonable workaround for folks who want a cmd/go that uses the C resolver.)

rsc commented

Would this cause go install cmd to install a different cmd/go from what make.bash produces?
That might be ok, but we would probably at least have to update some tests that assume it is a no-op.

Yes, and agreed.

rsc commented

With a little more work this lets us build completely reproducible distributions, where it doesn't matter which OS the distribution was built on at all. In particular they could all be built on a single trusted system. CL 454836 does this.

Change https://go.dev/cl/454836 mentions this issue: cmd/dist: make toolchain build reproducible

We default to the cgo-based net so that people with strange /etc/resolv.conf can still resolve the names they need to resolve. But perhaps that is more for local names like mDNS and such rather than the standard internet names that cmd/go needs.

I don't think that resolv.conf might be a problem, go 1.20 supports most options that are used in the wild.

Does anyone see anything that would break if we made the go command always use the pure Go net resolver?

Some users might have problem because of /etc/nsswitch.conf, when we compiled without cgo we default to files,dns order, we don't even parse that file.

Recently the nsswitch.conf (hosts database) on glibc-based linux systems becomes more and more bloated. We should be careful with this.

rsc commented

In what circumstances would nsswitch.conf be needed to resolve public internet names like github.com or proxy.golang.org?

In what circumstances would nsswitch.conf be needed to resolve public internet names like github.com or proxy.golang.org?

Glibc uses nsswitch.conf to resolve all names. Recently linux distros (desktop) started adopting systemd-resolve nss module, instead of a dns one, so that the dns module is not even used to resolve hostnames, the dns queries are send by the systemd-resolved deamon.
I mean if we change the go binary to use netgo by default, then probably nothing will break, but we don't know how the nsswitch.conf configurations might evolve in the future.

Edit: but on non-glibc systems (without nsswitch.conf support in libc) the go resolver will be fine, so for alpine and other musl based distros.

rsc commented

I guess we will find out - there are enough upsides to this change, including cross-compiled reproducible builds, that I think we owe it to ourselves to try it in Go 1.21 and find out whether there are any show-stoppers.

#57328 is an interesting data point here too. There, a user is reporting that building a cgo-enabled dynamically-linked binary on an Ubuntu with a newer glibc causes that binary to fail to run on a system with an older glibc.

That seems to imply that if we build a cgo-enabled cmd/go against a recent glibc and include it in a Go release, it will similarly fail to run on an older system. But we probably also don't want to build our releases on ancient versions of our supported platforms just to improve the glibc compatibility of the resulting binaries.

Building the release with CGO_ENABLED=0 nicely sidesteps that problem, allowing Go releases to be built on more up-to-date platforms.

failures due to glibc versions were also seen a long time ago in #5203

Change https://go.dev/cl/461689 mentions this issue: cmd/go: do not attempt to install cmd/addr2line in TestScript/mod_outside

Change https://go.dev/cl/463739 mentions this issue: cmd/dist: leave cgo enabled if external linking is required