6 ms·
In memory safety ? Yes, the language is much better at being safe by default. But it does nothing for logics bugs. The thing is, replacing from C (sudo or anyt
by nolok 3y ago
In memory safety ? Yes, the language is much better at being safe by default. But it does nothing for logics bugs.
The thing is, replacing from C (sudo or anything else), the number of exploit due to null pointer or buffer abuse or ... represent easily 50% of it.
- lionkor 3y agoIs that because theyre easy to find, or because theyre the worst?
- yakubin 3y agoThey’re easy to make.
- tialaramex 3y agoA lot of the most serious security vulnerabilities are memory safety because e.g. remote code execution is very often along the lines of "LOL, I smash buffer with machine code, it gets executed" and that's a memory safety problem. For sudo you have potential for some very serious logic bugs, where the program does exactly what the programmer wrote, but what they wrote was not what they intended. Rust's type safety makes it less vulnerable to these mistakes than some languages, but there is no magic. In C obviously a UID, a PID, a duration, an inode number, a file descriptor, a counter are all just integers. In Rust you could make all those distinct types (the "New type idiom"), and out of the box the Duration and the File Descriptor are in fact provided as distinct types. So, some improvement.
- Someone 3y ago> In C obviously a UID, a PID, a duration, an inode number, a file descriptor, a counter are all just integers. In Rust you could make all those distinct types For various kinds of IDs you can do that in C, too: struct UID { int value; }; A C compiler can pass these in registers to functions (https://wintermade.it/blog/posts/value-struct.html https://wintermade.it/blog/posts/value-struct.html). So, performance impact should be zero. It may be not as nice as other languages, but it isn’t bad, either. If you use C++, it can be made a bit nicer, and you could also have such structs that you can calculate with.
- elteto 3y agoYou can technically do this but then you have to write wrapper functions for all relevant syscalls or libc functions to unpack the structure and call the actual thing. Lots of work.
- viraptor 3y agoIt exists, but... throw in some macros or generic cache/storage which is untyped and you end up with a non-trivial version of this: struct GID gid = *(GID*) &some_uid; Which will compile without issues or warnings by default. No belts or braces in this area.
- jerf 3y ago"But it does nothing for logics bugs." "Nothing" is too strong. It does not solve logic bugs, but type systems stronger than C can solve some logic bugs too. Even something as simple as having some concept of "private" and "public" and some boundaries between them can help. I'm writing some code right now in Go, hardly a super strong type system, but I've still put some basic barriers in place like, you can have a read-only view of the global state, but the only way to write to it is to a per-user view of that state, and the only way to witness the changes to the underlying value is through one of those per-user write handles. This eliminates a large class of logic errors in which one accidentally reads the original global state when you should be using the per-user modified state or vice versa. This is a rewrite of some older code, and this error is so rampant in that code as to be almost invisible and probably in practice unfixable in the original code. (Which was solved in practice by only every dealing with one user at a time, and if there was multiple users, it simply ran the process completely from scratch once per user. It tried to cache its way out of repetition of the most expensive stuff, but, the cache keys had some of the same conceptual underlying problems, so it just wasn't as good as it should be.) You can't solve everything this way. Rust's stronger type system offers more options, but you can't solve everything with that either. But with good use of types, there are still classes of mistakes you can eliminate, and classes of other mistakes you can inhibit. (There are some tradeoffs, though; with bad types you can alse mandate incorrect usage. But I think in the case of something like a sudo replacement we can reasonably assume fairly high skill developers and that there will be a lot of high skill oversight, as evidenced by the fact they've already sought out a third-party security review.)
- ndriscoll 3y agoC does have some notion of visibility: put private declarations into the .c file instead of the .h file and declare static linkage. You could have a function that returns a pointer to const for read only data. Obviously they can cast that away, but other languages have unsafe escape hatches too. C also has static analyzers to help with some classes of bugs. Cowboy code might be common, but you don't have to do that. If using something C-like, C++ definitely gives you a lot more tools to write safe code (or hang yourself, up to you) though.
- timschmidt 3y agoEnums, Option and Result types, absence of null, not to mention that the type system, borrow checker, and static everything by default, rewards encoding application state and state transitions using all these mechanics, such that they can be verified at compile time. I'd say the language does quite a lot to address logic bugs as well as memory safety. It can't protect a determined developer from themselves, but it provides incredibly useful tools to anyone who can work out how to use them.
- ajuc 3y agoStatic-everything is such a gimmick in my opinion. It sounds great until you try to do something useful with your code. It's almost never the case that people actually want to hard-code stuff in the source code. Almost always you read configuration files at run-time (like sudo does) and change your behavior depending on run-time information - so you will have run-time errors.
- kstrauser 3y ago“Static” here means that variables are const by default, and you can’t modify one without explicitly marking it as mutable. In your case, a config object would be mutable inside the function that loads it from disk into memory, then read-only everywhere else by default.
- ajuc 3y agoI use rust, and it does have static by default in many places (for example it's hard to do the traditional OOP virtual polymorphism or to keep objects of various types in one container) and it makes it pretty hard for me to write "nice" looking code. It usually devolves into a lot of nested if-else and switch (match) instructions.
- kstrauser 3y agoI haven't run into that so much myself. What I have run into is trying to write C-but-in-Rust, for which the compiler yells at me to please knock it off. It got way easier when I gave up and committed to doing things the Rust way. Not saying you haven't done that, just sharing my personal experience with it.
- bunderbunder 3y agoThis gets said a lot, but I am coming to believe that the case is overstated. For two reasons: 1. Valgrind exists. It's not perfect, but it does arguably do a pretty good job as long as you're writing modern C. The biggest gap I'm aware of is that it can't really help you with global pre-allocated buffers. But I don't think that any language or tool can effectively protect you from information leakage if you're doing that sort of thing, not even Rust. 2. Memory-safe is not the same thing as secure. Programs written in memory-safe languages are rotten with security vulnerabilities, too. Rust's happening to be a memory-safe language that doesn't use garbage collection does not render it immune to this situation. It has some protections around concurrent usage of data that do add additional safety under certain circumstances (assuming you don't switch them off), but I doubt it's a panacea. I worry, though, that the Rust community's tendency to pitch this stuff as a security panacea could breed a culture of complacency that negates the advantages that Rust does bring to the table for systems programming languages. People tend to take unnecessary risks when they believe they're invincible.
- shakow 3y ago> Valgrind exists You may be right on an infinite frictionless plane, but unfortunately that does not work in real life, cf. e.g. https://msrc.microsoft.com/blog/2019/07/why-rust-for-safe-systems-programming/ https://msrc.microsoft.com/blog/2019/07/why-rust-for-safe-sy... > Memory-safe is not the same thing as secure. And safety belts do not help you if your car is on fire, still it's better to wear it.
- adgjlsfhk1 3y agoThe fundamental problem with valgrind is it only looks at what happened, not what could happen. Valgrind is great at making sure you don't have memory safety issues for "normal" inputs, but is basically useless at making sure your code doesn't have memory safety vulnerabilities when fed atypical inputs.
- chlorion 3y agoIt's true that it doesn't eliminate all bugs in general, but it can completely eliminate buffer overflows for example. There is no excuse to not at least have bounds checking. This is one of the most basic memory safety problems and it's trivial to prevent. Just preventing this small issue will prevent a non-trivial fraction of bugs. I don't have sudo's bug list on hand but I wouldn't be surprised if 25% or more are caused by buffer overflows. So even if it doesn't prevent all logic bugs, it cuts out a pretty big chunk of the bug list. >assuming you don't switch them off You can't switch them off. >Rust community's tendency to pitch this stuff as a security panacea I've not seen anyone claim this so far.