| 0/0 |
2026/07/24 00:22 |
flow |
assessment-security |
27m
Results: map[DenialOfService:false Explanation:Based on the provided bug report and source code analysis, here is the
assessment of the bug:
The report describes a KCSAN-detected data race on the `mapping->nrpages` field
in `mm/filemap.c`.
- **Writer:** Task 14787 is decrementing `mapping->nrpages` in
`page_cache_delete_batch()` during a file truncation operation (triggered by a
failed write on a FAT filesystem).
- **Reader:** Task 14788 is reading `mapping->nrpages` in
`mapping_needs_writeback()` during a `sendfile64` system call.
The read in `mapping_needs_writeback()` is used as a lockless, heuristic
fast-path check to determine if there are any pages in the page cache that might
need writeback before a read operation:
```c
static bool mapping_needs_writeback(struct address_space *mapping)
{
return mapping->nrpages;
}
```
**Security Impact Analysis:**
1. **Exploitability:** **None.** `mapping->nrpages` is an `unsigned long` and is
naturally aligned (offset 80 in `struct address_space`). On 64-bit
architectures, aligned reads and writes are atomic. The KCSAN report confirms
this by showing a clean value transition (`0x0000000000000006 ->
0x0000000000000005`), meaning there are no torn reads.
- If the reader sees a slightly stale non-zero value (e.g., 6 instead of 5),
it will still correctly return `true` and proceed to the safe slow-path.
- If it races with an increment from 0 to 1, it might return `false` and skip
writeback, but a newly added page wouldn't be dirty yet anyway.
This is a known, benign data race that does not lead to memory corruption,
information leaks, or any unsafe kernel state.
2. **Denial of Service:** **None.** The race does not cause crashes, hangs,
deadlocks, or resource leaks.
3. **Accessibility:** The code paths involved (`pwrite64`, `sendfile64`, and
generic page cache operations) are fully accessible to unprivileged users and
within user namespaces. However, because the race is benign, it cannot be
weaponized.
In conclusion, this is a harmless data race on a statistical/heuristic counter
and poses no security risk. Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:true UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 1/1 |
2026/07/24 00:22 |
action |
syz-repro-to-c-repro |
0m
Results:
|
| 2/1 |
2026/07/24 00:22 |
action |
kernel-checkouter |
0m
Results: map[KernelSrc:/app/workdir/cache/src/c62f318aa22f666cd96518e3888547dd326dc082]
|
| 3/1 |
2026/07/24 00:22 |
action |
kernel-builder |
0m
Results: map[KernelObj:/app/workdir/cache/build/888c520c20d3c1b16e32d2fac4415f1dd58ea0be]
|
| 4/1 |
2026/07/24 00:22 |
action |
codesearch-prepare |
0m
Results: map[Index:codesearch-index]
|
| 5/1 |
2026/07/24 00:22 |
agent |
expert |
27m
Model:
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:true UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
Instruction: You are an experienced Linux kernel security engineer. Your task is to analyze given kernel bug report
and determine its security impact based on the following dimensions.
Use the provided tools to examine the source code, check for capability checks (e.g., capable(), ns_capable()),
and understand the nature of the bug. Analyze the given kernel build and configuration.
You can check the kernel config by grepping ".config" file; you can check kernel cmdline by grepping
".config" file for "CONFIG_CMDLINE=". Assume sysctl parameters have default values.
But analyze for the corresponding production build w/o debugging tools enabled (like KASAN, KMSAN, UBSAN).
Try different strategies when analyzing the bug:
- think of ways in which the vulnerable code is unreachable
- or the other way around: try to come up with different ideas of how an unprivileged user can reach the bug
If still unsure err on the side of the bug being non-exploitable/not-accessible.
In the final reply, provide a reasoning for your assessment.
Analysis dimensions:
* Exploitable:
Determine if the bug can result in memory corruption, elevated privileges, or an information leak.
Memory safety issues are almost always exploitable (KASAN or UBSAN reports for use-after-free, out-of-bounds;
refcounting issues, corrupted lists, etc). When kernel is crashing on a completely wild pointer access
(e.g. user-space address, or non-canonical address, but not on NULL or address corresponding to KASAN shadow
for NULL address), including both data accesses and control transfers, that also usually implies possibility
of exploitation. Such reports usually say "unable to handle kernel paging request".
Uses of uninitialized values detected by KMSAN may be exploitable b/c attacker frequently can affect uninit
values with spraying techniques. However, for these exploitability depends on how exactly the uninit value
is used in the code, and what it affects.
Information leaks are exploitable on their own and should be classified as such. A bug that copies kernel
memory contents to userspace (e.g. an out-of-bounds read whose result is returned to the caller, or
uninitialized stack/heap bytes written to a user buffer) is exploitable: it can reveal kernel pointer
values and defeat KASLR, expose sensitive data such as cryptographic keys or other processes' memory, and
serves as a necessary building block in most modern kernel privilege-escalation exploit chains. Do not classify
an information leak as non-exploitable solely because it does not directly cause a memory write or control-flow
hijack; the leak itself is the exploit primitive.
Think of what happens after the bug is triggered. Some bugs cause kernel panic and halt execution,
they are harder to exploit. For example, BUG reports halts the kernel. However, WARNING reports don't halt
execution in production builds. Debug bug detection tools (like KASAN, KMSAN, KCSAN, UBSAN) are also not enabled
in production builds, so attacker can freely exploit these bugs w/o being detected by these tools.
If you see an integer overflow, think how the overflowed value used later (if it's used as allocation size,
or an array index). If you see an out-of-bounds read, think if it's followed by an out-of-bounds write as well.
Some KCSAN data-races may be exploitable by skilled attackers as well. Think what data structures got corrupted
as the result of data races and how. However, note that kernel has lots of "benign" data races that don't lead
to any runtime misbehavior at all.
* Denial Of Service:
Determine if the bug can result in denial-of-service. Most bugs can, since they cause system crash,
hangs, deadlocks, or resource leaks. This is mostly applicable to WARNING bugs that won't cause system crash
in production. For these think what will be consequences of the violation of the kernel assumptions flagged
by the WARNING. In some cases the unexpected condition is also properly handled by the normal control flow
(e.g. with "if (WARN_ON(...))"), these won't cause denial-of-service. If the condition is not handled,
then it may or may not cause denial-of-service.
* Accessible From Unprivileged Processes:
Determine if the bug can be reached from a typical (non-root) user process that does NOT have any special capabilities
(like CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON) or access to device nodes restricted to root.
Assume that unprivileged_bpf_disabled=1, that is eBPF loading is not accessible. However, cBPF (classical BPF)
is still accessible to non-root processes.
Assume that user namespaces are not accessible, that is, the process cannot get the mentioned capabilities even
within a new user namespace (checked by ns_capable() function in the kernel sources).
* Accessible From User Namespaces:
Determine if the bug can be reached within a user-namespace where the process has all capabilities
(including CAP_SYS_ADMIN, CAP_NET_ADMIN, CAP_NET_RAW, CAP_PERFMON). Such capabilities are checked with ns_capable()
function in the kernel sources.
* VM Guest Trigger:
Determine if the bug can be triggered from the context of a typical KVM guest (e.g., set up by a QEMU VMM).
Consider accesses to standard Linux host paravirtualized features (virtio-blk, virtio-net, etc.),
and handling of VM exits in the KVM code.
* VM Host Trigger in The Confidential Computing Context:
Determine if the bug can be triggered in a confidential computing guest kernel from the context of a KVM host.
Consider access to standard Linux guest paravirtualized features (virtio-blk, virtio-net, etc.).
* Ethernet Network Trigger:
Determine if the bug can be triggered by processing ingress network Ethernet traffic, either directly (network stack)
or via drivers exposed to network data.
* Other Remote Trigger:
Determine if the bug can be triggered by processing remote traffic other than Ethernet (Wifi, Bluetooth, NFC, etc).
* Peripheral Trigger:
Determine if the bug can be triggered via an untrusted peripheral device that can be physically plugged
into a system, such as a USB device or a niche hardware driver handling external hardware inputs.
This is particularly important for mobile and desktop environments where users can plug in unknown devices.
* Malicious Filesystem Trigger:
Determine if the bug can be triggered by the kernel mounting and parsing a malicious filesystem image.
This is highly critical for Desktop and Mobile environments where external media or downloaded images
might be auto-mounted.
Don't make assumptions about the kernel source code (it may be different from what you assume it is).
Extensively use the provided code access tools (codesearch-*, git-*, grepper, etc)
to examine the actual source code, and confirm any assumptions.
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt:
The kernel bug report is:
==================================================================
BUG: KCSAN: data-race in delete_from_page_cache_batch / filemap_write_and_wait_range
read-write to 0xffff88810610ce08 of 8 bytes by task 14787 on cpu 1:
page_cache_delete_batch mm/filemap.c:317 [inline]
delete_from_page_cache_batch+0x534/0x720 mm/filemap.c:336
truncate_inode_pages_range+0x1f3/0x7d0 mm/truncate.c:405
truncate_inode_pages mm/truncate.c:485 [inline]
truncate_pagecache+0x53/0x70 mm/truncate.c:798
fat_write_failed fs/fat/inode.c:218 [inline]
fat_write_end+0xa5/0x160 fs/fat/inode.c:247
generic_perform_write+0x314/0x490 mm/filemap.c:4379
__generic_file_write_iter+0x9e/0x120 mm/filemap.c:4475
generic_file_write_iter+0x77/0x1f0 mm/filemap.c:4501
new_sync_write fs/read_write.c:595 [inline]
vfs_write+0x57d/0x990 fs/read_write.c:687
ksys_pwrite64 fs/read_write.c:794 [inline]
__do_sys_pwrite64 fs/read_write.c:802 [inline]
__se_sys_pwrite64 fs/read_write.c:799 [inline]
__x64_sys_pwrite64+0xfd/0x150 fs/read_write.c:799
x64_sys_call+0xa2a/0x3020 arch/x86/include/generated/asm/syscalls_64.h:19
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x136/0x3c0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
read to 0xffff88810610ce08 of 8 bytes by task 14788 on cpu 0:
mapping_needs_writeback mm/filemap.c:634 [inline]
filemap_write_and_wait_range+0x59/0x370 mm/filemap.c:683
kiocb_write_and_wait mm/filemap.c:2904 [inline]
generic_file_read_iter+0xf4/0x320 mm/filemap.c:2978
copy_splice_read+0x47a/0x6b0 fs/splice.c:362
do_splice_read fs/splice.c:979 [inline]
splice_direct_to_actor+0x27c/0x680 fs/splice.c:1084
do_splice_direct_actor fs/splice.c:1202 [inline]
do_splice_direct+0x119/0x1a0 fs/splice.c:1228
do_sendfile+0x37d/0x640 fs/read_write.c:1371
__do_sys_sendfile64 fs/read_write.c:1432 [inline]
__se_sys_sendfile64 fs/read_write.c:1418 [inline]
__x64_sys_sendfile64+0x105/0x150 fs/read_write.c:1418
x64_sys_call+0x2dc4/0x3020 arch/x86/include/generated/asm/syscalls_64.h:41
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0x136/0x3c0 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
value changed: 0x0000000000000006 -> 0x0000000000000005
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 14788 Comm: syz.7.2910 Not tainted syzkaller #0 PREEMPT(lazy)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 06/25/2026
==================================================================
Reply: Based on the provided bug report and source code analysis, here is the assessment of the bug:
The report describes a KCSAN-detected data race on the `mapping->nrpages` field in `mm/filemap.c`.
- **Writer:** Task 14787 is decrementing `mapping->nrpages` in `page_cache_delete_batch()` during a file truncation operation (triggered by a failed write on a FAT filesystem).
- **Reader:** Task 14788 is reading `mapping->nrpages` in `mapping_needs_writeback()` during a `sendfile64` system call.
The read in `mapping_needs_writeback()` is used as a lockless, heuristic fast-path check to determine if there are any pages in the page cache that might need writeback before a read operation:
```c
static bool mapping_needs_writeback(struct address_space *mapping)
{
return mapping->nrpages;
}
```
**Security Impact Analysis:**
1. **Exploitability:** **None.** `mapping->nrpages` is an `unsigned long` and is naturally aligned (offset 80 in `struct address_space`). On 64-bit architectures, aligned reads and writes are atomic. The KCSAN report confirms this by showing a clean value transition (`0x0000000000000006 -> 0x0000000000000005`), meaning there are no torn reads.
- If the reader sees a slightly stale non-zero value (e.g., 6 instead of 5), it will still correctly return `true` and proceed to the safe slow-path.
- If it races with an increment from 0 to 1, it might return `false` and skip writeback, but a newly added page wouldn't be dirty yet anyway.
This is a known, benign data race that does not lead to memory corruption, information leaks, or any unsafe kernel state.
2. **Denial of Service:** **None.** The race does not cause crashes, hangs, deadlocks, or resource leaks.
3. **Accessibility:** The code paths involved (`pwrite64`, `sendfile64`, and generic page cache operations) are fully accessible to unprivileged users and within user namespaces. However, because the race is benign, it cannot be weaponized.
In conclusion, this is a harmless data race on a statistical/heuristic counter and poses no security risk.
|
| 6/2 |
2026/07/24 00:22 |
llm |
expert |
0m
Model:
Tokens:
input: 6983
output: 73
thoughts: 135
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Analyzing a KCSAN Data-Race in the Filemap Code**
Alright, so the bug report highlights a KCSAN data-race. The report's zeroing in on a nasty interaction in the filemap code, specifically between `delete_from_page_cache_batch` and `filemap_write_and_wait_range`. Sounds like we've got a classic read-write conflict going on.
The race occurs because a write operation, triggered within `page_cache_delete_batch` which is itself called via `truncate_pagecache` during a `fat_write_failed` scenario, is clashing with a read, which is called within `mapping_needs_writeback` via `filemap_write_and_wait_range`, during `generic_file_read_iter`. So, we have an asynchronous delete happening at the same time as the system is checking to see if it needs to write the file back.
Time to crack open `mm/filemap.c` and dig into those functions. Looks like line 317 and 634 are key areas to focus on. Let's see what's happening around there to understand the locking and memory ordering, and how this race condition is slipping through the cracks. Should be able to diagnose this quickly.
|
| 7/2 |
2026/07/24 00:22 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:mm/filemap.c Name:page_cache_delete_batch]
Results: map[SourceCode: 266: /*
267: * page_cache_delete_batch - delete several folios from page cache
268: * @mapping: the mapping to which folios belong
269: * @fbatch: batch of folios to delete
270: *
271: * The function walks over mapping->i_pages and removes folios passed in
272: * @fbatch from the mapping. The function expects @fbatch to be sorted
273: * by page index and is optimised for it to be dense.
274: * It tolerates holes in @fbatch (mapping entries at those indices are not
275: * modified).
276: *
277: * The function expects the i_pages lock to be held.
278: */
279: static void page_cache_delete_batch(struct address_space *mapping,
280: struct folio_batch *fbatch)
281: {
282: XA_STATE(xas, &mapping->i_pages, fbatch->folios[0]->index);
283: long total_pages = 0;
284: int i = 0;
285: struct folio *folio;
286:
287: mapping_set_update(&xas, mapping);
288: xas_for_each(&xas, folio, ULONG_MAX) {
289: if (i >= folio_batch_count(fbatch))
290: break;
291:
292: /* A swap/dax/shadow entry got inserted? Skip it. */
293: if (xa_is_value(folio))
294: continue;
295: /*
296: * A page got inserted in our range? Skip it. We have our
297: * pages locked so they are protected from being removed.
298: * If we see a page whose index is higher than ours, it
299: * means our page has been removed, which shouldn't be
300: * possible because we're holding the PageLock.
301: */
302: if (folio != fbatch->folios[i]) {
303: VM_BUG_ON_FOLIO(folio->index >
304: fbatch->folios[i]->index, folio);
305: continue;
306: }
307:
308: WARN_ON_ONCE(!folio_test_locked(folio));
309:
310: folio->mapping = NULL;
311: /* Leave folio->index set: truncation lookup relies on it */
312:
313: i++;
314: xas_store(&xas, NULL);
315: total_pages += folio_nr_pages(folio);
316: }
317: mapping->nrpages -= total_pages;
318: }
SourceFile:mm/filemap.c]
|
| 8/2 |
2026/07/24 00:22 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:mm/filemap.c Name:mapping_needs_writeback]
Results: map[SourceCode: 631: /* Returns true if writeback might be needed or already in progress. */
632: static bool mapping_needs_writeback(struct address_space *mapping)
633: {
634: return mapping->nrpages;
635: }
SourceFile:mm/filemap.c]
|
| 9/2 |
2026/07/24 00:22 |
llm |
expert |
0m
Model:
Tokens:
input: 8416
output: 49
thoughts: 438
Thoughts: **Benign Data Race Analysis: `mapping->nrpages`**
Okay, so I'm looking at this code and immediately see a potential data race on `mapping->nrpages`. Specifically, it's being modified in `page_cache_delete_batch` with the line `mapping->nrpages -= total_pages;` at line 317, while `mapping_needs_writeback` reads it at line 634 with just `return mapping->nrpages;`. There's no obvious locking to synchronize these accesses, which is the immediate concern.
My initial thought is to figure out the implications. Is this a truly bad race condition? I see that `mapping_needs_writeback` uses this value as a fast-path check. It essentially uses the value to determine if further writeback work is needed. If it returns `true`, then more checks or actions are done, but if it returns `false`, it skips the writeback.
The immediate concern is stale reads. If `mapping_needs_writeback` reads an old, outdated value of `nrpages`, it could lead to incorrect behavior. But looking at the context, this is a *decrementing* counter. So the only real concern is reading a value that's *too high*, which is less concerning. If it reads a *higher* value than the actual value (e.g., reads 6 when the real value is 5, as in the report) it will simply *do more work* by returning `true`, which is safe and might just require a recheck with a lock. The system will write data when it shouldn't have to, but it won't corrupt anything.
The real danger would be if it reads 0 when the real value is >0, which causes it to *skip* writeback when it shouldn't. However, given that `nrpages` is being *decremented*, the stale value would be *greater* than or equal to the current value, which, again, is safe.
Now, a red flag - if this were an exploitable race, KCSAN would have reported it, and I'd be seeing an entirely different issue. Since it hasn't, I'm leaning toward this being a benign data race, a race on a heuristic or statistic. Specifically, it seems to be an optimization. To confirm this, I need to check the callers of `mapping_needs_writeback` and see the context.
|
| 10/2 |
2026/07/24 00:22 |
tool |
codesearch-find-references |
0m
Args: map[ContextFile:mm/filemap.c IncludeSnippetLines:0 Name:mapping_needs_writeback SourceTreePrefix:]
Results: map[References:[map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:file_write_and_wait_range SourceFile:mm/filemap.c SourceLine:785] map[ReferenceKind:calls ReferencingEntityKind:function ReferencingEntityName:filemap_write_and_wait_range SourceFile:mm/filemap.c SourceLine:683]] TruncatedOutput:false]
|
| 11/2 |
2026/07/24 00:22 |
llm |
expert |
0m
Model:
Tokens:
input: 9548
output: 40
thoughts: 17
Thoughts: Okay, let's dive into this. Here's my take on `filemap_write_and_wait_range`:
**Examining `filemap_write_and_wait_range`**
Right, so I'm focusing in on `filemap_write_and_wait_range`. My first instinct is to understand its role within the broader file system architecture. It's clearly involved with writing and waiting, so it's probably deeply tied to the dirty page management and writeback process. I need to figure out the scope of its operation β what range of pages does it handle? Does it deal with an entire file, or just a segment? The "range" in the name is a big clue; I'm betting it's the latter.
Now, I'm thinking about the implications of the "wait" part. It must be designed to block until the writes are actually flushed to persistent storage, but how does it handle potential errors or timeouts? I need to look into any error handling strategies this function employs. Is there retry logic? Does it propagate errors, and if so, how? And what locking mechanisms are involved? I know that concurrent write operations are a huge problem in a file system, so I need to understand how this function ensures data integrity. It's likely involved with `writeback_control` and maybe even some dirty page state transitions.
I'm also curious about its integration with the VFS layer. Does this function interact directly with block device drivers, or does it go through a higher-level abstraction? I need to see if it makes direct calls to the block layer or if it relies on other file system components for data transfer. Understanding the calling context is important here; what calls `filemap_write_and_wait_range`? How is it triggered? Is it a key function in something like a sync or fsync operation? I'm going to look at related functions to try and find its parent function. Knowing the high level flow of this function in terms of other functions is critical to understanding the bigger picture.
Finally, I'll need to consider performance implications. Is this function optimized for different workloads? Does it use asynchronous I/O, or is it purely synchronous? If so, how does it mitigate the blocking behavior that it's designed to implement? What about NUMA considerations? I'll be keeping an eye out for potential bottlenecks and areas where this might contribute to performance issues on a heavily loaded system. I have a lot to dig into here to understand this key piece of the file system puzzle.
|
| 12/2 |
2026/07/24 00:23 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:mm/filemap.c Name:filemap_write_and_wait_range]
Results: map[SourceCode: 662: /**
663: * filemap_write_and_wait_range - write out & wait on a file range
664: * @mapping: the address_space for the pages
665: * @lstart: offset in bytes where the range starts
666: * @lend: offset in bytes where the range ends (inclusive)
667: *
668: * Write out and wait upon file offsets lstart->lend, inclusive.
669: *
670: * Note that @lend is inclusive (describes the last byte to be written) so
671: * that this function can be used to write to the very end-of-file (end = -1).
672: *
673: * Return: error status of the address space.
674: */
675: int filemap_write_and_wait_range(struct address_space *mapping,
676: loff_t lstart, loff_t lend)
677: {
678: int err = 0, err2;
679:
680: if (lend < lstart)
681: return 0;
682:
683: if (mapping_needs_writeback(mapping)) {
684: err = filemap_fdatawrite_range(mapping, lstart, lend);
685: /*
686: * Even if the above returned error, the pages may be
687: * written partially (e.g. -ENOSPC), so we wait for it.
688: * But the -EIO is special case, it may indicate the worst
689: * thing (e.g. bug) happened, so we avoid waiting for it.
690: */
691: if (err != -EIO)
692: __filemap_fdatawait_range(mapping, lstart, lend);
693: }
694: err2 = filemap_check_errors(mapping);
695: if (!err)
696: err = err2;
697: return err;
698: }
SourceFile:mm/filemap.c]
|
| 13/2 |
2026/07/24 00:23 |
llm |
expert |
0m
Model:
Tokens:
input: 10758
output: 40
thoughts: 456
Thoughts: **Analyzing a Potential Data Race in Page Cache Writeback**
Okay, so I'm looking at this code and trying to understand a KCSAN report. The core of it seems to be about a potential race condition when checking if a file mapping needs writeback. The logic hinges on `mapping->nrpages`. If `mapping_needs_writeback` returns false, we skip the `filemap_fdatawrite_range` and `__filemap_fdatawait_range` calls, right? And if `nrpages` is zero, there's nothing to write back anyway. Makes sense so far.
But here's the kicker: `nrpages` can be modified concurrently. The code uses `mapping->nrpages -= total_pages;`. So, imagine a scenario where `nrpages` is, say, 6, and a write operation comes in reducing `total_pages` to 5. A concurrent read could see either 6 or 5, both greater than 0, and incorrectly determine there's something to write back. But, what happens if it becomes *exactly* zero? If `nrpages` hits zero, it means all the pages have been deleted, so there's no problem.
And now, the real question: Could we get a torn value? I mean, `nrpages` is an `unsigned long`, and on a 64-bit system, aligned reads and writes are atomic, so we should be safe there. The KCSAN report confirms my suspicion. It shows a read and write to the same memory location, with the value changing from 6 to 5. This is definitely a benign data race. It's just a heuristic check, after all.
The fix here is likely straightforward: something like `READ_ONCE` and `WRITE_ONCE` or maybe a `data_race()` annotation to make it clear to the compiler, maybe? I'd probably need to verify that there isn't something more subtle going on with the surrounding code, but this looks like a textbook example of a data race that doesn't actually cause correctness issues, just suboptimal performance. Now let me see if I can find a patch that addresses this, just to be sure.
|
| 14/2 |
2026/07/24 00:23 |
tool |
git-log |
10m
Error:
Args: map[CodeRegexp:mapping_needs_writeback Count:10 SourcePath:mm/filemap.c]
Results:
|
| 15/2 |
2026/07/24 00:33 |
llm |
expert |
0m
Model:
Tokens:
input: 11757
output: 40
thoughts: 8
Thoughts: Okay, here's the summary, rendered as your thoughts:
**The Path Prefix Dilemma**
Ah, right, I need to make sure the user has provided the `PathPrefix`. This is key. Without it, the configuration won't be as flexible as it needs to be. I want the user to be able to set and override that, and I know from experience that it's often overlooked. It's a critical, fundamental part of the configuration, influencing how requests get routed, the root of the serving. I'll need to make this point clear in the documentation as well as in the code comments. Itβs the essential setting. Without it, the service will not function as it should.
|
| 16/2 |
2026/07/24 00:33 |
tool |
git-log |
0m
Args: map[CodeRegexp:mapping_needs_writeback Count:10 PathPrefix:mm/filemap.c]
Results: map[Output:4bdcd1dd4d2f mm: move filemap_range_needs_writeback() into header
63135aa3866d mm: provide filemap_range_needs_writeback() helper
ddf8f376d137 mm/filemap.c: clean up filemap_write_and_wait()
9326c9b20dd8 mm: consolidate dax / non-dax checks for writeback
]
|
| 17/2 |
2026/07/24 00:33 |
llm |
expert |
0m
Model:
Tokens:
input: 12075
output: 26
thoughts: 31
Thoughts: Here's my attempt at summarizing the thought process, tailored for an expert audience:
**Analyzing Recent Commits**
Okay, time to dive into this. Based on the task at hand, I'm thinking I need to investigate the changes introduced in the recent commits, likely to address a specific issue or implement a new feature. I need to pinpoint the relevant modifications quickly, so I'm going to focus on commit `4bdcd1dd4d2f` first. If that doesn't hold the answers, I'll switch my focus to `63135aa3866d`. This will allow me to track down the root cause by examining the diffs and looking for any potential side effects. I'll need to pay close attention to code structure, logic changes, and any potential regressions introduced. I'll be looking for clues in the context of the related files.
|
| 18/2 |
2026/07/24 00:33 |
tool |
git-show |
0m
Args:
Results: map[Output:commit 63135aa3866db99fd923b716c5ff2e468879624a
Author: Jens Axboe <axboe@kernel.dk>
Date: Thu Apr 29 22:55:18 2021 -0700
mm: provide filemap_range_needs_writeback() helper
Patch series "Improve IOCB_NOWAIT O_DIRECT reads", v3.
An internal workload complained because it was using too much CPU, and
when I took a look, we had a lot of io_uring workers going to town.
For an async buffered read like workload, I am normally expecting _zero_
offloads to a worker thread, but this one had tons of them. I'd drop
caches and things would look good again, but then a minute later we'd
regress back to using workers. Turns out that every minute something
was reading parts of the device, which would add page cache for that
inode. I put patches like these in for our kernel, and the problem was
solved.
Don't -EAGAIN IOCB_NOWAIT dio reads just because we have page cache
entries for the given range. This causes unnecessary work from the
callers side, when the IO could have been issued totally fine without
blocking on writeback when there is none.
This patch (of 3):
For O_DIRECT reads/writes, we check if we need to issue a call to
filemap_write_and_wait_range() to issue and/or wait for writeback for any
page in the given range. The existing mechanism just checks for a page in
the range, which is suboptimal for IOCB_NOWAIT as we'll fallback to the
slow path (and needing retry) if there's just a clean page cache page in
the range.
Provide filemap_range_needs_writeback() which tries a little harder to
check if we actually need to issue and/or wait for writeback in the range.
Link: https://lkml.kernel.org/r/20210224164455.1096727-1-axboe@kernel.dk
Link: https://lkml.kernel.org/r/20210224164455.1096727-2-axboe@kernel.dk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
diff --git a/include/linux/fs.h b/include/linux/fs.h
index bf4e90d3ab18..12766edee81f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2878,6 +2878,8 @@ static inline int filemap_fdatawait(struct address_space *mapping)
extern bool filemap_range_has_page(struct address_space *, loff_t lstart,
loff_t lend);
+extern bool filemap_range_needs_writeback(struct address_space *,
+ loff_t lstart, loff_t lend);
extern int filemap_write_and_wait_range(struct address_space *mapping,
loff_t lstart, loff_t lend);
extern int __filemap_fdatawrite_range(struct address_space *mapping,
diff --git a/mm/filemap.c b/mm/filemap.c
index 151090fdcf29..1750742b5689 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -635,6 +635,49 @@ static bool mapping_needs_writeback(struct address_space *mapping)
return mapping->nrpages;
}
+/**
+ * filemap_range_needs_writeback - check if range potentially needs writeback
+ * @mapping: address space within which to check
+ * @start_byte: offset in bytes where the range starts
+ * @end_byte: offset in bytes where the range ends (inclusive)
+ *
+ * Find at least one page in the range supplied, usually used to check if
+ * direct writing in this range will trigger a writeback. Used by O_DIRECT
+ * read/write with IOCB_NOWAIT, to see if the caller needs to do
+ * filemap_write_and_wait_range() before proceeding.
+ *
+ * Return: %true if the caller should do filemap_write_and_wait_range() before
+ * doing O_DIRECT to a page in this range, %false otherwise.
+ */
+bool filemap_range_needs_writeback(struct address_space *mapping,
+ loff_t start_byte, loff_t end_byte)
+{
+ XA_STATE(xas, &mapping->i_pages, start_byte >> PAGE_SHIFT);
+ pgoff_t max = end_byte >> PAGE_SHIFT;
+ struct page *page;
+
+ if (!mapping_needs_writeback(mapping))
+ return false;
+ if (!mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) &&
+ !mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK))
+ return false;
+ if (end_byte < start_byte)
+ return false;
+
+ rcu_read_lock();
+ xas_for_each(&xas, page, max) {
+ if (xas_retry(&xas, page))
+ continue;
+ if (xa_is_value(page))
+ continue;
+ if (PageDirty(page) || PageLocked(page) || PageWriteback(page))
+ break;
+ }
+ rcu_read_unlock();
+ return page != NULL;
+}
+EXPORT_SYMBOL_GPL(filemap_range_needs_writeback);
+
/**
* filemap_write_and_wait_range - write out & wait on a file range
* @mapping: the address_space for the pages
]
|
| 19/2 |
2026/07/24 00:33 |
llm |
expert |
0m
Model:
Tokens:
input: 13930
output: 37
thoughts: 26
Thoughts: Here's my take on the situation:
**Investigating a Potential Data Race**
Okay, so I'm seeing a potential data race with `mapping->nrpages`. That's not good. My immediate thought is, "Has this been addressed already? Has someone else spotted this and patched it?" I need to see if there are any commits out there that specifically target this problem. I have to look into the commit history. I need to know if I'm reinventing the wheel, or worse, making a duplicate report of a fix. Let's dig in and see what the code has to say.
|
| 20/2 |
2026/07/24 00:33 |
tool |
git-log |
0m
Args: map[CodeRegexp:mapping_needs_writeback Count:10 MessageRegexps:[data race]]
Results:
|
| 21/2 |
2026/07/24 00:33 |
llm |
expert |
0m
Model:
Tokens:
input: 14135
output: 36
thoughts: 23
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Investigating Potential Data Corruption**
Right, let's get down to brass tacks. I'm thinking we need to dig into the git log and see if we can unearth some clues regarding potential data corruption scenarios. Specifically, I'm going to focus my search on two key terms that are likely to be related to the issue we're facing: `mapping_needs_writeback` and `data-race`. The first, `mapping_needs_writeback`, screams "I/O issue" and points directly to problems with memory mapping and synchronization, particularly the need to flush data to disk. We know that writeback can get tricky with concurrent access, and is a likely trigger. The second term, `data-race`, well, that's just a classic red flag. Any commit mentioning that term should be looked at immediately. The interaction of these two are more telling than either in isolation. I'm hoping to uncover past commits where these were addressed, perhaps leading to a pattern of regression that can explain our current issues, or perhaps to give clues to the code paths to be investigated. I'm going to start with a broad search, and then refine the search, depending on the initial results.
|
| 22/2 |
2026/07/24 00:33 |
tool |
git-log |
2m
Args: map[CodeRegexp:mapping_needs_writeback Count:10 MessageRegexps:[race]]
Results:
|
| 23/2 |
2026/07/24 00:36 |
llm |
expert |
0m
Model:
Tokens:
input: 14478
output: 40
thoughts: 27
Thoughts: Okay, here's my take on those thoughts, tailored for an expert audience:
**Analyzing Potential Data Races in the Filemap Write Path**
Alright, my initial instinct is to dig into the source code to understand potential data races related to `filemap_write_and_wait_range`. Given my experience, I know this function is a critical point for flushing data from page cache to disk, making it a high-contention area ripe for concurrency issues. My thought process immediately jumps to using `git log` to trace the history of this function and, crucially, to search for related changes that explicitly mention "data-race" or potential concurrency problems. This targeted search approach is the most efficient way to quickly identify relevant commits β patches that might have introduced or resolved a race condition within that code path. I'll need to analyze these changes for insights into locking mechanisms, memory barriers, and potential issues with concurrent access to shared data structures within that code path. From there I can focus on testing the area with stress tests to confirm the theory.
|
| 24/2 |
2026/07/24 00:36 |
tool |
git-log |
1m
Args: map[CodeRegexp:filemap_write_and_wait_range Count:10 MessageRegexps:[race]]
Results: map[Output:6ebfede8d57a cifs: Pass unbyteswapped eof value into SMB2_set_eof()
edc6d01bad73 f2fs: Convert to using invalidate_lock
d4f5258eae7b ext4: Convert to use mapping->invalidate_lock
869ae85dae64 xfs: flush new eof page on truncate to avoid post-eof corruption
321fe13c9398 ceph: add buffered/direct exclusionary locking for reads and writes
16c54688592c ext4: Allow parallel DIO reads
837bb1d752d9 NFSv4.2: Fix writeback races in nfs4_copy_file_range
32ebffd3bbb4 ext4: fix races between buffered IO and collapse / insert range
ea3d7209ca01 ext4: fix races between page faults and hole punching
0f9160b444e4 xfs: xfs_setattr_size no longer races with page faults
]
|
| 25/2 |
2026/07/24 00:37 |
llm |
expert |
0m
Model:
Tokens:
input: 15021
output: 34
thoughts: 21
Thoughts: Okay, here's my summary, presented as a stream of thought:
**Diving into the Code's History**
Alright, I need to investigate a potential concurrency issue, likely a data race, related to memory management, specifically concerning `mapping->nrpages`. My first instinct is to dive into the Git logs. I'm going to formulate a targeted search to narrow down the relevant commits. I'll search for occurrences of both `mapping->nrpages` *and* `data-race` within the Git history. That combo should hopefully flag any commits where this specific variable was touched in conjunction with someone identifying, attempting to fix, or at least documenting a concurrency problem. This should hopefully be a very efficient approach.
|
| 26/2 |
2026/07/24 00:37 |
tool |
git-log |
1m
Args: map[CodeRegexp:mapping->nrpages Count:10 MessageRegexps:[race]]
Results: map[Output:f4e4c4e6acdc gfs2: fix address space truncation during withdraw
867da60d463b nfs: avoid i_lock contention in nfs_clear_invalid_mapping
3022fd7af960 shmem: _add_to_page_cache() before shmem_inode_acct_blocks()
cae106dd67b9 mm/khugepaged: refactor collapse_file control flow
2ce0bdfebc74 mm: khugepaged: fix kernel BUG in hpage_collapse_scan_file()
e3fce68cdbed dax: Avoid page invalidation races and unnecessary radix tree traversals
d3798ae8c6f3 mm: filemap: don't plant shadow entries without radix tree node
22f2ac51b6d6 mm: workingset: fix crash in shadow node shrinker caused by replace_page_cache_page()
16d4d43595b4 xfs: split direct I/O and DAX path
3176c3e0ef32 xfs: kill ioflags
]
|
| 27/2 |
2026/07/24 00:39 |
llm |
expert |
0m
Model:
Tokens:
input: 15508
output: 30
thoughts: 30
Thoughts: Okay, here's my take on those thoughts, framed as my own:
**Analyzing a Potential Data Race Fix**
Alright, let's get down to brass tacks. I'm taking a look at this potential data race scenario, specifically where we're using `data_race(mapping->nrpages)` within the `mapping_needs_writeback` function. My initial question, as always, is: **Did this patch *actually* fix the data race?** We're relying on that atomic access there to ensure we have a consistent view of the page count, so I need to verify that we're covering all the bases. I'll need to critically evaluate how `nrpages` is accessed and modified in other parts of the code. Is this `data_race` annotation sufficient, or are there subtle race conditions lurking elsewhere that it doesn't address? We can't let any of those slip through. I need to dig deeper into the synchronization primitives used around this area to confirm its proper behavior.
|
| 28/2 |
2026/07/24 00:39 |
tool |
git-log |
10m
Error:
Args: map[CodeRegexp:data_race.*mapping->nrpages Count:10]
Results:
|
| 29/2 |
2026/07/24 00:49 |
llm |
expert |
0m
Model:
Tokens:
input: 15818
output: 42
thoughts: 27
Thoughts: Okay, here's my take on those thoughts, framed as an expert's internal monologue:
**Investigating Potential Data Races in `mm/filemap.c`**
Alright, time to get down to brass tacks. I've got a hunch about a potential data race lurking around the `mapping_needs_writeback` function within `mm/filemap.c`. That area always seems to be a hotbed for these concurrency issues, and it's a critical piece of the file system writeback machinery, so any instability there is going to cause big problems. Let me dive in and refresh my memory on how that function's interacting with the other components. I want to trace the code paths that modify and read the data used for the writeback decision.
I need to understand what locks are held during accesses, who calls it, when and where, and what the context is. Let's see... what threads might be concurrently modifying the state that informs `mapping_needs_writeback`? Are there interrupt handlers that could sneak in? Are we relying solely on atomics, or is there a chance of some more complex conditional logic at play here? It's often the subtle interactions that trip you up, so I need to go in with a sharp eye for detail. This is important, as any data race would be a critical issue.
|
| 30/2 |
2026/07/24 00:49 |
tool |
git-log |
0m
Args: map[CodeRegexp:data_race.*mapping->nrpages Count:10 PathPrefix:mm/filemap.c]
Results:
|
| 31/2 |
2026/07/24 00:49 |
llm |
expert |
0m
Model:
Tokens:
input: 16183
output: 36
thoughts: 17
Thoughts: Here's my thought process, summarized as you requested:
**Assessing Writeback Requirements in the Current Tree**
Alright, let's take a look. My immediate concern is whether or not there are any pending writeback operations. I need to examine the `mapping_needs_writeback` flag within the current tree structure. This flag is the critical indicator. It will tell me whether the current state of data requires synchronization with persistent storage. I'm going to carefully scrutinize that flag to determine the need for a writeback operation and ensure data integrity. The focus now is on confirming if the flag indicates that a writeback is necessary or not, at this specific point.
|
| 32/2 |
2026/07/24 00:49 |
tool |
codesearch-definition-source |
0m
Args: map[ContextFile:mm/filemap.c Name:mapping_needs_writeback]
Results: map[SourceCode: 631: /* Returns true if writeback might be needed or already in progress. */
632: static bool mapping_needs_writeback(struct address_space *mapping)
633: {
634: return mapping->nrpages;
635: }
SourceFile:mm/filemap.c]
|
| 33/2 |
2026/07/24 00:49 |
llm |
expert |
0m
Model:
Tokens:
input: 16480
output: 34
thoughts: 155
Thoughts: **Analyzing a Potentially Benign Data Race**
Okay, so I'm looking at this bit of code and it's still just the basic `return mapping->nrpages;` statement. This is a familiar situation; it's a known data race that, for whatever reason, hasn't been explicitly annotated.
The key is that this read of `mapping->nrpages` is supposed to be a fast optimization. It's meant to quickly determine if we can skip writeback if the page cache is empty. The problem is, this read can race with `delete_from_page_cache_batch`, which is concurrently decrementing `nrpages`.
The immediate concern is that if the read happens at the wrong moment, we might end up with a torn or garbage value. Wait, hold on. On a 64-bit architecture, which I'm assuming we're dealing with, an aligned 8-byte read is atomic. And `mapping->nrpages` *is* an `unsigned long`, which should be 8 bytes. Is `nrpages` aligned? A quick check... yes, it's part of the `struct address_space`, and should be aligned correctly. So, if it's aligned, the read should be atomic and we won't get a partial write.
This feels like a familiar scenario. I have to verify the alignment, of course, but it still feels like a harmless race condition. I should probably dig deeper, but for now, it's likely safe.
|
| 34/2 |
2026/07/24 00:49 |
tool |
codesearch-struct-layout |
0m
Args: map[ContextFile:include/linux/fs.h Name:address_space]
Results: map[Fields:[map[Name:host OffsetBits:0 SizeBits:64] map[Name:i_pages OffsetBits:64 SizeBits:128] map[Name:invalidate_lock OffsetBits:192 SizeBits:256] map[Name:gfp_mask OffsetBits:448 SizeBits:32] map[Name:i_mmap_writable OffsetBits:480 SizeBits:32] map[Name:i_mmap OffsetBits:512 SizeBits:128] map[Name:nrpages OffsetBits:640 SizeBits:64] map[Name:writeback_index OffsetBits:704 SizeBits:64] map[Name:a_ops OffsetBits:768 SizeBits:64] map[Name:flags OffsetBits:832 SizeBits:64] map[Name:wb_err OffsetBits:896 SizeBits:32] map[Name:i_private_lock OffsetBits:928 SizeBits:32] map[Name:i_mmap_rwsem OffsetBits:960 SizeBits:256]]]
|
| 35/2 |
2026/07/24 00:49 |
llm |
expert |
0m
Model:
Tokens:
input: 17284
output: 66
thoughts: 908
Thoughts: **Benign Data Race in FAT Filesystem Page Cache Handling**
Okay, so looking at this KCSAN report, I see a data race involving `mapping->nrpages`. It's located at offset 640 bits, which is 80 bytes, and importantly, it's 8-byte aligned. This means on 64-bit architectures, the reads and writes are atomic. The KCSAN report confirms this, showing the value changing during the race, but it's just reading old versus new values.
Given this, I can already conclude this is a benign data race. It's not causing memory corruption, privilege escalation, information leaks, or denial of service, and it's accessible by unprivileged processes via file read/write operations within user namespaces. This isn't triggered by a specific VM guest/host, network, peripheral, or filesystem. It seems like a more generic VFS/MM issue.
Now, let's dig a bit deeper to be completely sure. If `mapping_needs_writeback` reads zero when it should be greater than zero, then writeback is skipped. Could this lead to data loss or corruption? If `nrpages` is actually positive but read as zero, `filemap_write_and_wait_range` could return zero without writing back. However, I need to consider when `nrpages` is decremented versus incremented. `nrpages` is only decremented in `delete_from_page_cache_batch`. If pages are being removed, it means they're either being truncated or invalidated, and we don't need writeback anyway.
On the other hand, `nrpages` can be incremented (e.g., in `add_to_page_cache_lru`). A race with an increment might cause a zero read, thus skipping writeback. However, if a page is *just* added, it's not dirty yet. Therefore, skipping writeback is fine. If it *is* dirtied, `nrpages` will be greater than zero. So, this seems completely benign in both scenarios.
Alright, let's document the findings clearly. I'll mark this as not exploitable, no denial of service, unprivileged access is true, user namespace is true, and none of the triggers (VMGuest, VMHost, Network, Remote, Peripheral, Filesystem) apply, since this is in generic VFS/MM code.
Wait, can I be entirely confident that no malicious filesystem can't trigger this race in a way that is exploitable? Since it's a generic VFS/MM bug, no, a malicious filesystem doesn't change anything. And it's triggered through standard file read/write operations.
Let's verify the system calls, just to be sure. I'm seeing Task 1 is associated with `ksys_pwrite64`, which goes through `vfs_write`, `new_sync_write`, `generic_file_write_iter`, `__generic_file_write_iter`, `generic_perform_write`, `fat_write_end`, `fat_write_failed`, `truncate_pagecache`, `truncate_inode_pages`, `truncate_inode_pages_range`, `delete_from_page_cache_batch`, `page_cache_delete_batch`, eventually writing to `mapping->nrpages`. Task 2 is associated with `__do_sys_sendfile64`, through `do_sendfile`, `do_splice_direct`, `do_splice_direct_actor`, `splice_direct_to_actor`, `do_splice_read`, `copy_splice_read`, `generic_file_read_iter`, `kiocb_write_and_wait`, `filemap_write_and_wait_range`, and reading `mapping->nrpages`.
Both tasks use standard system calls (`pwrite64` and `sendfile64`) on a FAT filesystem. The bug is clearly within the generic MM code (`mm/filemap.c`). So, this further confirms my earlier conclusion: the access is unprivileged.
Okay, I'll go ahead and set the results accordingly.
|
| 36/2 |
2026/07/24 00:49 |
tool |
set-results |
0m
Args: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:true UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
Results: map[DenialOfService:false Exploitable:false FilesystemTrigger:false NetworkTrigger:false PeripheralTrigger:false RemoteTrigger:false Unprivileged:true UserNamespace:true VMGuestTrigger:false VMHostTrigger:false]
|
| 37/2 |
2026/07/24 00:49 |
llm |
expert |
0m
Model:
Tokens:
input: 19215
output: 552
thoughts: 439
Thoughts: **Benign Data Race in Filemap: A Closer Look**
Okay, the analysis is complete. Time to synthesize my conclusions into a clear response. This KCSAN report has flagged a data race on `mapping->nrpages` within `mm/filemap.c`, specifically related to how a FAT filesystem handles truncated files. One thread is reducing this count via `page_cache_delete_batch`, which occurs during truncation after a failed write. Meanwhile, another thread is reading the same value in `mapping_needs_writeback` during a `sendfile` operation.
Now, the interesting bit here is the read in `mapping_needs_writeback`. It's a lockless, fast-path check: simply reading the `nrpages` value to determine if a writeback might be necessary. Crucially, the code is using the value as a *heuristic* to short-circuit writeback checks. If `nrpages` is non-zero, the slower path is entered to confirm and potentially initiate writeback; otherwise, it's skipped.
Given that `mapping->nrpages` is an `unsigned long` on 64-bit architectures, and properly aligned, reads and writes are atomic. The KCSAN report *confirms* this, noting no torn reads β the value transitioned from 6 to 5 without exhibiting any intermediate states.
Even if `mapping_needs_writeback` reads a stale value, the potential consequences are limited. If it reads 6 instead of 5, the slow path will be executed correctly since both numbers are greater than 0, resulting in correct behavior. The worst case is a missed writeback, but that's still safe. If the value were 0 and the increment was from 0 to 1, missing writeback is safe since a newly added page would not be dirty.
Therefore, while this is a data race, it's entirely benign. No memory corruption, no information leaks, and certainly no denial-of-service vulnerability. It is easily reproducible by unprivileged users executing standard I/O operations such as `pwrite64` or `sendfile64`, but it presents *no* security risk whatsoever. I can comfortably conclude that this race can be safely ignored.
|
| 38/1 |
2026/07/24 00:50 |
action |
format-explanation |
0m
Results: map[Explanation:Based on the provided bug report and source code analysis, here is the
assessment of the bug:
The report describes a KCSAN-detected data race on the `mapping->nrpages` field
in `mm/filemap.c`.
- **Writer:** Task 14787 is decrementing `mapping->nrpages` in
`page_cache_delete_batch()` during a file truncation operation (triggered by a
failed write on a FAT filesystem).
- **Reader:** Task 14788 is reading `mapping->nrpages` in
`mapping_needs_writeback()` during a `sendfile64` system call.
The read in `mapping_needs_writeback()` is used as a lockless, heuristic
fast-path check to determine if there are any pages in the page cache that might
need writeback before a read operation:
```c
static bool mapping_needs_writeback(struct address_space *mapping)
{
return mapping->nrpages;
}
```
**Security Impact Analysis:**
1. **Exploitability:** **None.** `mapping->nrpages` is an `unsigned long` and is
naturally aligned (offset 80 in `struct address_space`). On 64-bit
architectures, aligned reads and writes are atomic. The KCSAN report confirms
this by showing a clean value transition (`0x0000000000000006 ->
0x0000000000000005`), meaning there are no torn reads.
- If the reader sees a slightly stale non-zero value (e.g., 6 instead of 5),
it will still correctly return `true` and proceed to the safe slow-path.
- If it races with an increment from 0 to 1, it might return `false` and skip
writeback, but a newly added page wouldn't be dirty yet anyway.
This is a known, benign data race that does not lead to memory corruption,
information leaks, or any unsafe kernel state.
2. **Denial of Service:** **None.** The race does not cause crashes, hangs,
deadlocks, or resource leaks.
3. **Accessibility:** The code paths involved (`pwrite64`, `sendfile64`, and
generic page cache operations) are fully accessible to unprivileged users and
within user namespaces. However, because the race is benign, it cannot be
weaponized.
In conclusion, this is a harmless data race on a statistical/heuristic counter
and poses no security risk.]
|