4 ms·
Why Rust? (In general..) Are C memory-related bugs still such a real problem? IIUC, Rust can prevent these kinds of memory vulnerabilities. But it cant really
by yazr 7y ago
Why Rust? (In general..)
Are C memory-related bugs still such a real problem?
IIUC, Rust can prevent these kinds of memory vulnerabilities. But it cant really present the million of other types of vulnerabilities, such as mis-configuration, wrong logic in the code, races, etc
Am i understanding this correctly?
- scottlamb 7y ago> Are C memory-related bugs still such a real problem? I believe so, yes. https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/ https://www.zdnet.com/article/microsoft-70-percent-of-all-se... > IIUC, Rust can prevent these kinds of memory vulnerabilities. Yes: if your Rust code has memory errors, there's a bug in an "unsafe" block (~1% of the code in a project of mine, which I think is typical) or in the compiler. > But it cant really present the million of other types of vulnerabilities, such as mis-configuration, wrong logic in the code, races, etc It can prevent data races. It can't prevent all possible race conditions. https://doc.rust-lang.org/nomicon/races.html https://doc.rust-lang.org/nomicon/races.html
- oconnor663 7y ago> if your Rust code has memory errors, there's a bug in an "unsafe" block Minor clarification around this part. It's possible for a bug in safe code to break an invariant that some correct unsafe code is relying on, if that safe code has private access to something that the rest of the world doesn't. For example, by changing only safe code inside of Vec, you could introduce a bug that set the wrong capacity. Since all the unsafe code in Vec assumes the capacity is correct, that would break everything and cause tons of UB. Vec is sound, though, because the capacity is a private field, and safe code in the caller can't change it. But it does mean that when we're auditing unsafe blocks, we might also need to audit the safe code in the same module, depending on what invariants the unsafe blocks are assuming.
- glennpratt 7y agoI guess that's debatable, your point is that code that should be unsafe might not be, but then that did mean the unsafe code is wrong in a sense. It assumes an invariant that isn't enforced.
- oconnor663 7y agoSome people describe it as unsafe code "infecting" its containing module. This section of the nomicon goes into more detail: https://doc.rust-lang.org/nomicon/working-with-unsafe.html https://doc.rust-lang.org/nomicon/working-with-unsafe.html
- est31 7y ago> But it cant really present the million of other types of vulnerabilities, such as mis-configuration, wrong logic in the code, races, etc That's correct. The great achievement that Rust brings to the table is that it gives you the safety of a traditionally dynamic language like Java or JS with native performance. Let's look at it from a security angle. For some domains, the security that Rust provides is enough to create really safe solutions inside those domains. Think of PDF viewers, image viewers, browsers, etc. Here, it takes in untrusted input, parses it, and displays it to the user, and the codepaths where privileged stuff happens, e.g. reading arbitrary files, are only very sparse. In some domains, Rust alone won't be enough. Think of TLS implementations or kernels. Here, almost any logic bug is also security relevant. Ideally you'd have computer proofs for their security. The language is largely irrelevant, all you need is support for your language in the proof tool. Now, let's look at it from a development angle: C requires you to manually malloc, free and check whether the malloc was successful. Rust does that for you, and although there are no "failible" allocators in the standard library, the language itself doesn't prevent you from writing your own containers etc. that do it, if you really need failible allocators. The bugs that Rust prevents are precisely those kind of bugs that are most annoying to debug. I'm very glad that I don't have to deal with stuff like this [1] or this [2] any more. For the second bug, it wasn't even a crash, it just had weird behaviour. Classical nasal demons. [1]: https://github.com/minetest/minetest/commit/57a461930ba13b0b499c334d77e4b6a0aa73606b https://github.com/minetest/minetest/commit/57a461930ba13b0b... [2]: https://github.com/minetest/minetest/commit/1f76808e4fa5a198f1dbddba6fa18ea1ecb20cb6 https://github.com/minetest/minetest/commit/1f76808e4fa5a198...
- eeZah7Ux 7y ago> The great achievement that Rust brings to the table is that it gives you the safety of a traditionally dynamic language like Java or JS with native performance. Plenty of other modern and old languages are equally fast and memory safe. Calling it a "great achievement" is unfair to other languages.
- est31 7y agoWhich language do you have in mind?
- gamozolabs 7y agoMemory related bugs are quite common (I see many daily as a security researcher). I have previous hypervisors and kernels I've written (in assembly, C, and Rust) [https://github.com/gamozolabs/falkervisor_beta https://github.com/gamozolabs/falkervisor_beta and https://github.com/gamozolabs/falkervisor_grilled_cheese https://github.com/gamozolabs/falkervisor_grilled_cheese]. Memory corruption was my most common issue in these kernels, and when working with fuzzing and security research, my confidence in my own tooling got in the way of root causing bugs. I would find that sometimes bugs that I "detected" in the code I was fuzzing, was indeed due to corruption in my own code. This pushed me a bit towards finding a safer language to write my kernel in, not for security, but for code quality. I was a pretty hardcore C fan and I never saw myself getting into a higher level language like Rust. However the cleanliness of the output code got me immediately hooked a few years ago. I do a lot of work on low-level development and optimizations, and having a compiler with predictable properties of emit code is really important to me (such that I can have a decent idea in my head what the emit code will be). Having allocators be scope based rather than garbage collected really helps with this, and helps with the usability of the language for kernel development. Also you mentioned races as something Rust does not prevent, but it does prevent traditional "exploitable" race conditions, by enforcing that all types shared (passed via message passing, or via globals) must be "Sync", which means they must be proven safe to share between threads. Using atomics or wrapping things in Mutexes is one way to make things sharable. However, Rust does not prevent deadlocks, which are fairly common as just "bugs", especially in kernel development. That being said, Rust has many things that I do not like, such as the clumsiness around working with generic arrays of >32 elements, and working with raw "plain old data". There's definitely a lot of research in modern Rust going into web assembly and other features that I have zero interest in personally, while some of the systems aspects can be a bit lacking. But, I am not personally contributing time to the Rust project, so I cannot complain too much. That being said, it is full featured enough to write bootloaders and kernels in, and I use it for all of my projects for the past few years. TL;DR: Rust is fast, prevents many of the most common bugs (and many of the hardest to reproduce/fix bugs such as corruption/UaFs/etc), and has predictable codegen which is useful for optimization and systems development.
- jrvidal 7y ago
- josteink 7y ago> But it cant really present the million of other types of vulnerabilities, such as mis-configuration, wrong logic in the code, races, etc It can prevent multiple types of data-races. It has nullable-types as an option (I.e. not the default), and not checking for null is a type-error flagged by the compiler. It has checked array-access, preventing out of bound reads. It has immutability by default, preventing accidentally modifying data meant to stay constant. Etc etc. All of this together help creating higher quality, more secure code. If you can have all those errors go away for “free”, why choose a language like C where all of these errors are possible?