|
|
Subscribe / Log in / New account

Toward a fully reproducible Debian

Benefits for LWN subscribers

The primary benefit from subscribing to LWN is helping to keep us publishing, but, beyond that, subscribers get immediate access to all site content and access to a number of extra site features. Please sign up today!

June 15, 2018

This article was contributed by Tom Yates


FLOSS UK
It's been a little over one year since we last covered Debian's reproducible builds project. The effort has not stopped in the interim; progress continues to be made, the message has sharpened up, and word is spreading. Chris Lamb, speaking about this at FLOSS UK in a talk called "You may think you're not a target: a tale of three developers", hinted that the end may be starting to come into sight.

The three developers of the title are part of the sharpened message, each being an example of the problem that reproducible builds aim to solve. Alice, a system administrator who contributes to a Linux distribution, is building her binaries on servers that, unknown to her, have been compromised; her binaries are trojan horses, carrying malicious content into systems that run them. Bob, a privacy-oriented developer, makes a privacy-preserving browser, but is being blackmailed into secretly including vulnerabilities in the binaries he provides. Carol is a free-software user whose laptop is being attacked by an evil maid called Eve, the third developer of the title; each time Carol shares free software with her friends, it is pre-compromised by Eve. All of these attacks hurt free-software users and the reputation of free software as a whole.

Worse, the mere existence of these classes of attack is a disincentive to share software. People like Alice may reason that, if their servers turn out to be compromised, they will be blamed for the malicious software they have unwittingly distributed, and that the potential opprobrium may not be justified by the fleeting gratitude they currently get for their unpaid work. Others who have [Chris Lamb] servers, skills, and time they might once have volunteered to help build free software may similarly decline to paint a target upon themselves. In Lamb's words, they may say "I'm not going to do this free software lark. I'm going to go for a walk instead". Participation in the community is reduced, as is the trust we all place in the binaries we install.

Building everything from sources that one has hand-inspected is a solution to this, but it doesn't scale. Many of us aren't qualified to spot security weaknesses (Lamb's specific example was the one-line patch that throttled Debian's ability to generate random keys, back in 2008), and in any case you still need to get that initial compiler from somewhere. Many users, even those who love free software and wish to use it in preference to proprietary software, will continue to install binaries. I will be one of them.

But if compilation from a given set of sources in a given environment always resulted in binaries that were bit-for-bit identical to each other, having confidence in the integrity of your binaries would be a much easier proposition, since you could compare your own binary copy with those of a suitable number of others. You could ring a friend and compare checksums, or you could perhaps participate in a distributed checksum validation scheme comparable to the old Perspectives system for distributed validation of SSL certificates. Many strategies for increasing confidence would be possible, but only if the build is reproducible. That is what Debian has been striving for, and why.

There are other advantages to reproducible builds. For developers, they mean that successive generations of a binary should change only in proportion to the source changes that were made between them; the only changes you should see in your binaries are the ones you intended to be there. It helps cut down on unnecessary build dependencies; you can remove a dependency and rebuild, and if the binary hasn't changed, you didn't need that dependency and can get rid of it. In some cases, it can even help find bugs: Lamb referred to a build that had been made non-reproducible by a 15-digit random number that was generated during each build and baked into the resulting binary. It turned out that it was used as an OpenID secret, which meant that everyone running a given build of the software was using the same secret key.

Clearly, reproducible builds are a good thing, but it turns out they aren't trivial. As we reported earlier, many build systems put timestamps inside binaries, which is an obvious problem. But some go further and include user, group, and umask information, and sometimes environment variables, which are also a problem. Build paths are often rolled in, for example in C++ assertions. File ordering can be an issue, because Unix doesn't specify an order in which readdir() and listdir() should return the contents of a directory, so components can get built in an unpredictable order. If these components are packed into a binary in the order they're returned, each build will be different even if no other change has been made.

Similar problems exist with dictionary key ordering: for example, a build that iterates over the keys of a Perl hash will have problems, since these elements are also returned in a variable order. Parallelism in a build process can also make the build order non-deterministic, because different elements can build at different speeds at different times.

