Anyway, many kudos for this work!
From the perspective of an application developer I want that dynamic representation to also be predictable.
hathawsh meant representation in the sense of memory layout and other low-level details of how application state is encoded. You seem to be talking about the programmer-visible abstractions built out of that layer. Behaviour at that level has to be predictable in order to "maintain correctness", but predictability at the lower level is mostly a help maintaining for the correctness of malware.
There is so many things based on Debian and adding reproducibility in Debian is a massive security improvement.
I have a lot of respect for people working on this, it must be hard to respect release freezes when you've been working on this for years.
From the article, it looks like many of the others are reproducible on a code level, but the release system is using older binaries, which haven't been rebuilt yet.
It's too bad it won't be fixed in time for this release, but bodes very well for future releases.
Edit: found this nice overview by clicking a few links from the original post https://reproducible-builds.org/
if I cant run the build process, and I dont really know which patch sets have been applied on my system, and which version of the source was used, and I dont really have a handle on the dependencies. doesn't make it substantially more difficult to debug and work with the resulting system?
its really quite odd that the dominant open source platform settled on opaque and unreproducible binaries as the distribution mechanism early on.
So, best use of time would be one of three activities:
1. Gradually rewriting apps or kernels in safe languages. Can even make stuff reproducible as a side effect of rewrites.
2. Improving tools like SAFEcode snd Softbound+CETS that make C code safe. Esp usability and packaging. If not that, then more mitigations in OS like OpenBSD does. Can even port theirs.
3. Running static analyzers, fuzzers, etc on all that code out there. Then, fixing the vulnerabilities. Id say prioritize highly-priveleged and newest code.
That would actually improve the security of Debian against the kind of attacks that hit it the most. There's some people doing this. Not enough by far.
I would envisage it working in the following way. The developer submits links to their code and links to their package. The service builds from code and checks if the final package matches what is being distributed by the developer. If yes, it then publishes the hashes of the code and package, so users can quickly check that they are using a reproducibly built package from the correct source.
https://ssl.engineering.nyu.edu/blog/2019-01-18-in-toto-pari...
https://salsa.debian.org/reproducible-builds/debian-rebuilde...
https://github.com/in-toto/apt-transport-in-toto
https://reproducible-builds.org/docs/sharing-certifications/
This allows users to verify that the binary packages you see were actually gotten by compiling the source code (presuming your compiler isn't compromised). This means that auditing the source-code is almost as good as auditing the package (the exception being compiler mistakes). Thus, we need less trust in the software packagers.
You can do this with Bazel and Buck and with a few assumptions and some configuration even with Gradle.
Which means someone has to build and upload those binary packages.
How can you tell that the person who built or hosts the binary packages didn't change the source code (for example, putting in backdoors or other malware)?
It helps with this problem if anyone else can build the same source code, and get a byte-for-byte identical copy of the binary package.
This sounds trivial, but it actually requires some dedicated support from build tools and build scripts. (You have to have the exact same version of the compiler and everything else, the compiler wants to automatically put the build timestamp in the executable, the order the OS lists files in a directory can sometimes change, the timestamps in files contained in tar/zip archives can't be set to the current time, etc.)
Some people in the Debian community have been making an effort to update all of Debian's packages to be byte-for-byte reproducible.
Go in and vote for it anyway. I'm sure some of the Debian packages are written in Java. ;-)
For example the ISO file system, typically ISO 9660 or UDF, will have a volume UUID from a random number. Sure you can code a flag for mkfs to specify a fixed number, that's easy. But then next that ISO typically contains a payload in the form of a squashfs file. And quite a bit of work on squashfs has happened to make sure file timestamps can be set to a known value. However, if one build process uses xz level 3 compression, and another build process uses xz level 7 compression - hashing will of course fail. The point is, be it inode UUIDs and timestamps and compression levels, there's a lot being measured that we don't really care about, just to have a simple verification method at the back end.
I never figured out a maintainable scheme. Some of my packages are in /opt, some are in ~, some in ~/local, and some under GNU stow. And other than GNU stow's half-assed uninstall method, it's always a pain in the neck when I have to remove or upgrade any of these packages.
If there’s no newer package available you can try to reuse the debian directory from the older source package to build from the newer source.
Sometimes this works in the first attempt, but if you need this for a lot of packages, it’ll be a lot of work.
* output is deterministic but dependent on some aspect of the build environment (locale, hostname, etc)
* output is accidentally non-deterministic (eg "we put all the .html files into a tarball with a shell glob pattern, which gets you an order dependent on your filesystem implementation and the phase of the moon")
* a wide array of "output contains a timestamp" issues
"Let's put the timestamp into our version string/a generated file so the user knows when it was built" is a really common thing, and it seemed like purely a nice convenience feature until the concept of 100% binary-reproducible builds became a current concern.
That's like saying, "why did you introduce entropy?" It's there. It happens, and it's difficult to get rid of in any complex system.
https://en.wikipedia.org/wiki/Reproducible_builds
https://wiki.debian.org/ReproducibleBuilds
https://www.win.tue.nl/~aeb/linux/hh/thompson/trust.html
Debian was one of the first large distributions to use a build farm for many different architectures. Maintaining deterministic builds (even as far as just file timestamps) in a distributed environment is very challenging.
If you mean which distribution has 100% of its packages reproducible, probably none yet. But Arch and Debian are both making progress.
OS-wise, NixOS.
Build system-wise, there are lots of options: Blaze, Buck, Pants, Please (AFAIK)
If you build the same code on two different machines, using the same compiler, with the same options, then the generated binaries should be exactly the same.
These problems can also cascade, if component A embeds the hash of another component B, e.g. to verify that it's been given a correct version. If that hash comes from an unreproducible upstream, and building it ourselves gives a different hash, then we'll need to alter component A to use that new hash. That, in turn, changes the hash of component A, which might be referenced in some other component C, and so on.
Look at windows. Even if you fix the compiler and linker, you still non-reproducibility by design, the PE header contains a timestamp.
People also like to stick non-reproducible stuff into builds directly, like timestamps.
Compilers don't have any reason to lay down data in a specific order, so if they are threaded in the backend they just don't.
IDL tools might stick in the timestamp of when a file was generated, for convenience.
and on and on and on.
Once you make the sensible choice to include build time in the result you've broken reproducibility. Fixing this means tracking down every package that does this and removing the timestamp.