4 ms·
Ultimately you're going to have to be adept at stuff like the Underhanded C Contest to spot this kind of thing in any Turing-complete language, so the idea of a
by tadfisher 3y ago
Ultimately you're going to have to be adept at stuff like the Underhanded C Contest to spot this kind of thing in any Turing-complete language, so the idea of auditing the source is unreliable at worst. So I'd take another page from the Java/Maven ecosystem and require hashed+signed binaries, with the possible addition of requiring builds to be performed on a trusted remote host so that at least we can verify the binary is produced from the same source and results in the same output.
But determined actors with access are always going to try to thwart these schemes, so verification and testing is going to need to step up.
- naikrovek 3y agoreproducible builds never made sense to me. if you trust the person giving you the hash, just get the binary from them. you don't need to reproduce the build at all. if you trust that they're giving you the correct hash, but not the correct binary, then you're not thinking clearly.
- emn13 3y agoOne thing a culture of reproducible builds (and thus stable hashes) however does provide is a lack of excuse as to why the build isn't reproducible. Almost nobody will build from source - but when there's bugs to be squashed and weird behavior, some people, sometimes, will. If hashes are the norm, then it's a little harder for attackers to pull of this kind of thing not because you trust their hash rather than their blob, but rather because they need to publish both at once - thus broadening the discovery window for shenanigans. To put it another way: if you don't have reproducible builds and you're trying to replicate an upstream artifact then it's very hard to tell what the cause is. It might just be some ephemeral state, a race, or some machine aspect that caused a few fairly meaningless differences. But as soon as you have a reproducible build, then failure to reproduce instantly marks upstream as being suspect. It's also useful when you're trying to do things like tweak a build - you can ensure you're importing upstream correctly by checking the hash with what you're making, and then even if your downstream version isn't a binary dependent on upstream (e.g. optimized differently, or with some extra plugins somewhere), you can be sure that changes between what you're building and upstream are intentional and not spurious. It's clearly not a silver bullet, sure. But it's not entirely useless either, and it probably could help as part of a larger ecosystem shift; especially if conventional tooling created and published these by default such that bad actors trying to hide build processes actually stick out more glaringly.
- rstuart4133 3y agoActually, this xz-utils was a sort of reproducible build issue. But the twist it is wasn't the binary not built reproducibly. It was the tar ball. The natural assumption is it just reflected the public git repository. It didn't. Debian's response is looking to be mandating the source must come from the git repository, not a tar ball. And it will be done using a script. And the script must produce the same output every time, ie be reproducible. Currently Debian's idea of "reproducible" means it reflects the source Debian distributes. This change means it will reproducibly reflect the upstream sources. That doesn't mean it will be the same - just that it's derived in a reproducible way. As for trusting the person who gave you the hash: that's not what it hinges on. It hinges on the majority installing a binary from a distro. That binary can be produced reproducibly, by an automated build system. Even now, Debian's binaries aren't created just once by Debian. There are Debian builders all around the planet creating the binary, and verifying it matches what's being distributed. Thus the odds of the binary you are running not being derived from the source are vanishingly low.
- naikrovek 3y agoSo if something is hidden in the source, a reproducible build will give you the confidence to believe that the source is fully vetted and clean. I see what you’re saying, but I don’t buy that reproducible builds actually solve anything, especially long term. As this whole xz thing has shown us, lots of things fly under the radar if the circumstances are right. This kind of thing will absolutely happen again. In the future it may not even require someone usurping an existing library, it could be a useful library created entirely by the hacker for the express purpose of infiltration a decade later. Reproducible builds are a placebo. You must still assume there are no bad actors anywhere in the supply chain, or that none are capable of hiding anything that can be reproducibly built, and we can no longer afford to make that assumption. A reproducible vulnerability is still a vulnerability.
- tremon 3y agoYou're focusing on the wrong issue. Just because reproducible builds don't solve all avenues of attack doesn't mean they're worthless. No, a reproducible build does not give you any confidence about the quality of the source. It gives you confidence that you're actually looking at the correct source when your build hash matches the published hash, nothing more. A window that can be smashed in is still a vulnerability, so there is no value in people locking their front doors.
- tripdout 3y agoBut you can build the code yourself, and verify that your hash is the same as theirs, meaning the binary is the same.
- naikrovek 3y agoJust get their binary, then. Why do you need to build it yourself? If you trust the people giving you the hash of the binary, just get the binary from them, too.
- emn13 3y agoIt's easier to hide nastiness in a binary than it is in source. And indeed this XZ hack too relied on multiple obfuscated binary blobs. The hash helps because it makes it a little harder to hide things like this. It's not a silver bullet, but it would have in this specific instance made it harder to hide that malicious m4/build-to-host.m4 in the tarball - after all, had the attacker done that despite publishing a hash they would have needed to use the hash including the modified build script, but then anybody building from the git repo would have had a different hash, and that's a risk for detection. Reproducible builds and hashes thereof aid in transparency and detecting when that transparency breaks down. Of course, it doesn't mean hackers can't hide malicious code in plain sight, but at least it makes it slightly harder to hide between the cracks as happened here.
- naikrovek 3y ago"slightly harder" isn't enough. That's what I'm saying that people are not accepting. The days of 3rd party libraries simply being trusted because they're open source are slowly coming to an end. the problem is not unreproducible builds, the problem is that we implicitly trust source code found online. Projects relying on 100s of 3rd party libraries are a major problem, and no one seems to care. They like it when their Rust build lists all the libraries that they didn't have to write as it compiles them. They like it when they can include an _extremely_ small Node library which itself relies on 4 other _extremely_ small Node libraries, which each rely on another 4 _extremely_ small Node libraries, until you have a node_modules directory with 30,000 packages in it. We don't know how to write software any more. We know how to sew bits of things together into a loincloth, and we get mad when the loincloth makes us itch. Of course it does, you didn't LOOK at anything you are relying on. You didn't stop to think, even for a moment, that maybe writing the thing instead of trusting someone else with it was even an option. As we continue doing this, relying on 3rd parties to write the heavy lifting code, we lose the skill to write such code ourselves. We are transferring the skills that we need into the hands of people that we can't trust, when viewed from a high level. We need to get back to small applications, which we know because we wrote them in their entirety, and that someone else can trust because the code for the thing is 2500 lines long and has extremely few, if any, dependencies. We need to get away from software which imports 30,000 (or even 100) third party libraries with implicit trust because it's open source. "All bugs are shallow with enough eyes" requires that people use their eyes.
- klabb3 3y ago> to spot this kind of thing in any Turing-complete language I’m not sure I follow. The bar for passing review and audits is “people can understand it”, at least to the point of preventing smuggling in a custom public keys and other shenanigans – as opposed to “all valid programs in the language”. While I agree Turing-completeness opens up undeniable complexity, it’s the best we got. And there are huge variations in obscurity across languages and tooling.
- khaki54 3y agoUnderhanded C is meant to create code that is transparent enough to convince the reader that it's obviously and clearly doing one thing, while subtly doing something else.