There's a kind of naive thing going on on HN where peopel see a bug and ask whether or assert Rust will fix it. The problem is they are homing in on just the bugs Rust addresses - this is fine, I've had this conversation at work (not involving Rust, even) for two decades, including discussions about Java.
The problem is that Rust solves _a_ class of issues without even beginning to address other kinds of problems, and so this sort of thinking is evolving toward a mindset that "oh it's rust so no security issues", which is completely wrong.
Unfortunely did not come with an OS, wasn't freely available, and quite costly.
Remeber that until AT&T was allowed to take commercial advantage of UNIX, its source code was available for a symbolic price, and it came with a C compiler toolchain, at least until Sun started the trend among UNIX vendors of spliting UNIX development tools into an additional purchase.
The UNIX vendors that had Ada compilers, that was an additional purchase on top of UNIX SDK (which already had C and C++), so unless there was a hard requirement to use Ada, no one bothered to pay extra.
Indeed. Ada killed itself, partially because it was one of the DoD approved languages and so the vendors got on board with raping and pillaging everything they could, killing the whole thing in the process.
I keep using "mostly safe languages" as kind of abstract term, Rust comes into speech even in scenarios where other alternatives would be a viable option.
I don't think so. Rust solve a class of security issue, but that class is 2/3 of all security issues! That's overwhelmingly more secure.
And it's not like it has no effect on the final third either. The stronger type system and ownership system make non-memory related bugs less likely too.
Your comment makes it sound as if you have a better solution. But Rust is the best one we know so far, so this kind of naysaying does more harm than good.
Naysaying is that these problems can't be fixed in C, this kind of naysaying does more harm than good. Rust merely uses an idea that was known before C even existed.
Do you realize how many security issues exist in applications written in memory-safe Java/PHP/JS/Python ? Memory corruption is but the tip of the iceberg.
You are right that there are software bugs that aren't memory bugs.
Now as GP was saying, Rust inherently mitigates a great deal of generally serious software vulnerabilities, which is great, even if it doesn't mitigate anything else.
The answer is probably yes. The issue is caused by a heap-memory overflow. In Rust, if you're storing an array on the heap then there will be bounds checks on the array access. If you're using a vec then it would automatically grow (so again bounds checks).
So the answer is: Not necessarily. I agree though that the memory safety features in Rust would help reduce the risk. On the other hand, one could also write safer C by abstracting away buffer management. The world is not black and white.
That function was using an unsafe block to disable the bounds check. This kind of bug would likely be impossible in "safe" rust (that didn't use unsafe).
That isn't the use-case for unsafe. If you see a codebase doing this then you should stop paying attention to or using that codebase.
Unsafe is for creating things that are beyond the understanding of the borrow checker. For example, using unsafe is mandatory for creating a mutex because the safety rules are upheld by the data structure itself. Unsafe is not "C mode" as most would assume - it is more unsafe than C because if you don't uphold the memory model things will break.
Rust's strict aliasing and mutability rules provide ample opportunity for compiler optimizations and zero cost abstractions. Turning to unsafe is generally a sign of incompetence/arrogance.
The linked glibc code was likewise being fancy trying to use a stack buffer to avoid a heap allocation. Idiomatic C would have worked just fine too. The point is that Rust is also (though not as severely) subject to developers playing tricks and hurting themselves.
Basically: the code was an optimization trying to avoid a heap allocation by using a stack buffer instead, but its fallback for "it doesn't fit in 1k of stack memory" wasn't tested and didn't work right.
Rust struggles with alloca-style code too, to the extent that users who want to do this kind of trickery usually resort to unsafe. There's a link elsewhere in this topic to a Rust library vulnerability that looks similar.
The upshot is that if the code had been written idiomatically and just used the heap like it was supposed to, it probably would have worked fine. The glibc authors got fancy, loaded a footgun, and it went off, something that Rust is equally capable of.
> Rust struggles with alloca-style code too, to the extent that users who want to do this kind of trickery usually resort to unsafe.
Sort of, but not really. I've done this sort of "if it fits in a small stack buffer, use that, else fall back to heap" in code too. It's possible in safe-ish Rust:
let mut s = SmallString::<[u8; 1024]>::new();
write!(s, "{} frobs for {} widgets.", var_a, var_b)
.expect("writes to a String are infallible");
Safe-ish, because there is an unsafe {} hidden behind the safe interface exposed by `SmallString`. (And that crate has had vulnerabilities against it.)
But that's sort of the point: we're here looking at logging code, and the logging code itself shouldn't be doing this sort of unsafe trickery, it should be using some interface/utility that handles that, and then there's only a single spot that needs safety analysis. (Here, that would be the smallvec crate.) While I don't think C outright prevents you from building an equivalent, certainly how people tend to approach C does, and we see that here. The pattern is unsafe at the instantiation site, not at the definition, leading to far more unsafe code. (Not to mention the fact that in C, we have no unsafe {} blocks, so one must assume all such code is unsafe, but even if we just consider the laughable and impossible-to-grep "just the actually unsafe parts", it's far, far more.)
In the C at hand here, the second attempt here fails due to a variable never truly getting initialized (in the sense of having a meaningful value), and the version prior to that is just laughably unsafe, allocating a 1 byte buffer but passing a size far larger.
(The second attempt (i.e., time of bug) also uses the cursed variable name `l`, and the site this code is hosted on uses a font where `l` and `1` are homoglyphs.)
That seems pretty unpersuasive. It seems like you're agreeing that rust is subject to the same bug, are even aware of situations where it's happened, and are hiding behind a switcheroo where you're blaming not the language but the fact that C didn't use a standard gadget for the trick.
But (1) that says nothing about the language, you could totally implement something like smallstr in C, (2) smallstr isn't very standard! I literally had to look it up, and importantly (3) this is glibc, not app code, and you absolutely can't be pulling random libraries into the core standard library in any case.
Basically this seems like excusemaking. Rust in fact has the same problem, because it's a hard problem, and not subject to clean abstraction through the tooling. And it would be good for everyone to admit that fact rather than try to prestidigitize an explanation.
It does. Again, the area requiring audit is substantially smaller: just smallstr. And not just because we've extracted it there, but because we statically know that unsafe behaviors are limited to there. (By way of unsafe {} blocks.) I.e., we only have to audit the unsafe code in Rust, vs. all of the code in C.
> (2) smallstr isn't very standard!
Well, the same could be said for C? Rust's stdlib, like Cs, is somewhat purposefully kept small. It could be that someday it'd get added, but there is enough variation in implementation here that I'm not sure it would.
But pulling in a package in Rust is far easier than it is in C.
It might not be "standard", but I do think there's a set of crates in Rust that are what I'd call "well-known". Like Boost in C++ or requests in Python.
> (3) this is glibc, not app code, and you absolutely can't be pulling random libraries into the core standard library in any case.
That seems NIH. I see no reason glibc couldn't pull in static code, if it does the thing that needs doing, and correctly so.
> Basically this seems like excusemaking. Rust in fact has the same problem, because it's a hard problem, and not subject to clean abstraction through the tooling. And it would be good for everyone to admit that fact rather than try to prestidigitize an explanation.
No, Rust provides better tooling to solve the problem. (Even if it must still be solved, and even if you had to manually reimplement smallstr yourself.)
You're just going back to saying "Rust is better than C!" which is true, but uninteresting. The question at hand was whether this bug would have happened in a memory-safe language. And in fact it could have, because it's implementing an optimization Rust can only emulate using unsafe.
This is what drives me bananas about the rust community. The religion around memory safety persists even in circumstances where it doesn't exist. That's a cult, not an engineering effort.
> c-gull is a libc implementation. It is an implementation of the ABI described by the libc crate.
> Currently it only supports --linux-gnu ABIs, though other ABIs could be added in the future. And currently this mostly focused on features needed by Rust programs, so it doesn't have all the C-idiomatic things like qsort yet, but they could be added in the future.
As C++ advocate on C vs C++ flamewars, I already find quite ironic that GCC, clang, clang's libc and Windows Universal C Runtime are all written in C++.
All those C users hatting on C++, while being forced to use tooling that has dropped C for C++.
Anyway, something that I appreciate about the Rust community is their dedication to rewriting anything and everything in Rust. I'd love it if the Lisp community also had some of that drive. Seeing a library which uses a Python script to generate documentation is so disheartening, they don't need that horrendous, awful garbage, they could just do it in Lisp.
You're not exactly "forced" to use the C stdlib though.
That's one nice thing about C, that the C stdlib is so bare bones that it could just as well not exist and not much would be lost (much harder to ignore the stdlib in C++, at least for some "modern C++" features).
It would be quite amusing, but there's no reason in principle that it couldn't be done.
The user-facing APIs would be just as dangerous as ever, but the internal implementation-detail stuff - like this "__vsyslog_internal" - could presumably be made safer.
Well, the Common Language Runtime that powers .Net languages isn't written with .Net, and the Java runtime environment isn't written in Java.
I know these are a lot more involved than the functions provided by the glibc, but the point is that libc means Library for C, not Library in C.
And of course on Unixes all software is expected to link to the glibc for basic functionality, no matter whether it's written in C or not. So the name is only historically accurate.
Yes, but even more so. Linux “expects” programs to link to libc, but many other Unix-like OSes require programs - in any language — to link to libc. The kernel syscall interface is not considered a stable API.
Windows has a similar structure, but the required kernel interface library is not the same one as the C runtime, so it’s less confusing language-wise.
EDIT: I wonder if you're thinking about how sometimes bounds checks are optimized away? It is true that that will happen in release mode more than debug mode, but those are only the checks that can be proven redundant, if there is any doubt, they will not be optimized out. Semantically, they are still there.