5 ms·
How do these Rust kernel modules handle out of bounds access in an array? In a C module it would be undefined behaviour leading to kernel panic or weird bugs,
by steeleduncan 4y ago
How do these Rust kernel modules handle out of bounds access in an array?
In a C module it would be undefined behaviour leading to kernel panic or weird bugs, in a Rust userspace binary it would be a panic that terminates the process with an error message, what happens here? Would it be a kernel panic as well? or is there a possibility of handling it?
- EugeneOZ 4y agoYou can catch the panic. It will panic, but I don't know if the driver will catch it. I hope so :)
- ncmncm 4y agoThis not actually substantively different from throwing an exception.
- EugeneOZ 4y agoIndeed, but it's much better than undefined behavior :)
- davidatbu 4y agoI believe Rust in linux was made so that it never panics. Here's a patch that removes panicking allocations for example: https://lore.kernel.org/lkml/20210704202756.29107-1-ojeda@kernel.org/ https://lore.kernel.org/lkml/20210704202756.29107-1-ojeda@ke... (but I think all other instances of panicking were removed as well). EDIT: Look at replies. "Linus considers panics acceptable in some cases".
- ncmncm 4y agoI presume it will still Oops...
- tialaramex 4y agoLinus considers it acceptable to panic for some programming mistakes, since after all the C code also blows up if you make some programming mistakes. One I ran into (in the sense of read about, not experienced) was if I flatten a Vec of arrays, it's theoretically possible that the flattened structure has too many items in it to represent as a machine word integer. If this happens the flatten operation will panic. This can't happen in a language like C (or C++) because their smallest type has size 1, so all the arrays can't possibly be bigger in total size than the amount of memory, that's nonsense. But Rust has two smaller sizes than this. The relevant one here is the Zero Size Type, Rust has no problem with the idea of an array of empty tuples, such an array could have say, a billion empty tuples in it, yet on a 32-bit system it just needs 4 bytes (to remember how many empty tuples are in it). We can see that flattening a Vec of arrays of empty tuples is a pretty wild thing to choose to do, and nevertheless even if we do it, it only panics when the total amount of empty tuples won't fit in the integers of our native word size. But the function could be asked to do this, and so it might panic. [ You might be wondering how can there be two sizes smaller than C's single byte types in Rust. The answer is the Never type ! and its pseudonym Infallible. The Never type is Empty, no values of this type are possible, so not only does Rust never need to store this type, it doesn't even need to emit machine code to handle this type - the code could never run. This makes sense in Generic programming, we can write Generic error handling code, but it evaporates when the error type was Infallible ]
- davidatbu 4y agoThis is exactly the kind of stuff I come on HN for. Thank you!
- kzrdude 4y agoCan you, in kernel context?
- EugeneOZ 4y agoAfter comments below, I'm not so sure. I was talking about regular Rust, I didn't know that Linux Rust is patched. Sorry.
- hiimkeks 4y agoYou can also use .get(idx), which gives you either Some(data) or None in case of out-of-bounds access.
- dcomp 4y agoFrom what I understand a rust panic will just call BUG(). There is no support for unwinding as such. Most likely you would have to use .get() which returns an Option rather than [] array index which panics.
- ogoffart 4y agoExactly. A rust panic will call the panic_handler, implemented there: https://github.com/Rust-for-Linux/linux/blob/459035ab65c0ebb8d7054b24b6c00de907819eb2/rust/kernel/lib.rs#L263 https://github.com/Rust-for-Linux/linux/blob/459035ab65c0ebb... So accessing an array out of bound will have a runtime check that will call the panic handler, and that panic handler calls BUG() which means kernel panic.
- nicoburns 4y agoWorth noting that one doesn't need to use raw array accessing in Rust nearly so much as in C because you have things like iterators and for..in loops that will ensure correct access. But I would assume it would be a kernel panic. It definitely won't be UB.
- scoutt 4y agoHow does the Rust compiler handle, check bounds and ensures nothing bad can happen with a dynamic array that is passed to a Rust module from the Kernel, another C module or a C userspace program? If an array and a length can be passed to a Rust module, I can just lie about it's size and, unless there is a runtime bound check (which can be slow), I guess bad things can happen too.
- tialaramex 4y agoThe Rust for Linux implementation converts a Rust panic into a Linux kernel BUG macro call. I believe this will expand to an invalid CPU instruction (at least on popular architectures), and if you're a kernel thread you die immediately with the kernel reporting the state where this happened. Obviously in some cases this is fatal and the report might only be seen via say, a serial port hooked up to a device in a test lab or whatever. So, it's not a kernel panic, but it's extremely bad, which seems appropriate because your code is definitely wrong. If you're not sure whether the index is correct you can use get() or get_mut() to have an Option, which will be None if your index was wrong (or of course you could ask about the length of the array since Rust remembers how long arrays are).
- throwaway894345 4y agoWould a kernel module be written as a normal Linux-targeting Rust program, or would it be more like a bare metal target with its own (user-provided) panic handler?
- loeg 4y agoMore like the latter. Kernel modules don’t run in userspace.
- megous 4y agoBUG() will panic the kernel. https://elixir.bootlin.com/linux/latest/source/include/asm-generic/bug.h#L52 https://elixir.bootlin.com/linux/latest/source/include/asm-g... I guess that's quite drastic for a checked out of bound access, when there's no actual memory safety issue and the compiler can simply return an error from the function, or do something else less drastic.
- sealeck 4y agoIn which case you can call the get method (which returns an Option - i.e. either the value or null) rather than indexing and return an error value.
- 4y ago