Proper Community Engagement
Proper Community Engagement
Posted Aug 31, 2024 2:25 UTC (Sat) by roc (subscriber, #30627)In reply to: Proper Community Engagement by rc00
Parent article: Rust-for-Linux developer Wedson Almeida Filho drops out
That's not the right way to think about it. "unsafe" lets you deference raw pointers, which means you can bypass the borrow checker by using raw pointers instead of references, but you can use references in unsafe Rust and they still get borrow-checked. This matters because it means that entering an unsafe block because e.g. you want to call a C function does NOT mean that you are suddenly also susceptible to lifetime bugs.
> Unsafe Rust is inevitable in the Linux kernel
It is inevitable that unsafe Rust is present in the kernel, but it matters a great deal *how much* is present and where it is present. If you have unsafe Rust in the Rust wrappers around kernel APIs but you can write a lot of drivers with zero unsafe Rust (which is actually the goal), then that is likely to be a big win. You write the wrappers, you invest effort in reviewing that code and testing it, and then all your driver code (which is much more code than the wrappers, in the long run if not the short run) benefits from the safe Rust guarantees.
OTOH if every driver has to use copious amounts of "unsafe" then Rust in the kernel will have failed.
> instead of something like Zig that has around 80% of the memory safety that you get from Rust's borrow checker feature set but with 0% of the downside of the loss of productivity in fighting the borrow checker?
In release builds (i.e. builds with acceptable performance) you get no use-after-free checking with Zig, and those are most of the exploited memory safety issues these days. Plus of course Rust is giving you more safety than just memory safety.
> I believe both Zig and Odin also do not have undefined behavior where Unsafe Rust and C do
UAF is for sure undefined behaviour in Zig. There is no way to define it!
> This strikes me as Zig 1.0 if the current trajectory holds true.
Nope, no UAF protection in production code with Zig.
Posted Aug 31, 2024 3:10 UTC (Sat)
by rc00 (guest, #164740)
[Link] (8 responses)
I've already placed my wager. đŸ˜‰
> In release builds (i.e. builds with acceptable performance) you get no use-after-free checking with Zig, and those are most of the exploited memory safety issues these days. Plus of course Rust is giving you more safety than just memory safety.
Let's debug more of your programming language knowledge:
* Zig's standard library offers a general-purpose allocator that can be used to prevent double-free, use-after-free, and can also detect memory leaks.
* Zig has a build mode named ReleaseSafe that is not only fit for production code but considered the main mode for releases. With ReleaseSafe, memory and safety checks are still enabled.
Let's try to avoid spreading misinformation.
Additional links and resources:
Posted Aug 31, 2024 3:17 UTC (Sat)
by intelfx (subscriber, #130118)
[Link] (2 responses)
> Let’s try <…>
Let’s try to get our facts and logic straight before directing condescension at others, shall we?
Posted Aug 31, 2024 3:37 UTC (Sat)
by rc00 (guest, #164740)
[Link] (1 responses)
It's a general-purpose heap allocator. For all intents and purposes, it can be thought of as the default allocator. You can certainly use others for specialized cases but during development and debugging, why not use the general-purpose one out of good habit? How is this any different from kmalloc? (These are rhetorical questions. See the last sentence of this reply.)
> Let’s try to get our facts and logic straight before directing condescension at others, shall we?
Can you approach this thread with correct information? It's quite the take that you want to apply a negative connotation to "condescension" but yet you state that toxic comments that suggest brigading are "funny."
No, I'm not going to interact with you beyond this dribble.
Posted Aug 31, 2024 3:41 UTC (Sat)
by Cyberax (✭ supporter ✭, #52523)
[Link]
JFYI, Linux has a variety of ways pointers are allocated, kmalloc is only one of them. One of the problems with Rust adoption was that Rust's standard library was not ready for custom allocators and fallible allocations.
Posted Aug 31, 2024 4:05 UTC (Sat)
by roc (subscriber, #30627)
[Link] (3 responses)
Which leaks virtual memory (to catch heap UAF) and is not suitable for production use.
> Zig has a build mode named ReleaseSafe that is not only fit for production code but considered the main mode for releases. With ReleaseSafe, memory and safety checks are still enabled.
ReleaseSafe does not affect the choice of allocator and therefore does not detect heap UAF unless you opt into the general-purpose allocator, which is not suitable for production use.
And FWIW Zig has *nothing at all* to detect stack UAF.
Posted Aug 31, 2024 5:05 UTC (Sat)
by rc00 (guest, #164740)
[Link] (2 responses)
> Which leaks virtual memory (to catch heap UAF) and is not suitable for production use.
The general-purpose allocator is configured with never_unmap set to false by default. Only when set to true is there a possibility that every allocation can be leaked. Again, this allocator can be used for production release modes.
https://www.openmymind.net/learning_zig/heap_memory/
> ReleaseSafe does not affect the choice of allocator and therefore does not detect heap UAF unless you opt into the general-purpose allocator, which is not suitable for production use.
Please read the previous links. This was directly addressed.
> And FWIW Zig has *nothing at all* to detect stack UAF.
The language is still not 1.0 yet. Here is the issue where use-after-free stack allocations will be addressed:
I am sharing these links in good faith. Please take the appropriate time to process them.
Posted Aug 31, 2024 9:04 UTC (Sat)
by roc (subscriber, #30627)
[Link] (1 responses)
Yes, I checked all your links (and more) before I responded, and the information in those links is consistent with what I said. Your new link is also consistent with what I said.
> The general-zurpose allocator is configured with never_unmap set to false by default. Only when set to true is there a possibility that every allocation can be leaked. Again, this allocator can be used for production release modes.
This doesn't support your claims. It doesn't mention never_unmap or describe exactly what GeneralPurposeAllocator guarantees or say what the performance impact is. In fact those things are not documented anywhere outside the source code, as far as I can tell; certainly nowhere you have linked to. So I find your attitude irksome.
But in the spirit of https://xkcd.com/386, I went ahead and looked at the source code: https://github.com/ziglang/zig/blob/master/lib/std/heap/g.... The situation is pretty complicated, but as far as I can tell, the following things are true in the default configuration with ReleaseSafe build mode:
In more detail: the source code comments say:
It's not entirely clear from the comment what "memory slots" means here, but looking at the code it's more clear: https://github.com/ziglang/zig/blob/37df6ba86e3f4e0f5d6a2...
However, when freeing a sub-page-size object, if that means the bucket is *completely empty*, the entire bucket is freed: https://github.com/ziglang/zig/blob/37df6ba86e3f4e0f5d6a2...
Note that the comment "for larger ones it is handled in the backing allocator" is false for the default PageAllocator. There is no logic to avoid reusing virtual memory in that code. So virtual memory isn't leaked, but in exchange you get UAF bugs.
For allocations >= the page size, you enable UAF bugs immediately because PageAllocator can reuse addresses.
This Reddit thread agrees with me that "UAF will not be reliably detected": https://www.reddit.com/r/Zig/comments/1eysv2k/general_pur...
andrewrk did write: https://github.com/ziglang/zig/issues/3180#issuecomment-6...
> I am sharing these links in good faith. Please take the appropriate time to process them.
Oh, I've spent way too much time processing this.
> Here is the issue where use-after-free stack allocations will be addressed: https://github.com/ziglang/zig/issues/3180
Will it really, though? It is not easy at all to detect and prevent stack UAF bugs. For example, if you take the address of a stack value and store it in a heap object, is that allowed? It's often useful to be able to do that, so I guess Zig would want to allow it, but if you allow it, it can be very difficult to prove that the pointer is not used after the function has returned. If they do solve this, there will be some overhead and/or some existing useful Zig code that is no longer legal.
For now, safe Rust prevents UAF and all Zig has is partial, inefficient solutions and promises.
Posted Aug 31, 2024 13:34 UTC (Sat)
by corbet (editor, #1)
[Link]
Posted Aug 31, 2024 5:32 UTC (Sat)
by pbonzini (subscriber, #60935)
[Link]
https://lwn.net/Articles/863459/ has two unsafe blocks, both at initialization time, and that was three years ago. It's a simple driver, sure, and some sources of unsafely are only apparent with e.g. devices that do DMA, but rest assured that the developers have done their homework.
Proper Community Engagement
> UAF is for sure undefined behaviour in Zig. There is no way to define it!
> Nope, no UAF protection in production code with Zig.
* https://zig.news/kristoff/how-to-release-your-zig-applica...
* https://medium.com/@shyamsundarb/memory-safety-in-c-vs-ru...
* https://ziglang.org/documentation/master/#Build-Mode
Proper Community Engagement
Proper Community Engagement
Proper Community Engagement
Proper Community Engagement
Proper Community Engagement
https://github.com/ziglang/zig/issues/3180
Proper Community Engagement
> https://www.openmymind.net/learning_zig/heap_memory/
-- GeneralPurposeAllocator reuses addresses of allocated objects in many cases and does allow UAF bugs in those cases
-- GeneralPurposeAllocator avoids reusing addresses of allocated objects in other cases, and therefore must suffer from serious fragmentation problems leading to performance degradation
-- GeneralPurposeAllocator lacks a lot of the optimizations essential to modern high-performance allocators and cannot be expected to be competitive with those allocators
> //! ### `OptimizationMode.debug` and `OptimizationMode.release_safe`:
...
> //! * Do not re-use memory slots, so that memory safety is upheld. For small
> //! allocations, this is handled here; for larger ones it is handled in the
> //! backing allocator (by default `std.heap.page_allocator`).
GPA passes through objects >= the page size through to the underlying page-level allocator (which defaults to td.heap.page_allocator). For smaller objects, it has a list of page-sized "buckets" per size class, with each bucket carved up into "slots" of that size class. To allocate an object, it finds a bucket for the right size class with empty space, and uses the *next slot in the bucket that has never been used*. I.e., even if some objects in the bucket have been freed, those slots won't get used. This is what inevitably leads to fragmentation and poor cache usage.
With the default PageAllocator and GPA configuration, this memory is returned to the operating system. The next time GPA needs to allocate a page, PageAllocator will likely return memory at the same address. GPA will hand out references to that memory and so classic UAF bugs can then be triggered --- references through a pointer to the freed object will work but access memory in the freshly allocated object, perhaps of a different type.
> Use after free is now solved as far as safety is concerned with heap allocations, if you use the std lib page_allocator or GeneralPurposeAllocator.
And maybe you believed him, but unfortunately that's not true, or at least it's not true now.
This language-advocacy discussion has gone fairly far from the original topic and seems unlikely to resolve anything. This seems like a good time to let it go.
Proper Community Engagement
Proper Community Engagement
