New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/go: go tool can be tricked into linking a set of packages that do not typecheck as a whole #13119
Comments
Proposed fix https://go-review.googlesource.com/#/c/16475/ |
CL https://golang.org/cl/16475 mentions this issue. |
Your example seems to rely on manipulating the GOPATH so that one package is seen in one case and a different package with the same apparent name is seen in a different case. It's not obvious to me that it's important for the go tool to try to defend against people who do this kind of thing. You could do exactly the same thing by simply replacing the .a file. Your proposed CL makes that a bit harder, because now I can't just replace the .a file using cp, I have to actually edit the .a file to change the build note value. Can you explain why this is worth changing? |
I consider this issue worth fixing, because it ensures the program as a whole is well-typed, that whatever type-safety assertions the compiler made, while compiling an individual package, still hold at the time of linking. |
I don't think this has anything to do with type safety of Go.
You're manipulating the objects behind the compiler's back.
Actually you don't even need to have two GOPATH to do
this. You first build package and c, then change the source
of package a, rebuild it but keeping the mtime of both source
and .a file the same as the original one, and finally build b.
The proposed change also introduces a major problem:
two different builds of the same package will produce
different buildID, so we lost the ability produce identical
binaries given identical inputs: the toolchain is no longer
deterministic.
To really fix the problem without breaking the deterministic
constraint is very hard, we basically have to include a hash
of the source code into the buildID (just hashing the exported
interface is not enough, because it's possible to only change
the internal implementation of some non-exported functions
and achieve the same arbitrary memory read).
|
The ultimate goal of type-safety is to produce an executable, free of type errors. A type-checked
I'm sorry, I'm not manipulating objects. I'm manipulating GOPATH, which is supposed to be
OK, multiple different ways, by which one can achieve the same bad result just increase the severity of the problem.
"toolchain is no longer deterministic" is quite a statement, the output consist of eight concrete non-deterministic bytes, the rest is deterministic. How is that property used at the moment? Whatever procedure compares the outputs of two builds,
Yes, but hashing the entire source was already considered unacceptable tradeoff wrt. build speed, |
Every language that supports separate compilation is vulnerable to the issue you describe. I don't think this is serious or worth fixing. Sorry. Simple deterministic output is a highly desirable property. |
Normally, when compiling a package, it is typechecked together with its imports, their imports , etc, transitively. It is possible to successfully compile a package, but later link it with a version of a package's import, that it has not been typechecked against.
When building a package, the
go
tool generates a buildID as a SHA1 sum of, basically, the list of package source file names and thebuildID
s of the imported packages. The tool compares the expected/computedbuildID
with the actualbuildID
, recorded in the package binary, and decides if the package needs to be rebuilt.Two different packages can have the same set of source file names and the same set of imported packages, consequently the same
buildID
. This is not entirely unlikely, for example, these might be two (binary incompatible) versions of the same package.Consider two such packages
A1
andA2
, with identicalbuildID
. A third package,C
, importsA
and is successfully typechecked and compiled againstA2
as the actual package found for the import pathA
. If, later, packageC
is linked withA1
,go
tool may not notice thatC
needs to be rebuilt, because the computedbuildID
ofC
, which uses thebuildID
ofA1
, is identical to the recordedbuildID
ofC
, which uses thebuildID
ofA2
.The steps to reproduce this problem are described in https://github.com/momchil-velikov/go-abuse
(download link https://github.com/momchil-velikov/go-abuse/archive/master.zip)
There are two examples, one of accessing a
float32
asuint32
and one of writing to arbitrary memory location, obviously, without using theunsafe
package.It was tested with go-1.4.2, go-1.5-1 and master on GNU/Linux and MacOS X.
The text was updated successfully, but these errors were encountered: