-
Notifications
You must be signed in to change notification settings - Fork 2
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
rust-lang build not reliably reproducible (relying on pre-compiled binaries, insufficient checksum checks) #3
Comments
I understand your motivation to have it the same way as other OpenWrt packages. I just think that you're comparing apples and oranges. Let me elaborate. You're comparing it with GCC but the thing is that there are no official builds of GCC with all possible combinations of C libraries and other environment choices (like kernel headers etc.), so it really is necessary to build it from scratch. On the other hand, Rust, as a compiler, is always the same (regardless of the target environment) and there are official builds available + official builds of the standard library for a lot of platforms (including arm/aarch64 + MUSL). If we compare it with other languages/runtimes that you use, for example Python and Node.js, then it also makes sense to build those from scratch because you need a runtime for the target architecture. Rust has no runtime. The only target-specific part of the Rust toolchain is the standard library and there are official builds available for every version of Rust and for many target architectures. The standard library itself (parts of it) is then statically linked with the resulting binary along with all the application dependencies downloaded by cargo.
The Rust package from this repository can be easily used to build also other Rust applications. You don't need to build the Rust compiler from its source in order to build other apps.
TLS does more than that. TLS also guarantees integrity of the transferred data, so as long as you trust that the remote server will give you the binaries that you asked for (which it does in this case) and as long as you trust that the server hasn't been compromised, you'll get the same binaries every time. This is pretty much the same guarantee that you have for all those dependencies downloaded via Python's pip, Node.js' npm or Rust's cargo. I guess that you don't have static checksums for all those dependencies in your Makefiles, or do you?
And are you really sure that downloading sources at one time and building them at another time works in your case? How about all the dependencies downloaded via language specific dependency managers (pip, npm, cargo) during the package build?
Yes, it does. As I mentioned, if you trust that the server used by rustup hasn't been compromised and that the server will give you the binaries that you ask for (which is the server's purpose), you will get the same set of binaries every time, so the only difference between downloading sources and binaries is that the first is human-readable and the second is not. :) If you don't have this trust then you're screwed because you already face the same problem with dependencies downloaded via pip and npm. TL;DR If you insist on building the Rust toolchain from sources, I can update the package once I find some extra time. But given the fact that there really aren't many benefits in doing it, I'd prefer investing my time into something that actually makes sense. Please note that building Rust from sources can easily take more than 60 minutes (this was the case the last time I had to build it), so it can really be painful. If you decide to build Rust from sources, you should also know that Rust is a bootstrapping compiler (you need a Rust compiler to build a Rust compiler), so there will always be some binaries that need to be downloaded. It works the same way as GCC (you need GCC to build GCC). |
Here is a small follow up regarding the Rust bootstrapping procedure I mentioned before: https://rustc-dev-guide.rust-lang.org/building/bootstrapping.html#stage-0 Theoretically, it should be possible to download Rust installation package from here, verify its checksum and use it for bootstrapping the build from source. But I haven't tried this before, so I'm not sure if that would be feasible. I also cannot guarantee that the build script won't try to download anything else during the build. So as you can see, you cannot avoid downloading binaries. Anyway, this still does not solve the problem with downloading dependencies via cargo during the build of the angelcam-connector package. But if the main concern here is allowing offline builds, we could run |
Hi, Some issues I ran into with By default, The arguments about using pre-compiled binaries. I've got no opinion either way how anyone can/should handle that issue. If you're interested, these are some of the arguments I tangled with when I was looking at the project at the beginning. If you are source building everything (including the LLVM), which is how I'm doing it, it does download a pre-compiled The compromise was building from source (since I had to anyway for the custom tuples) and using the pre-compiled to bootstrap If a security issue was discovered, the entire thing gets rebuilt on the update for it anyway under the way I do it. Since I will be changing the Looking quickly at the Turris github, in theory, Turris probably also suffers from the same Feel free to ping me if you need another set of eyes on an issue. I might be able to help (or at least tell you how I previously failed at it to save you time). |
Hi @Grommish! Thanks for the insights.
Yes, that's a known issue. It can be easily dealt with using the
Building every version of Rust just to have a "clean" bootstrapping chain would be insane. There have been 61 versions of Rust so far + bugfix releases. But guess what! It does not end there. The very first version of Rust was written in OCaml, so you'd also have to build OCaml. OCaml is implemented in C + OCaml. I'm not sure if it's also a bootstrapping compiler but that isn't important. We can use GCC to build/bootstrap OCaml but can we trust the GCC on the build host? Why should we?! Let's bootstrap also GCC all the way from the very first version implemented probably in assembler 😄 I hope you can see how ridiculous this is. In my opinion, we can trust the official Rust releases as much as we trust the GCC on the build host. Sure, we can be paranoid and download a standalone binary release from here and verify its checksum instead of using rustup. Then we could use this binary release to bootstrap our own build of Rust. But bootstrapping Rust all the way from the very first version? That's insanity :)
JFYI you don't have to build Rust just because you use custom targets. You can use the build-std feature together with a custom target specification in JSON. Even though it's still nightly, it works reasonably well. I'm using it in several Buildroot-based hobby projects targeting quite obscure architectures and everything works fine so far. Of course, we could argue that using Rust nightly channel isn't a good idea for production releases, so building Rust from source would still make sense for architectures that are not available using rustup.
I'm quite sure that rustup currently covers all targets used by Turris.
Yes, I'm aware of that. Unfortunately, there are more problems then just the ARM ISA versioning. OpenWrt also messes up the target ABI which is quite unfortunate. For example, the GNU target for Turris Omnia is
There can be exceptions for various |
The way I ended up dealing with it was via https://github.com/openwrt/packages/pull/13916/files#diff-6b866d23e2208710b2de3c36ab1ec8111be9a84c88aef41ff2bc1ead81031773 This outlines the logic I use to split out target logic, it also allows me to call CodeGen I use
Very much so! I just wanted to point out the push-back I received about pre-compiles. I didn't find it in any way feasible to build up from scratch, either, but I'm sure if someone hasn't already brought it up here, it would be sooner or later. |
Cool. That's some serious work you've done. I'd be happy to switch our angelcam-connector package to the official OpenWrt Rust package once it's in the upstream. And we can also drop our rust-lang package then. I believe the current solution will work just fine until then. cc @autobakterie |
Thanks.. It does work, integrates well, and has the ability to build the distribution archives, which is how I was doing it prior to just installing it to the build system directly. My biggest issue is the fact my testing device is a mips64, so while it works, I can't personally vouch for other archs. I've been working through issues to my test packages to figure out if it's the build system, the rust install, or the package itself. Rust/Cargo applications that use As I said before, I'm not trying to influence anything being done. There's no assurances OpenWrt will ever merge rust-lang into the official build system, but it'll be there if they decide to. I would have loved to use My goal was to have
I'm not sure what |
Clarification: Builds on OpenWrt master branch using my rust-lang toolchain. So, it builds, and helped me with an issue I hadn't been able to previously diagnose regarding duplicate definitions. I'm still not quite sure what the arrow package is for, but at least builds. |
It's a service for connecting IP cameras from your local network to Angelcam Cloud. See https://github.com/angelcam/arrow-client and https://angelcam.com if you're interested. |
Ah, I've got no way to test it then. Anyone willing to test the ipk output and ensures it actually works with my rust implementation, since I can't? I'm more than happy to generate a target-specific arch ipk. Mostly I"m interested in testing the package to ensure I still don't have issues with xxxx arch. |
I can test it on Turris Omnia and Turris MOX. Those are |
angelcam-connector_0.10.1-1_aarch64_cortex-a53.ipk.gz
The above ipk was |
I went on the assumption that the original
|
@Grommish I can't install the package because Turris probably uses different names for some dependencies (the package depends on libpcap1 and libopenssl1.1 but these packages are available as libopenssl and libpcap in the Turris OS). But that's not the main problem here. I was able to extract the binary from the package and test it anyway. Unfortunately, it does not work because the binary depends on incorrect dynamic linker lib. It depends on This is the output of
And this is an ldd output for a different binary:
Of course, if I create a symbolic link from I had a similar issue with our rust-lang package. The problem was that when MUSL was being linked statically, the resulting binary contained path to an invalid dynamic linker lib. Adding |
Sorry for the close and reopen ping. That was a misclick. First to the original reply:
I acknowledge there are additional reasons to build other languages' toolchains from source which are not relevant to the Rust toolchain, but that doesn't mean they are the only reasons.
Well, I certainly can build other apps using precompiled Rust toolchain. What I wanted to imply by 'easily' wasn't just the possibility of building. It was also the reliability which, as I see it, isn't really provided by the current rust-lang package 'compilation' process. It's based on binaries and not checked against static checksums at the same time. Neither is considered good practice for any OpenWrt package. I would expect a compiler toolchain package other packages should rely on to be more robust.
What you describe is just what I meant - relying on TLS == trusting the download server - which extends the attack surface unnecessarily.
We actually do, I think, for most of them, at least. See all those *_HASH definitions in Python or Node related packages Makefiles. If you find a Makefile downloading the source without checking the hash (should be done automatically by the build system if the corresponding *_HASH variable is specified), don't hesitate to create an issue. It should be checked. For reference:
Yes, those pip packages are problematic in this regard.
As I said - I do not trust the server; those pip and npm packages are being checked against static checksums as well. I consider the preference of sources over binaries to be an unrelated issue - having integrity checked is important in both cases. Sources then make the build process more transparent and as we are developing a security-focused Linux distribution based on free software, maintaining maximal reasonable transparency is quite important to us. Regarding the followup too: Building everything from source using a precompiled bootstrapping binary seems to be the way many other Linux distributions (e.g. Debian, Fedora) choose. |
Ok. Thank you for your response @autobakterie. Let me summarize it as I see it and feel free to correct me if you see it differently.
Regarding the dependencies downloaded by cargo - there is a checksum for each dependency in the lockfile, for example:
I assume that cargo uses it to check downloaded dependencies. So I guess that this should be enough for you, is that correct? Since Grommish is working on the official Rust package for OpenWrt, I don't see much sense in duplicating his effort here. I'd be happy to switch the angelcam-connector package from the rust-lang package in this feed to the official OpenWrt package once it's available. So my question is if you're OK with leaving the rust-lang package in this feed to use rustup or if you want me to change it according to the description above. |
I see some problems in the way the Rust toolchain is obtained by the rust-lang package. Description of the problems in form of a continued #2 conversation follows:
Even if I might not want to (I think I believe you), it is the way how other parts of the OpenWrt toolchain (GCC, ...) are made, it is transparent and would be really nice to have.
It would not be so bad if the build time was the only issue. We are already building whole package feeds at each release, so the time added for Rust toolchain build probably wouldn't hurt that much and/or would be worth the possibility of running Rust software easily on Turris OS and OpenWrt routers.
Nevertheless, downloading the binaries might be an acceptable temporary solution as long as their integrity is reliably checked.
Adding a thread related to the current state of an effort to add Rust support to the OpenWrt build system for reference: openwrt/packages#13916
It would be nice if rustup of a particular version guaranteed concrete checksums of consecutively downloaded binaries, but I cannot see this being the case.
According to https://rust-lang.github.io/rustup/security.html , the referenced issues ( rust-lang/rustup#2028 , ... ) and the rustup-init.sh itself even the rustup binary downloaded by rustup-init.sh is not checked to have any static checksum (the only check is done by TLS and just makes sure the binary comes from the desired server).
By determinism, I mean that the packaged software will be based on exactly the same source files each time it is built.
This can be accomplished either by the source archive (that has its SHA256 checksum fixed in an OpenWrt Makefile variable) being sufficient for the build without additional downloads or by all the downloads being reliably checked against static checksums specified in the archive.
The first option is preferred by me and my colleagues in TurrisTech because it allows for rebuilding the package at any time once its download phase was completed no matter the availability of original sources at build time. It is then possible to download sources of all the packages at one time and build them all at any other (any build can then be reproduced at any future time if the downloaded sources are archived).
The second option would at least maintain the transparency and some degree of reproducibility of the build process. Unfortunately, rustup does not provide this kind of determinism either.
I know packaging Rust properly for OpenWrt is far from an easy task, but that, unfortunately, does not make improperly packaged one and the dependent packages easy to maintain.
The text was updated successfully, but these errors were encountered: