ksmbd: validate COPYCHUNK source and target ranges

ksmbd_vfs_copy_file_ranges() rejects negative source offsets in the
copy loop, but it does not validate target offsets. It also calculates
lock and overlap endpoints before ensuring that either range fits within
MAX_LFS_FILESIZE.

When the target is an alternate data stream, the buffered path passes a
negative target offset to ksmbd_vfs_stream_write(). Let n be Length and
let -d be TargetOffset, where 0 < d < n <= XATTR_SIZE_MAX. For an empty
stream, the writer allocates n - d bytes, then copies n bytes starting d
bytes before the allocation. An authenticated SMB client can control d
and the source data, overwrite kernel heap memory, and crash the host.

Validate both ranges before lock, overlap, or I/O calculations.

Fixes: 8482150a07 ("ksmbd: support copychunk for alternate data streams")
Assisted-by: Antiproof:GPT-5.6-Sol
Signed-off-by: Alon Shakevsky <shakevsky@berkeley.edu>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Alon Shakevsky 2026-09-01 00:05:31 +00:00 committed by Namjae Jeon
parent 0e75389962
commit 0480cee8cc

View File

@ -2007,6 +2007,11 @@ static ssize_t ksmbd_vfs_copy_file_range_buffered(struct ksmbd_work *work,
return ret;
}
static bool ksmbd_vfs_copy_range_valid(loff_t offset, size_t len)
{
return offset >= 0 && (loff_t)len <= MAX_LFS_FILESIZE - offset;
}
int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
struct ksmbd_file *src_fp,
struct ksmbd_file *dst_fp,
@ -2042,6 +2047,10 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
dst_off = le64_to_cpu(chunks[i].TargetOffset);
len = le32_to_cpu(chunks[i].Length);
if (!ksmbd_vfs_copy_range_valid(src_off, len) ||
!ksmbd_vfs_copy_range_valid(dst_off, len))
return -E2BIG;
if (check_lock_range(src_fp->filp, src_off,
src_off + len - 1, READ))
return -EAGAIN;
@ -2134,7 +2143,8 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
len = le32_to_cpu(chunks[i].Length);
copy_len = len;
if (src_off < 0)
if (!ksmbd_vfs_copy_range_valid(src_off, len) ||
!ksmbd_vfs_copy_range_valid(dst_off, len))
return -E2BIG;
if (src_off > src_file_size || len > src_file_size - src_off) {