[PATCH v4 2/2] cifs: fix loff_t underflow in cifs_remap_file_range() when len == 0

Frank Sorenson <[email protected]>
Newsgroups org.kernel.vger.stable,org.kernel.vger.linux-cifs
Message-ID <[email protected]>
With len == 0 (clone to EOF), the effective length is computed as:

    len = src_inode->i_size - off;

If off > src_inode->i_size, the result is a negative loff_t, sending a
corrupted ByteCount in the FSCTL_DUPLICATE_EXTENTS_TO_FILE request and
wrapping the filemap_write_and_wait_range() range.  An off >= i_size
check exists but fires only after the ioctl has already been sent.

Snapshot i_size_read(src_inode) once and use it for both the bounds
check and the length calculation, eliminating the TOCTOU and 32-bit
torn-read risk of direct ->i_size access.  Use strict inequality
(off > src_size) so that off exactly at EOF is not rejected.

Fixes: 04b38d601239 ("vfs: pull btrfs clone API to vfs layer")
Cc: [email protected]
Signed-off-by: Frank Sorenson <[email protected]>
---
 fs/smb/client/cifsfs.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index e9e5ba4fa865..d2a0a9ed4bf3 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -1415,8 +1415,15 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off,
 	 */
 	lock_two_nondirectories(target_inode, src_inode);
 
-	if (len == 0)
-		len = src_inode->i_size - off;
+	if (len == 0) {
+		loff_t src_size = i_size_read(src_inode);
+
+		if (off > src_size) {
+			rc = -EINVAL;
+			goto unlock;
+		}
+		len = src_size - off;
+	}
 
 	cifs_dbg(FYI, "clone range\n");
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.