build.rs by design can run absolutely anything. There tons of build.rs scripts that invoke a whole-ass C compiler toolchain to build and link C dependencies...

It isn't so much a question of sandboxing build.rs, as fundamentally changing the way that foreign dependencies are integrated into the rust toolchain (i.e. moving from a rust-centric system like Cargo to something more general like buck2)

Worth noting that the JVM ecosystem doesn't have this issue because there is no notion of installing dependencies, and the package managers are just downloaders with nothing else. No build.rs equivalent.

To solve the problem of native/C dependencies, they just bundle pre-compiled libraries as data files.

Rust could do the same thing.

But then that shifts the issue. You've now got an opaque binary blob being injected into programs. What if it is malicious?

It may or may not be a problem depending on whether it's actually used, which is still better than "gets you instantly the moment you compile the app". A lot of codepaths and even whole libraries aren't invoked just because a program depends on them.

It doesn't really matter anyway, because nobody is reading anything in their dependencies before it gets downloaded. Malware can also be hiding in plain sight in source code, as this attack and many others shows.

ABI stability is significantly different in a VM language to a native language, and reified generics necessarily require source compilation. Binary-only development for Rust would be exactly as 'sort of not really' as C++, for exactly the same reasons. (There is also no notion of 'installing' dependencies in Rust, and build-time code being malicious isn't much worse than runtime code being malicious.)

But people say build.rs is used mostly to compile C dependencies, in which case the lack of ABI stability of Rust is neither here nor there.

The vast and overwhelming majority of build scripts are building C code, so the other solution is to move away from integrating with C dependencies to native Rust dependencies, in which case adding friction to build scripts would be less noticeable.

Just denying write access outside the build directory and denying network access would go a long way and won't break pretty much any well-behaved build systems.

Any C library that's also packaged by debian supports being built under these conditions because it's required for everything except non-free packages: https://www.debian.org/doc/debian-policy/ch-source.html#main...

> Just denying write access outside the build directory and denying network access

As the link you posted mentions, you need a tiny bit more than that: you also need write access to the temporary directory (/tmp and similar). Many build tools temporarily store files there; for instance, unless things have changed since I last looked, if you don't use the -pipe argument the C compiler stores its temporary intermediate files (preprocessor output, assembler input) there.

One of rust's strengths is it's ability to interface relatively easily with existing c code without having to rewrite absolutely everything in rust. I don't think that is something we want to give up.

build.rs changes nothing about how easy it is to integrate with C. What does simplify: figuring out how to supply library you need at build time.

Which is the result of how bad dependency managment is outside (i.e. DLL-hell).

Pretty much all other use cases of build.rs can be sandboxed. Well, there is sqlx that wants to connect to database at expansion time to compile check-queries (yew).

sqlx at least has the (optional) offline mode, where you "cargo sqlx prepare" once (which wants access to a db) and then you can build in offline mode which typechecks your queries against local files.

Although I suppose that's still doing a lot of shenanigans at compile time. It could be sandboxed pretty well (theoretically). I'd hate to give it up completely though, getting a compile time error when SELECT query params or return values have type mismatches is extremely nice.

sqlx offline mode being opt-in instead of default is what bothers me. You know what else can validate that your queries return what you expect? Integration tests. Shoutout to sqlx for #[sqlx::test] though.

I also wish that it would be the default. Integration tests are fine, but they aren't compile time. Elevating them to compile time and using an LSP enabled editor makes it just underline SQL errors before I've even had a chance to run a manual compile let alone a test...

LSP diagnostics is actually what made me switch from compile time check queries. Whole "is db up? are migrations applied?" dance tired me pretty quickly. Its fine if you use sqlite, but anything else gets annoying.