Debian's approach to this has been the development of the torture test. Everything is built twice, an A build and a B build, and between the two builds as much as possible is varied. The clock on the B build server is 18 months ahead of the clock on the A server; their hostnames and domain names are different. The reproducible build team developed a FUSE filesystem called disorderfs, which tries to be as non-deterministic as a working filesystem can be. They vary the time zone, locale, UID, GID, and kernel, all to try to determine to a high degree of accuracy whether a given build is reproducible.

When this work started in 2013, 24% of the software in Debian would build reproducibly. As we reported earlier, by 2015 it was up to about 75%, and as of March 2018, said Lamb, 93% of the packages in Debian 10 (buster) built reproducibly on amd64. But, while the proportion has been steadily increasing, the increase hasn't been monotonic. Lamb's graph of reproducibility vs. time since late 2014 showed a couple of big backslides. These, he said, tended to correlate with new variations introduced to the torture test. A sharp drop in reproducibility in late 2016, for example, marked the introduction of variable build paths. The issues that this exposed were dealt with over the next four months; this work included a patch to GCC.

Meanwhile, the idea is spreading; various distribution and build-system projects, including coreboot, Fedora, LEDE, OpenWRT, NetBSD, FreeBSD, Arch Linux, Qubes, F-Droid, NixOS, Guix, and Meson, have all joined the reproducible builds project. Three reproducible build summits have been held, and more are anticipated. Good tools other than disorderfs have come out of the project, such as the .buildinfo file we covered earlier. We also covered diffoscope, but this can now interpret about sixty different types of content, from Android APKs to xz-compressed files. As happens with any good tool, people are starting to find other uses for it. Lamb said that he found it particularly helpful verifying that security patches didn't touch any more of a binary than he expected them to; he also noted its utility in comparing binary blobs such as an old and a new router firmware image.

An honest look at limitations is a good thing. In response to a later question about whether diffoscope could identify "effectively reproducible" builds that differ in only trivial ways, Lamb declined to come up with a definition of "sufficiently reproducible". For him, the reproducibility test is exact binary compatibility; diffoscope is a tool to help diagnose failures to meet that standard, not an opportunity to lower the bar. Reproducible builds themselves are no panacea. They do nothing to help find backdoors or other vulnerabilities in the source; if your Git repository has been compromised, reproducible builds won't save you. Similarly, they do nothing to find or fix programming errors, weak algorithm choices, or "testing" modes in the style of Volkswagen.

Further improvement is possible. User interfaces for handling the installation of software that cannot build reproducibly could do with a lot of improvement over Debian's current offer. Toolchains continue to need fixes: the GCC patch referred to earlier is not yet in upstream, and a whole bunch of OCaml packages aren't reproducible. The advantage of fixing these at the toolchain level is that you fix a given issue across half a million packages at once instead of having to modify each individual package's build to work around it. Lamb noted that help from OCaml and R experts would be particularly valuable right now.

He hopes that the next release of Debian will be 100% reproducible, and noted that progress can be seen at isdebianreproducibleyet.com. He mentioned that at some point a policy change to Debian might be considered, such that software that wouldn't build reproducibly wouldn't be accepted for inclusion. In response to my question, he said that 93% is to his mind too early for such a change, but that once reproducible builds get to 98-99% he'd become much more supportive of it.

In the tricky middle ground of 95-96%, his position would depend on why builds were non-reproducible, as there are a few valid reasons for this to happen. In response to another question, he said that two good reasons for a non-reproducible build were packages that build inside their own virtual machine, such as Emacs, and security packages with signing keys such as secure boot. The former, he thinks, can probably be solved with enough work; the latter can't be fixed, but there are only a couple of them, and an exception could be made.

I'm a big fan of tools that let me manage my own security. I prefer a YubiKey to an RSA token, because I can generate and load my own secrets. This reproducible build work cheers me up because it allows me to manage the security of my vendor-supplied binaries in addition to trusting my vendor's building and signing infrastructure. Hopefully, Debian will reach a point where it mandates reproducible builds and others will soon follow suit.

[Thanks to the Linux Foundation, LWN's travel sponsor, for supporting my travel to the event.]

Index entries for this article
SecurityDeterministic builds
SecurityDistribution security
GuestArticlesYates, Tom
ConferenceFLOSS UK/2018


(Log in to post comments)

Toward a fully reproducible Debian

Posted Jun 15, 2018 19:16 UTC (Fri) by xtifr (guest, #143) [Link]

My one minor complaint about the project (and it's a *very* minor complaint) is that they've outlawed build-time time-stamps. Which I always rather liked. It seems like there *must* be a way to identify tiny bits of data (not code) as time-stamps or the like and skip over them during the comparison phase. Obviously not a priority, but I hope it's something they get around to looking at *someday*. (Though I won't be upset if they don't--it might be *way* more work than it's worth.)

But overall, I think this is a big win for everyone. It's not just the security issues. It's handy to be able to verify that your supposed-to-be-purely-cosmetic changes to some code really didn't change anything, for example.

Toward a fully reproducible Debian

Posted Jun 15, 2018 19:27 UTC (Fri) by Karellen (subscriber, #67644) [Link]

Honest question - why do you want build-time time-stamps? If the software built today is the same as the same software built last week, bit-for-bit, does it actually matter when it was built?

Toward a fully reproducible Debian

Posted Jun 15, 2018 19:50 UTC (Fri) by pizza (subscriber, #46) [Link]

It's so you can (relatively) easily tell that something has intentionally changed. Such as when you're actively developing/testing something and don't want to have to bump/change a revision string every time you type 'make'.

Toward a fully reproducible Debian

Posted Jun 15, 2018 20:16 UTC (Fri) by jani (subscriber, #74547) [Link]

> It's so you can (relatively) easily tell that something has intentionally changed.

A timestamp doesn't tell you that. A git commit id does. Use git describe for creating your version string.

Toward a fully reproducible Debian

Posted Jun 15, 2018 22:35 UTC (Fri) by k8to (guest, #15413) [Link]

git hashes cannot be sorted. This is a significant reduction in utility.

Toward a fully reproducible Debian

Posted Jun 15, 2018 22:59 UTC (Fri) by tux3 (subscriber, #101245) [Link]

If that's the only objection, the timestamp of the git hash is as reproducible as the git has itself. And obviously can be sorted.

Toward a fully reproducible Debian

Posted Jun 16, 2018 8:07 UTC (Sat) by josh (subscriber, #17465) [Link]

And that's what reproducible builds typically do; they export SOURCE_DATE_EPOCH in the environment pointing to either a commit timestamp or changelog timestamp, and then anything that wants a timestamp uses that date.

https://reproducible-builds.org/specs/source-date-epoch/

Toward a fully reproducible Debian

Posted Jun 19, 2018 6:18 UTC (Tue) by k8to (guest, #15413) [Link]

Hooray!

Glad our armchair commentary is already addressed.

Toward a fully reproducible Debian

Posted Jun 15, 2018 23:20 UTC (Fri) by hmh (subscriber, #3838) [Link]

git commit ids might not be trivially sortable, but "git describe" output can be made to be. OpenWRT (openwrt.org) has been doing that for quite a while, look at how they do it if you're curious.

But that doesn't even matter: you can just use the timestamp of the vcs commit, and embed that instead of wallclock time wherever you need reproducibility.

Toward a fully reproducible Debian

Posted Jun 16, 2018 14:17 UTC (Sat) by pizza (subscriber, #46) [Link]

That requires a commit to be preformed every time one builds, which I prefer to not do until it at least passes local smoke testing. That workflow is also not how most software is actually developed.

In my experience supporting users, it's quite useful to have both an actual source "timestamp" (actually, two -- one that is derived from revision control at compile time, and another that is derived and fixed when the source was snapshotted/released) plus a build timestamp.

Saves a lot of going back and forth.

Toward a fully reproducible Debian

Posted Jun 16, 2018 16:02 UTC (Sat) by niner (subscriber, #26151) [Link]

In Rakudo Perl 6 we use a hash of the whole source tree to get the "has it changed in any way" information. This replaced timestamps and is even more precise.

Toward a fully reproducible Debian

Posted Jun 18, 2018 12:45 UTC (Mon) by error27 (subscriber, #8346) [Link]

The time stamp tells you very little. Most of the time a git commit works fine and a + character on the end to show it has
been modified locally. That actually gives you more information than just the time stamps.

Toward a fully reproducible Debian

Posted Jun 18, 2018 13:07 UTC (Mon) by pizza (subscriber, #46) [Link]

> The time stamp tells you very little.

And I'm saying (for a third time) that this "very little" is still quite useful in certain contexts.

> Most of the time a git commit works fine and a + character on the end to show it has
been modified locally. That actually gives you more information than just the time stamps.

That only tells you if something has been modified since the last commit, which is simultaneously more info, and less info, than a simple build timestamp can provide.

Toward a fully reproducible Debian

Posted Jun 18, 2018 15:02 UTC (Mon) by johill (subscriber, #25196) [Link]

You could still put a git commit + timestamp if modified, or just plain git commit if unmodified, I guess?

Toward a fully reproducible Debian

Posted Jun 21, 2018 0:19 UTC (Thu) by Comet (subscriber, #11646) [Link]

As an example of the utility: letting applications link against libraries which backport security fixes detect the existence of updates.

For instance, immediately post-heartbleed I wrote an nginx module `nginx-openssl-version` which lets you make into a runtime configuration error a situation where the loaded version of OpenSSL is too old. For various deployment scenarios, I was facing people messing with builds without understanding them and knowing that if nothing was done, we'd regress the Heartbleed fixes. For stuff we deployed, we just included new versions of OpenSSL and were able to pick up off version numbers. Yes, this did save us at least once, thanks to the predicted less-than-informed tinkering.

After publishing the code as open source, the very first issue filed was Debian/Ubuntu support, because those distributions were backporting security fixes and not changing the version number. Frustrating for me, but fair for their goals, with the limits of the version numbers they could propagate through the library. But ... there was a library build date. So the first feature developed after publication was "be able to enforce a minimum build timestamp". Cue happy Debian/Ubuntu users.

Reproducible builds are just fine: the OpenSSL code gets patched, the reproducible timestamp gets updated, everyone's happy. There would only be an issue if a patch were applied in 2018 but the code still claimed that it was built in 2015.

From the other side of the fence, it was fairly simple to adapt even Exim's codebase to be able to use `$SOURCE_DATE_EPOCH` if found in environ during build; this was committed in 2017-04.

Toward a fully reproducible Debian

Posted Jun 15, 2018 23:09 UTC (Fri) by Karellen (subscriber, #67644) [Link]

Actually, now that I think about it, I'm pretty sure that build-time time-stamps are only fixed if the SOURCE_DATE_EPOCH environment variable is set - and is set to the date stored in that variable. If you don't set that, e.g. during development builds, you should get "honest" timestamps as before.

https://reproducible-builds.org/specs/source-date-epoch/

Toward a fully reproducible Debian

Posted Jun 16, 2018 2:09 UTC (Sat) by pabs (subscriber, #43278) [Link]

In general, timestamps should be removed or replaced with timestamps based on the date the source changed. SOURCE_DATE_EPOCH is only a workaround for situations where build timestamps cannot be removed (like in on-disk formats that contain timestamps).

Toward a fully reproducible Debian

Posted Jun 16, 2018 2:01 UTC (Sat) by guillemj (subscriber, #49706) [Link]

The build-time timestamp updates *on-disk* are not banned, nor discouraged. This is actually the inverse, not doing so would break a ton of stuff. What we do is clamp those timestamps when generating the resulting artifacts to a fixed one that gets increased at controlled times (usually during the package release process, and recorded in the debian/changelog, passed over via the referenced SOURCE_DATE_EPOCH spec). In case of dpkg and Debian that includes at least .deb ar members and its tar archives within, or any other timestamp embedded in the included files by the various other tools, which have been improved to support that spec.

Having a changing timestamp in the resulting files makes no sense, as has been mentioned here. But something I've considered important it still recording the build time because that tracks information that is otherwise more difficult to get now. This information is not really relevant for the generated artifacts. But it helps track events that are initiated externally to the contained build-environment. Say, data-corruption in the filesystem, an accidental file removal, etc.
and that's why we still record it out-of-band (see the Build-Date field in <https://manpages.debian.org/sid/deb-buildinfo>).

Toward a fully reproducible Debian

Posted Jun 16, 2018 2:06 UTC (Sat) by pabs (subscriber, #43278) [Link]

The build timestamps just moved into the .buildinfo files.

Toward a fully reproducible Debian

Posted Jun 15, 2018 21:30 UTC (Fri) by josh (subscriber, #17465) [Link]

> security packages with signing keys such as secure boot

For this case, the binary being signed should still be 100% reproducible, and the signature should be in a verifiable format using a documented public key.

Toward a fully reproducible Debian

Posted Jun 15, 2018 21:36 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

Not if you use something like an HSM to store the private key.

Toward a fully reproducible Debian

Posted Jun 15, 2018 21:41 UTC (Fri) by josh (subscriber, #17465) [Link]

You can and should still provide the corresponding public key, and document the signature format, so that people can verify the signature themselves as well as verifying that the rest of the binary is 100% reproducible aside from the signature.

Toward a fully reproducible Debian

Posted Jun 16, 2018 15:30 UTC (Sat) by Lennie (subscriber, #49641) [Link]

I wonder if any proprietary company even comes close to doing something like this, if so I've never heard of it.

Toward a fully reproducible Debian

Posted Jun 16, 2018 19:38 UTC (Sat) by smoogen (subscriber, #97) [Link]

Software that was to meet Orange Book A ratings supposedly had build systems like this. Similarly deep space satellite and similar systems usually had build systems like this because you might be rebuilding the OS for the device decades later and needed to make sure it was exactly what you put in the lander.. even if the original PDP-11 it was designed on wasn't around. However those were limited commercial environments and also done in ways which were different from this.. so the similarity is probably about as much the way I described it :)

Toward a fully reproducible Debian

Posted Jun 17, 2018 20:38 UTC (Sun) by jani (subscriber, #74547) [Link]

Yes, some security evaluations require you to be able to check out the project from version control and build the exact same thing again. ITSEC/TCSEC in the past, I believe certain protection profiles in the Common Criteria as well. The companies doing this stuff generally don't make much noise about it.

Also companies masking their software to ROM typically would like to be able reproduce the builds. I've used a build system for ROM masking that allowed you to fix bugs in EEPROM afterwards, taking into account what's in ROM in the build. I don't know how common that was, but it felt pretty cool at the time.

Reproducible builds aren't a new thing, nor a specifically open source thing.

Toward a fully reproducible Debian

Posted Jun 20, 2018 21:41 UTC (Wed) by Lennie (subscriber, #49641) [Link]

Thanks for your answer. That was the sort of info I was looking for.

Toward a fully reproducible Debian

Posted Jun 19, 2018 6:20 UTC (Tue) by k8to (guest, #15413) [Link]

In my experience, we lose the ability to build the older versions entirely, let alone reproduce the result.

Toward a fully reproducible Debian

Posted Jun 28, 2018 9:01 UTC (Thu) by njs (guest, #40338) [Link]

Vesta is a old combined VCS and build system based around this idea [1].

It's an interesting system. It's designed to allow for strict tracking and reproduction of arbitrary build artifacts, e.g. they want the guarantee that if someone says "hey I noticed a problem with this build from 10 years ago, it says it's #1039828?" then they can hit a button and reproduce build #1039828. So it has to be a VCS, so it can track the source corresponding to each build. It also expects you to check in your compilers etc. to source control (so it can find them later), has its own language for describing builds (so it can track provenance through the build), and exposes the source tree through a custom filesystem API (so it can run builds inside a chroot where it has complete control over all the files visible to the build tools).

Compaq and then Intel used it very heavily for a long time, for developing chips. (Maybe they still do?) This is an environment with incredibly complex custom build tooling that evolves over time (for a modern general purpose CPU, you don't design the chip, you design software that designs the chip), with multiple gigabytes of output on every build, test suites that can take weeks or months to run, shipped products that are supported for many years, and where a minor bug slipping through can cost $475 million [2]. So there's a *very strong* motivation to track *exactly* what you are testing and shipping, and Vesta's trade-offs make a lot of sense. I don't know if any more traditional software shops ever picked it up though.

Google's blaze/bazel systems solve a lot of similar problems for similar reasons, though AFAIK they don't bother aiming for bit-for-bit reproducibility. I think Facebook's buck is in a similar space too.

[1] http://www.vestasys.org/
[2] https://en.wikipedia.org/wiki/Pentium_FDIV_bug

Toward a fully reproducible Debian

Posted Jun 18, 2018 5:41 UTC (Mon) by Fowl (subscriber, #65667) [Link]

Great work, a credit to the whole team!

Toward a fully reproducible Debian

Posted Jun 18, 2018 8:31 UTC (Mon) by nim-nim (subscriber, #34454) [Link]

While wonderful, this endeavor only addresses half of the problem.

Making sure you can rebuild perfectly only helps so much if you don't have any update path to fix problems in your perfectly rebuilt software (it may rebuild perfectly but it is never perfect as a whole). And the natural bend of a dev you're asking to produce anything that can be rebuilt perfectly is to set in stone the versions of all components, make lists over lists of exact git hashes, locking down everything so much:
1. it's a major PITA to update any of the used software components
2. the actual component states used in each software start to drift, since everyone locks down different versions
3. that in turn increases the amount of versions that would need to be audited to make actual used of the perfectly rebuilt software ecosystem

So you end up with something that one could audit in theory (because you're sure the result can be reproducible, making the audit worthwhile) but that no one will audit in practice (too much version drift resulting in too many individual components versions that need actual checking).

Toward a fully reproducible Debian

Posted Jun 21, 2018 1:48 UTC (Thu) by smcv (subscriber, #53363) [Link]

When a source package is compiled into binary packages, the Debian package build infrastructure now records the dependencies and toolchain that were used in a .buildinfo file accompanying the build (which is not required to be reproducible - it includes things that we hope do not alter the binaries, like the wall-clock date and time). The assertion is that if you match the dependency versions etc. from the .buildinfo (let's say D1), *and* use the same source code, you should get the same binaries (let's say B1).

There's no requirement that the complete dependency chain gets recorded in the source package: the dependencies etc. recorded in the .buildinfo file are a secondary input to rebuilding. Normally you'd only rebuild using the same dependencies D1 if you wanted to test the claim that the binaries B1 from Debian were really built from the source code we claim they were: the idea is that if you rebuild a small arbitrary sample of packages and get the same answers Debian did, you can have reasonable confidence that the rest have also not been tampered with (because in the presence of even a fairly small proportion of rebuilds, an attacker substituting builds from maliciously modified source code can't be confident that their attack will remain undetected), without having to spend the resources to rebuild *everything* for yourself.

If you want to build that source code against different dependencies D2, you're welcome to do so (subject to the same restrictions about compatible versions that always existed). You can't necessarily expect the binaries to be identical to B1 (for instance if you use a different gcc version it will probably generate different code), but if what you get when using D2 is B2, and the package is reproducible, then you can expect that someone else rebuilding the same source code against D2 will also get B2.

livecd/dvd/usb automation

Posted Jul 16, 2018 1:12 UTC (Mon) by Garak (guest, #99377) [Link]

So you end up with something that one could audit in theory (because you're sure the result can be reproducible, making the audit worthwhile) but that no one will audit in practice (too much version drift resulting in too many individual components versions that need actual checking).
To get sufficient audits in practice I think merely requires ordinary automation refinement. I don't see it as an overly challenging problem for a distribution to provide a livecd/dvd/usb image that when booted, has a zero/one button automated process to verify the distro release via the generation of identical packages. Braindead pushbutton automation is the key. Seems like we'll get there sooner rather than later, good to see people keeping the dream alive. I.e. i hope that within a few years we might see each debian/fedora/etc pointrelease come with a verification livedvd release, that combined with a pile of as many source packages as the verifier wants to verify, can trivially verify the shipped bits of the vendor.

Given the Snowden revelations of five years ago, I really wish this was already in place, but I guess the arc of progress through history, while bending slowly, does seem to bend towards what was obviously the right answer all along.


Copyright © 2018, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds