> would this have been a problem had it been written in rust?
The answer would be "it depends on whether you consider denial-of-service a problem". The key detail which makes all the difference is that, unless you're playing with raw pointers (which can only be dereferenced in "unsafe" blocks), the pointer to a buffer slice is always kept together with its length (in a "fat pointer"). Attempting to write through it past the buffer's bounds will result in a Rust panic, which usually aborts the whole process (there are ways to abort just one thread, or even to treat it similarly to a C++ exception, but a library cannot depend on them since the program might be compiled in the panic=abort mode). While that's obviously better than allowing for remote code execution, it still could be considered an issue.
Of course, that's assuming you want a similar API and are writing the code in a similar style, just replacing the direct pointer manipulation with slice manipulation. I don't know whether, in this particular case, more idiomatic Rust code would have avoided the issue. And, of course, the "growable container" approach would completely avoid it, but Rust is also used in places where memory allocation is not allowed, so having a non-allocating API still makes sense.
It should be noted that you can simply use the fallible API's for slices in Rust, then you don't have a crash but can cleanly abort the operation and return an error.
True, but it doesn't make much sense to use the fallible slice APIs when you know they will never fail (the only way they could fail would be if the code has a bug). It would just complicate not only the code within the function, but also the API to the function, which also becomes a fallible API (and this propagates outward, until it meets a caller which already was fallible for other reasons). And complicating the code unnecessarily increases the chance of logic bugs.
It's actually preferrable in many of those "infallible" cases to panic rather than handling the error since it usually indicates that your application is in unknown territory and there is no "safe" way to handle it.
If you're writing cryptographic code, panicking for every issue is not good, that's a DoS vector that could be easily exploited. It's safer to handle the error in-band and let the application higher up decide if it should panic, error or continue.
IMO you should use the fallible slice API's in any safety-critical code, such a cryptographic code.
Yes, there is more code, but it does not become a lot more complex, if you need to you can unwrap to explicitly panic. You should still insert asserts to catch issues. But if there is an issue, such as running out of memory or anything else, you can handle it more appropriately than producing a Denial-of-Service issue immediately, which is definitely not good.
Rust would take the growable container approach here, so it wouldn't be vulnerable in the same way. There's nothing in C that prevents you from doing this either, but as the parent post mentions it's common style to do this (see also things like snprintf).
I am a Rust evangelist as much as the next person, but this is really a case of C developers preferring caller reallocation over callee reallocation, which as the root comment points out is fraught with danger. If the C implementation here used callee reallocation, while you do still have to be careful, the risk of this kind of error is greatly reduced (but at the cost of having to use dynamic memory, which might not be appropriate in all cases).
Yes, Rust would eliminate this error, but you can still do it "safer" in C (but you have to give up certain things to do it that way).
That is fair, though, I'd guess that no other mainstream language except for modern C++ and Rust would fit the bill of OpenSSL. Both of which are embarrassingly recent.
It is not a failure of C that we couldn't improve on it for so many decades.
Yeah, most folks in C++ would just use an std::vector, right? I guess if you wanted to use the modern abstraction of std::array, it could be a problem, since using `operator[]` on a non-existent element produces UB.
It is an exercise in navel gazing until an organization steps up to fund: 1) a linkable clib harness that exports Rust functions to replace OpenSSL functions. and 2) pays to get the resulting harness and underlying code FIPS certified so people can use it.
Probably not. It's definitely possible to write this function exactly as it is in openssl with this issue, nothing about Rust's safety claims prevent it. However, Rust doesn't have the same issues that lead to this kind of pattern being common like they are in C. Result<> types being so common, better handling of dynamic allocations, and at least for now a generally (it can't last forever) more security conscious community mean that other patterns will be chosen unstead. I'm not sure any language can actually prevent it from being possible outright, but you possibly pair it with some kind of formal proof system like using Coq and TLA+ might let you prove thag an issue like this doesn't exist in a specific implementation. However it's incredibly hard to do this.