smb: client: fix data corruption with concurrent writes and O_TRUNC
Impact
In the Linux kernel, the following vulnerability has been resolved:
Source excerpt · LinuxAffected packages
Affected products
Vendor version evidence. Product records are separate from automatic dependency matching.
Linux · Linux
Other versions: unaffected
| Version / range | Source status |
|---|---|
| 110fee6b9bb58a5c50047fc2594d415f741b591e to before 4d143608a0445443a85c9b29f4c9f8e63d5dbfc9 | affected |
| 110fee6b9bb58a5c50047fc2594d415f741b591e to before ffa66fdc7d35b890606767c4d2c7ac26b4d90a99 | affected |
| 110fee6b9bb58a5c50047fc2594d415f741b591e to before a8603b52b39f520ea8a34def74c23fba87396d3e | affected |
Linux · Linux
Other versions: affected
| Version / range | Source status |
|---|---|
| 6.18 | affected |
| 0 to before 6.18 | unaffected |
| 6.18.59 through 6.18.* (inclusive) | unaffected |
| 7.2.13 through 7.2.* (inclusive) | unaffected |
| 7.3 through * (inclusive) | unaffected |
Original source description
In the Linux kernel, the following vulnerability has been resolved:
smb: client: fix data corruption with concurrent writes and O_TRUNC
cifs_do_truncate() flushes dirty pages with filemap_write_and_wait() and truncates the file on the server, but in the old code both operations ran without holding i_rwsem or invalidate_lock. A concurrent buffered write via netfs_perform_write() -- which only needs i_rwsem shared -- could dirty new pages after the flush but before the local truncation, and those pages would be silently discarded by cifs_setsize() -> truncate_pagecache().
Fix by acquiring inode_lock (exclusive i_rwsem) and filemap_invalidate_lock at the top of cifs_do_truncate(), so the entire flush-truncate-resize sequence is atomic with respect to:
- buffered writes (blocked by exclusive i_rwsem, since netfs_start_io_write takes i_rwsem shared),
- read page faults (blocked by exclusive invalidate_lock, since filemap_fault takes it shared),
- writeback collection (blocked by netfs_wb_begin/netfs_wb_end around the server truncate and local resize, since netfs_writepages also acquires the wb lock).