Hacker News new | past | comments | ask | show | jobs | submit login

Just curious whether Rust would have averted these issues?



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.


Perhaps an innoculation against this is to respond "Yes, but so would Ada"


Ada is such a lost opportunity honestly. As powerful as C, performant and clean.


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.


Memory corruption is literally 2/3 of the iceberg. Look it up.


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).


There was a similar bug in the past in Rust: Integer overflow causing a buffer overflow: https://github.com/rust-lang/rust/pull/54399/commits/8ac88d3...

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).


In reality people use unsafe to optimize and then introduce bugs. You could also use a safe abstractions to avoid bounds violations in C.


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.


The amount of lines added, let alone unsafe lines, is really startling for such a conceptually simple operation.


It's actually questionable. The vulnerable code is described really well in the Qualys report: https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt

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.


> (1) that says nothing about the language

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.


Yes, glibc needs a leftpad incident


It would be quite something to rewrite glibc in Rust! Of course, its the C/C++ run time.


Yeah it would. There are a few attempts, such as C-gull (https://github.com/sunfishcode/c-ward/tree/main/c-gull#readm...).

> 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++.


> All those C users hatting on C++

Such haberdashery!

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.


I can't quite guess what you meant (balderdash[1]?), but I'm pretty sure you didn't mean a goods and wears shop[0]

[0]: https://www.merriam-webster.com/dictionary/haberdashery [1]: https://www.merriam-webster.com/dictionary/balderdash


Because 'hating' was misspelled 'hatting' I did mean to refer to a provider of men's wear such as hats.


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).

Besides: MUSL is written in plain C ;P


Yeah, but that isn't C any longer, it is a flavour of a language that largely looks like C.

C is the complete printout from ISO/IEC 9899.


Indeed it is a shame. All bloated. It would be nice to have small and lean tool chain again.


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.


It's not so unusual to write the C stdlib in a different language.

E.g. Zig is getting a libc written in Zig:

https://github.com/ziglang/zig/issues/514

Rust would work too of course. MUSL is probably the only popular C stdlib actually written in C.


I think their point is that the c in glibc stands for C, as in the language. A glibc rewrite in Rust wouldn't be glibc anymore!


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.


> Well, the Common Language Runtime that powers .Net languages isn't written with .Net, and the Java runtime environment isn't written in Java.

Actually a large part of it is, and in Java's case there are bootstraped implementations, OpenJDK isn't the only one.

Java is like C and C++, where multiple implementations are available for a given specification.

https://docs.oracle.com/javase/specs/


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.


It's a funny thought, but I don't think there's any reason it shouldn't work; IIRC redoxos is providing a libc written in rust for compatibility.


The redox impl is here: https://github.com/redox-os/relibc

Apparently it also supports linux!


Yeah, unless you bypassed the bounds checking with unsafe{} for performance reasons. (The is an unlikely place to do so.)


rust disables bound checking in the release builds, so no, you are wrong


Rust does not disable bounds checks in release builds.


It does, as well as overflow checks, you can re-enable everything to be safer with a custom build profile, but you'll loose at benchmarks


Overflow checks turn into two's compliments' wrapping, but that's only considered acceptable because bounds checks are not turned off.

https://play.rust-lang.org/?version=stable&mode=release&edit...

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.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: