5 ms·
Tracking trust with Rust in the kernel
- lock1 1y agoInteresting. Though it reminds me of Alexis's "Parse, don't validate", isn't `syscall :: u8 -> Untrusted<u8>` considered as "validate"? I hope kernel codes that consume it will transform it to appropriate type as well `Untrusted<u8> -> T`.
- vlovich123 1y agoThe kernel is different because it’s not safe to access Untrusted until you copy it locally. Only then can you start parsing. Otherwise you run the risk of TOCTOU security vulnerabilities parsing user space input which then changes the next time you try to access it. Untrusted doesn’t validate - it just ensures you don’t accidentally access the data until you’ve ingested data that could be potentially attacking you.
- MBCook 1y agoThis is something I’ve always wanted from a type system, or a way to make it if you can easily make custom types. Especially for strings, bags of bytes are easier. Seems like it could help in a lot of circumstances with security issues. Writing a web app? All user input is untrusted until you process it. And if Untrusted<String> can’t be converted to String accidentally then it forces the programmer to think about it. Unfortunately in Java (my everyday language) this isn’t feasible. I’d want to be able to join or process Untrusted<String> the same as normal. Really it would need to be built into the stars library. Back to the article it sounds like this could work really well for the kernel. I hope this kind of idea catches on outside of that.
- lock1 1y agoWhy is that not feasible? You could define `Untrusted<T>` container and `.map()` in Java just fine.
- menaerus 1y agoYes, it can be implemented basically in any language that can hide the data members so I also see nothing special about it.
- surajrmal 1y agoIt's only special when you are coming from C. Kernels implemented in c++ have done this sort of thing for a long time.
- kimixa 1y agoThere's plenty of C string libraries with opaque types. No reason why a similar thing can't be done there.
- menaerus 1y agoOpaque types cannot be stack- or statically allocated.
- kimixa 1y agoNo, but many languages already have limitations like "strings live on the heap", even many discussed in this thread. Dynamically sized objects on the stack has always been difficult. You could argue that C special casing fixed length strings to allow that is the odd one out.
- ViewTrick1002 1y agoNot really. Hiding the data is the easy part. What makes Rust special is that you need to acknowledge the potential errors when unwrapping the type. With a standard library and culture built on exposing the edge cases at compile time. That is where the guarantees and feeling of certainty comes from.
- lock1 1y ago
- bjackman 1y agoIt's worth noting that in the kernel there's more to "user data" than just the fact that its content might be crafted maliciously: - it might get swapped out or migrated, meaning your thread goes to sleep if you touch it. - it can always change concurrently. - the pointer is only valid within the current context (coz it's a pointer into the user address space). - I've actually never thought about this before but also the user could free it concurrently I think? So there's actually already C APIs in the kernel that force you to be aware of this, at least for strings (stuff where the user passes a pointer to their memory). There's also fancy compiler stuff for marking struct fields as pointing to user data, which IIUC can be used to detect if you're forgetting to use the right conversion APIs. This isn't the case for values passed in registers though so I think Trusted<u64> would be totally new. ANYWAY, overall: this is cool and good but it's actually one of the lower-impact things from Rust in the kernel IMO. I don't think the bugs that this prevents are actually all that common in practice. TOCTOU would be the biggest one by far but they are rare compared to the daily deluge of incredibly basic UAF bugs that Rust also prevents.
- tux3 1y ago>I've actually never thought about this before but also the user could free it concurrently I think? Yup. But if you only send it back to the malloc heap, the kernel doesn't notice, it will happily read data that has been freed. Unless the data is unmapped, then the kernel is going to get a page fault while trying to read your input. What goes up must come down, so that gets translated to SIGSEGV, and the program stops.
- cyphar 1y agoThe kernel doesn't give you SIGSEGV in that case -- you will usually just get -EFAULT. All user pointer accesses are scoped with user_access_begin() and user_access_end() (or something equivalent) which stops the block of data from being unmapped by another thread -- of course, if this mechanism didn't exist then you would get a kernel oops if there was a concurrent munmap(2).
- cyphar 1y ago
- blibble 1y agoof all languages, perl supported this as a first class feature, "tainting"
- k_bx 1y agoAfter jumping from no-embedded-knowledge to a forced situation where I needed to produce something working, I've played a bit with Rust-for-Embedded, and it has exactly this approach when working with various ports and devices (UART, clocks etc.). And oh by is this approach practical! While still very possible, it does make a large move towards compiler not letting you shoot in the foot.
- pjmlp 1y agoYou can do this kind of type oriented programming in C++, unfortunely as many people only use it as a better C, this knowledge is seldom widespread, and even when demoing, it needs a lot of advocacy alongside compiler explorer to actually make the point across. And then the audience will nod yes, accept the message of what is possible, and go back to whatever approach they were doing already.
- ultimaweapon 1y agoRust give more ergonomic to this. In C++ it need a lot of typing for creating a new type compared to Rust.
- pjmlp 1y agoDepends pretty much on the type, if using templates or not, if being anti-macros or not. It isn't the typing, rather the culture.
- tialaramex 1y agoRust's type system is a technology, but technology can be used by a culture to support its goals. The technology alone will not get you there, so the culture is more important, but we do need both for success.
- jeroenhd 1y agoYou need to add a lot of text, but the text contains about the same semantic meaning. It's a lot of typing but that's a matter of density rather than ease of use. At least in modern c++. Then again, modern C++ seems to play the same role as modern Java, in that some places use it but most of them are stuck at the version they picked when they started developing on a piece of software decades ago.
- pjmlp 1y agoTo be fair to modern C++, or lack thereof, I would assert most places being stuck with specific versions applies to any programming language that traces back to the 20th century. Turns out updating software versions in most companies is really hard, and updating humans atittude to specific programming practices even harder, unless their job is on the line.