To ensure integrity against build machine compromise, we should be able to produce identical binaries on two different identically configured machines and verify that hash is the same for each. Right now, this is not possible, primarily because of two things:
gcc uses entropy for symbol mangling
The linker inserts timestamps into libraries, especially static ones.
Issue 1 can be solved by giving gcc a specific seed in our makefiles (-frandom-seed=string). If we have no collisions, we can get away with giving the same seed to every gcc invocation.
Issue 2 can be solved for static libraries by passing the -D option to 'ar'. It is unclear if shared libraries can be produced in this way, or if this option is not needed for shared libraries.
Weird. tor.git is already creating deterministic builds (same sha1sum for ./src/or/tor) for me without the -frandom-seed option. It has static symbols.. I don't get why that is. Maybe Nick knows?
Vidalia also seems to be reproducible (same sha1sum after a make clean && make). I wonder if this is due to a custom patch my distro has done, or if these changes got propagated through the toolchain defaults.
Erinn, is your build process fully automated? I get errors when trying to follow the instructions in build-scripts/DEPLOYMENT
Yikes, that file is out of date. You should be able to just use the makefiles, eg, make -f linux.mk build-tor, and within that makefile there are various build options associated with all of the targets.
I don't find that make -f linux.mk works by default - only some of the targets seem to work and not all of them. I'm going to try to produce a linux tbb build and hack up the Makefile until it works.
I've found that the generic-bundle target does not function:
cp ../changelog.linux-2.2 generic-bundle/Docs/changelog# This should be updated to be more generic (version-wise) and more Linux specificcp ../README.LINUX-2.2 generic-bundle/Docs/README-TorBrowserBundlecp -R /tmp/srv/build-trees/build-alpha-x86_64/Firefox generic-bundle/Appcp: cannot stat `/tmp/srv/build-trees/build-alpha-x86_64/Firefox': No such file or directorymake: *** [install-firefox] Error 1
Ok, so the next step is to have Erinn publish the distro + version of the build system she uses, so we can try to replicate the setup and produce an identical binary.
I'll commit to trying a TBB alpha build once Erinn tells us this info + provides some good build instructions so that we can replicate her steps exactly, and see if we get the same sha1sum. It's about time I learn how to build the damn thing anyways.
Trac: Cc: nickm, asn to nickm, asn, mikeperry Owner: erinn to mikeperry Milestone: N/Ato TorBrowserBundle 2.3.x-stable Status: new to assigned
Ooh, Seth Schoen just pointed me at this: http://gitian.org/. It appears to be a collection of Ruby scripts for facilitating distributed, reproducible builds in qemu vms.
Trac: Cc: nickm, asn, mikeperry to nickm, asn, mikeperry, Sebastian
I just found out we use mingw for Windows builds a few days ago. That thing might actually be able to produce the same binary twice in a row (assuming their build servers are not infected with malware by now..).
Trac: Summary: Deterministic builds for Linux and Mac OS to Deterministic builds
Ok, so the next step is to have Erinn publish the distro + version of the build system she uses, so we can try to replicate the setup and produce an identical binary.
I'll commit to trying a TBB alpha build once Erinn tells us this info + provides some good build instructions so that we can replicate her steps exactly, and see if we get the same sha1sum. It's about time I learn how to build the damn thing anyways.
I did a test building 0.2.3.20 Tor rpms (just the daemon, not whole TBB) on two Fedora 17 and one Scientific Linux 6 machines using mock (mock is a Redhat tool builds in a chroot environment with cleanly downloaded dependencies and toolchain; it can cross-compile as well).
Suprisingly the resulting tor binaries ended up identical accross build machines as long as the target configuration was identical, e.g. every binary built for 'epel-6-x86_64' configuration was bit-identical. Around 10 combinations [build_machine, target_configuration] were tried.
Then I ran a TBB build and tried to build some of the components deterministically. Qt 4.8.2 from src.rpm gave me almost identical builds (compared to distro libs), libQtCore.so and libQtGui.so differing only in 24 and 27 bytes, respectively. The differences appear in strings like 'qt_instdate=2012-08-11' and the ELF NOTE program header.
It looks like they use a utility called 'faketime' to eliminate timestamp differences, and it appears to be a debian package. It also looks like they use it successfully for win32 under mingw, too. There is a separate pile of python scripts for Mac.
Ok, using the hacks from bitcoin's Windows gitian descriptors on Linux, I got Firefox to build almost identically a few times in a row. The only differences were in these files: libplc4.so, libplds4.so, libnspr4.so, and omni.ja.
It looks like all of the differences are due to faketime not faking the milliseconds in timestamps in those files. This might be because they didn't (properly?) hook gettimeofday(), but it looks like they at least tried to do so: https://github.com/wolfcw/libfaketime/blob/master/src/faketime.c#L519, so the problem may be deeper.
Ok, I found the culprit: nsprpub/config/now.c. It gets called during build time to set a #define, and worse, it has specific calls to GetSystemTimeAsFileTime() for Windows. That is definitely not hooked by faketime.
Luckily, it seems to have a #define to omit the build timestamp entirely. I will test a build with that and see what happens.
I played a bit with it. Great work, Mike! Some feedback/questions: 1) After I shut down my computer during the first build I wanted to continue with the build later (or restart it) but gitian (probably) complained that the VMs are already available and did not let me. I thought there was some kind of clean target for that case in the makefile, too, but eventually I had to delete the already existing VMs by hand. Not a big deal but if there were such an additional target in the makefile that would be fine. 2) Do you check the signatures for the language packs (or more precisely: the signature of the SHA512SUMS file + the contained sha512 hashes of the language packs)? That does not seem to be the case or did I miss something? 3) Do you have a result of your builds somewhere to check whether I really got the same binaries?
Following the steps you outlined on IRC (taking the tbb-3.0alpha1-close-enough tag etc.) I got the following build error:
****** Starting Tor Component of Linux Bundle (1/3 for Linux) ******--- Building tor-linux for lucid i386 ---Stopping target if it is upMaking a new image copyFormatting 'target-lucid-i386.qcow2', fmt=qcow2 size=11811160064 backing_file='base-lucid-i386.qcow2' encryption=off cluster_size=65536 Starting targetChecking if target is up..........Connection timed out during banner exchange./bin/gbuild:21:in `system!': failed to run on-target true (RuntimeError) from ./bin/gbuild:73:in `build_one_configuration' from ./bin/gbuild:223 from ./bin/gbuild:218:in `each' from ./bin/gbuild:218 from ./bin/gbuild:216:in `each' from ./bin/gbuild:216mv: cannot stat `var/build.log': No such file or directorymake: *** [build] Error 1
After running at least into issue 1, 2 and 5 mentioned in README.build I eventually succeeded. See the attached SHA256 sums. (although I am wondering why there were no 64bit Mac OS X builds done)