I tried reading and gave up at the "Headline"...<p>Quoting from the bug analysis:<p>>Headline. The crash is real and reproducible. With musl instrumentation we pin the in-process mechanism precisely: a thread's own store to a freshly- faulted anonymous page becomes invisible to that same thread's reload ~10 instructions later, because the page's backing is replaced mid-function. A pagemap read at the instant of the fault shows the backing is the kernel's zero page. A captured core dump confirms the crash site with matched virtual addresses. The mechanism localizes to the interaction between the per-VMA-lock anonymous-fault fast path and a concurrent munmap's TLB shootdown. A source-level review of Linux 7.0.12 identifies a specific race in that interaction, and a git comparison across v6.19/v7.0/v7.1/mainline identifies the v7.0-introduced change on the munmap-teardown side that widens it.<p>"a thread's own store to a freshly- faulted anonymous page becomes invisible to that same thread's reload ~10 instructions later, because the page's backing is replaced mid-function."
-> ??? What's a "backing" of a page? Freshly-faulted? Fresh fries?
"~10 instructions later"?<p>"A pagemap read at the instant of the fault shows the backing is the kernel's zero page."
-> Backing?<p>"The mechanism localizes to the interaction between the per-VMA-lock anonymous-fault fast path and a concurrent munmap's TLB shootdown."
-> How can a mechanism "localize"?<p>And more.<p>This is... words strung together. Nothing more. I wonder how people read and make sense of this.<p>In case people have forgotten what real technical writing looks like, here's a sample (I am not the author):
<a href="https://yifan.lu/2019/01/11/the-first-f00d-exploit/" rel="nofollow">https://yifan.lu/2019/01/11/the-first-f00d-exploit/</a>
I'm becoming increasingly allergic to the performative writing of LLMs.<p>The worst part is how compulsive LLMs are at writing like this. Like the system prompt instructs it to "reason" and like a college Sophomore it pontificates and quotes Nietzsche to fein intelligence and orginal thought.
I love LLMs for technical stuff, but their writing style is horrendous. I also think it's bad form to waste fellow humans' time with walls of generated text.<p>I understand that it's probably a hard technical problem to get models to conform to a style without sacrificing performance in other areas. But I really wish AI companies would spend more effort getting them to write in a neutral, concise way and not like a middle manager on 80mg of Adderall.
This is technical writing for kernel developers who already know how memory management works. If you want to understand it better, you should study up on the x86 MMU and the kernel memory management subsystem. I'm not a kernel expert but I found it pretty understandable, so I'll try to explain it.<p>MMU: The memory management unit, part of the CPU designed to allow an OS kernel to flexibly control how memory addresses used by a program map to physical RAM.<p>Page: A 4k region of memory addresses.<p>Anonymous: The page is just regular old memory used by a single process for general purposes, it's not part of e.g. a memory-mapped file.<p>Backing: The memory corresponding to a page. The kernel can direct the MMU to map any page to any part of RAM, or delete the mapping entirely.<p>Zero page: The kernel keeps a single 4 KB page filled with zeros (the "zero page").<p>Page fault: An error that occurs when you try to write a page that's not present, or write to a read-only page. Some page faults are normal and expected by the kernel, they support features like swapping, memory-mapped files, etc. Such "expected" page faults are invisible to your program. (On the other hand, an unexpected page fault occurs when your program just straight-up accesses an address it's not supposed to, which will end your program with a SIGSEGV signal -- an all-too-familiar experience for a C programmer.)<p>When you allocate say 4 MB of memory, the kernel simply sets it to 1k read-only copies of the 4 KB zero page. Then when your program tries to write to a page, it faults. The kernel handles this expected fault by assigning that page an individualized memory region. If a program allocates a lot of memory, it's only assigned memory for what it actually uses, when it first uses it. This is an optimization: Every program that allocates more memory than it needs is wasteful, but the kernel can recover that waste by not backing the allocation with memory -- the program has to prove each page is needed by writing to it.<p>Store to a freshly-faulted anonymous page: The program stored data to its own memory, which caused an expected page fault.<p>> becomes invisible to that same thread's reload ~10 instructions later<p>The thread fairly quickly tried to read the data from the same place in memory it had just written to. It doesn't get the same data back. <i>This is a major problem</i> that causes the program to malfunction and crash.<p>> A pagemap read at the instant of the fault shows the backing is the kernel's zero page<p>The expected fault occurred because the program tried to write to an address that was mapped to the zero page, probably because it's the first write to freshly allocated memory. (This rules out other reasons it might be faulted, e.g. the page had been swapped to disk.)<p>> concurrent munmap's TLB shootdown<p>The page table is big and slow so the CPU caches parts of it in an area called the TLB (translation lookaside buffer). munmap is a kernel function that removes the backing for an address region. Since munmap changes the mapping, it has to inform the MMU the relevant part of the TLB is no longer valid.<p>> per-VMA-lock anonymous-fault fast path<p>This is what the kernel does when the program first writes to a zero page. Saying it's the "fast path" implies there's some (slow) special case handling in the kernel code, but the bug doesn't trigger any of the special cases, we're in the most common case, which the kernel code tries to handle as quickly as possible because it has measurable impact on performance. I would guess per-VMA-lock has to do with how the kernel synchronizes this code (a "lock" is a basic synchronization primitive, you should be familiar with it if you do any kind of multithreaded programming).<p>> The mechanism localizes to the interaction between the per-VMA-lock anonymous-fault fast path and a concurrent munmap's TLB shootdown. A source-level review of Linux 7.0.12 identifies a specific race in that interaction<p>The mechanism: What's actually happening to cause the program not to be able to load data it just stored in memory.<p>Localizes: The cause of a problem like this is a needle in a haystack -- it could be caused by the program, the kernel or the hardware. The analysis has narrowed down the haystack to a specific part of the kernel code.<p>Race in that interaction: Two parts of the kernel code, (1) The kernel code for munmap and (2) the kernel code to handle a program's first write to the read-only zero page for a fresh allocation. These two parts work fine individually but the problem occurs when they both try to change the page tables / TLB at exactly the same time. This is quite a small, specific haystack compared to "somewhere in the program, kernel or hardware" we started with.
I understood the jargon just fine. The writing is still terrible and way too verbose.
Excellent explanation.<p>I’ve been reading the LWN kernel page for >20 years so I’ve picked up almost all the jargon and could understand it pretty decently.<p>You’re dead on in saying it was written for that specific audience, not anyone more “normal”.
Thank you for taking the time to write that out. I found it incredibly helpful, just wanted to let you know I appreciated it!
Agreed, the article you linked is a great example of clear, understandable, detailed technical writing.
fwiw "backing" is standard jargon in this context, and "freshly faulted" is phrasing you'll see in Linux source comments. The writeup as a whole is indeed slop, though.
This is a pretty clear analysis if you are a kernel developer.<p>> a thread's own store to a freshly- faulted anonymous page becomes invisible to that same thread's reload ~10 instructions later, because the page's backing is replaced mid-function<p>A result of a machine instruction to store something in RAM got erased, when the same thread attempted to load it ~10 machine instructions later. The reason is that the physical RAM page backing that particular virutal page got replaced while the thread was running.<p>The fault happens in the fast path for anonymous (i.e. not backed by files on disk) pages, in the granular per-VMA (virtual memory area) locks.<p>> "A pagemap read at the instant of the fault shows the backing is the kernel's zero page." -> Backing?<p>Yes, it's typical kernel terminology. "A backing page" or a "backing file".<p>> This is... words strung together. Nothing more. I wonder how people read and make sense of this.<p>There's nothing wrong with this description. It's just written for kernel developers. It needs to be expanded and explained for people who are not.
"backing" is a Virtual-Memory related term. With virtual memory, you can have memory areas (called "pages") that are not really there but only present in the metadata (the "book-keeping", so to say). The first time, someone actually tries to access this page, that access is interrupted ("faulted") and the kernel gets a say in what should be done to that piece of memory (i.e. load it from disk somewhere, reserve actual physical memory and fill it with zeroes, or crash the process).<p>The "backing" refers to the physical memory that might or might not be present for every "virtual" piece of memory that your program has allocated.<p>"Freshly faulted" means that a page of (virtual) memory has just received a "backing" by the process above and is, thus, very fresh in physical memory (even though the virtual memory might have been allocated much earlier)<p>"~10 instructions later" refers to the assembly- (machine-) code, which, contrary to a high-level language like C, usually has long(ish) sequences of rather simple "instructions". 10 instructions is a rather short interval in assembly code.<p>As for the "localize", the term used is actually "localizes to" which I read as "turns out to be located in" (probably just a bad English translation by the original author)<p>While this whole summary reads a bit weird, I don't think it is necessarily the result of an LLM, it's probably just that someone who is rather inexperienced at writing up technical summaries did it.
So the theory is that the page is faulted in, then somehow evicted within 10 instructions, then re-faulted in somewhere else, resulting in writes not making it to the page? That would need a context switch and another page fault to happen in short succession. But the context switch to evict the page back out would have necessitated pending writes to have finished. Nothing actually makes sense with that explanation.
The way I read it was that it wrote to a page and then did a read on that page within 10 instructions and that was not enough time for the memory system to have gone through the process of creating the page backed with real memory and that the timing bug widened in Linux 7.0 such that more things like this exposed the bug. Or there was flapping in the TLB for some reason, or the locking wasn’t correct, or whatever else that the kernel devs will figure out was the cause.<p>I’m guessing it wrote to a page and read back zero page as the memory was in the mist of being allocated.
Sounded like a race condition causing a correct new mapping in the TLB to be cleared away by mistake, reverting back to the zero page mapping it was before.
I understand all the words in it and follow the argument, but it's still bullshit in the technical sense of being written by someone who wants to sound authoritative but doesn't ultimately care if they are right or wrong.<p>The write-up should have been about five paragraphs: (1) "The script at https://... generates a tree with X million files taking 20 GB total. Running ripgrep 1.2.34, compiled with musl, on my Threadripper 9876 as 'rg ...' crashes about a fourth of the time. With glibc, it does not crash." (2) "This appears to be a bug introduced by commit abcdef1234 in some_vm_call() that allows a race between [...] such that user space can see a corrupt whatever." (3) "The sequence of operations that causes this is: (show two or more kernel threads with lines interleaved to explain the bug)". (4) and (5) as needed to elaborate on those three core points.<p>But the actual post is long on (fluent) speculation and short on reference to actual code. That's a large part of why it's offensive slop.
Thanks for the explanation. I should have looked up each term a bit more.<p>So "backing" is the underlying physical memory the page maps to.<p>So if I were to make sense of that piece of slop, is this what it would be?<p>"In one thread, a page fault happens during a store operation. The physical memory address is the proper address, which is immediately (around 10 assembly instructions later) replaced by the 0x00000000 memory address by another thread due to race condition, resulting in a crash when the original thread tries to read that page again."
The first thread is the user program, the other thread is the kernel doing things on another core.<p>Reading from the zero page is legal, that doesn’t cause it to crash. The crash is because of a logic “bug” in the program where the zero it reads back causes some other issue in the program.<p>I say “bug” because it’s clearly impossible without the kernel messing up. It just stored a non-zero value there.
Nope. It's more complicated. The store operation does not need to trigger the fault, it can happen for other reasons.<p>What happens here is a bug in munmap() that happens in another thread. It corrupts the TLB, for a brief instant replacing the correct page.<p>So that the virtual memory page that the crashed thread tried to read its RAM, it gets replaced by the special zero-filled physical page. The kernel uses this zero page as an optimization when it needs to create a region of data filled with zeroes, so it can just map one physical page over the entire range.<p>It's a really low-level bug that just requires a lot of specialized knowledge just to explain. A better write-up is certainly possible but needs to have a lot of explanations to make it understandable.
I don't care if the cat is black or white, so long as it catches mice.<p>Translation: if this nails-on-chalkboard LLM spew identifies a kernel bug, which is then patched, its aesthetic qualities do not interest me in the slightest.
Unfortunately, the kernel bug would need to be understood to be patched, and the developed patch itself would need to be reviewed before being accepted, which seems... very hard, to put it mildly, using the nails-on-chalkboard LLM spew report.
At least it <i>is</i> a report. It says hey, there's a bug vaguely like this in this general area. Not too dissimilar from the average user report.
Yes, the word 'if' was in that sentence.<p>The only people who have a need to judge the quality of the report (not aesthetically, I mean) are those few who know enough about the subsystems of the kernel it implicates to do something about it.<p>My point: does it lead to a bugfix? Good. No? Bad.<p>Do you have an answer to that question? I believe it's a bit early, no?
[dead]