[PATCH 3/7] ksmbd: report actual xattr value length for stream EndOfFile/AllocationSize
"Gaël Blivet-Bailly" <[email protected]>
| Newsgroups | org.kernel.vger.linux-cifs |
|---|---|
| Message-ID | <[email protected]> |
From: Gael Blivet <[email protected]> fp->stream.size holds the byte length of the mangled xattr *name* string (it's used as the attr_name_len argument when looking up the xattr), not the size of the stream's actual data. CREATE and every QUERY_INFO handler that reports EndOfFile/AllocationSize for a stream handle used fp->stream.size directly, so clients received a bogus size derived from the internal xattr key name length instead of the stream's real content length. Add ksmbd_stream_eof() to query the xattr's actual value length via ksmbd_vfs_casexattr_len(), and use it at every site that reports a stream handle's size: the CREATE response, get_file_standard_info(), get_file_all_info(), get_file_network_open_info(), and find_file_posix_info(). Signed-off-by: Gael Blivet <[email protected]> --- fs/smb/server/smb2pdu.c | 55 ++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index e6d0f58d2..735c3eb72 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -2828,6 +2828,22 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path, return 0; } +/* + * fp->stream.size is the byte length of the mangled xattr *name* + * (used as attr_name_len when looking the xattr up), not the size of + * the xattr's value. Reporting it as EndOfFile/AllocationSize for a + * stream handle is wrong -- query the xattr's actual value length + * instead. + */ +static loff_t ksmbd_stream_eof(struct ksmbd_file *fp) +{ + ssize_t slen = ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp), + fp->filp->f_path.dentry, + fp->stream.name, + fp->stream.size); + return slen < 0 ? 0 : (loff_t)slen; +} + static int smb2_remove_smb_xattrs(const struct path *path) { struct mnt_idmap *idmap = mnt_idmap(path->mnt); @@ -4112,10 +4128,17 @@ int smb2_open(struct ksmbd_work *work) * using the raw on-disk block count, which can include filesystem * preallocation and metadata rounding. */ - if (!S_ISDIR(stat.mode) && stat.size > fp->allocation_size) - fp->allocation_size = round_up(stat.size, stat.blksize); - rsp->AllocationSize = cpu_to_le64(fp->allocation_size); - rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); + if (ksmbd_stream_fd(fp)) { + loff_t seof = ksmbd_stream_eof(fp); + + rsp->AllocationSize = cpu_to_le64((u64)seof); + rsp->EndofFile = cpu_to_le64((u64)seof); + } else { + if (!S_ISDIR(stat.mode) && stat.size > fp->allocation_size) + fp->allocation_size = round_up(stat.size, stat.blksize); + rsp->AllocationSize = cpu_to_le64(fp->allocation_size); + rsp->EndofFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); + } rsp->FileAttributes = fp->f_ci->m_fattr; rsp->Reserved2 = 0; @@ -5456,8 +5479,10 @@ static int get_file_standard_info(struct smb2_query_info_rsp *rsp, sinfo->AllocationSize = cpu_to_le64(fp->allocation_size); sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); } else { - sinfo->AllocationSize = cpu_to_le64(fp->stream.size); - sinfo->EndOfFile = cpu_to_le64(fp->stream.size); + loff_t seof = ksmbd_stream_eof(fp); + + sinfo->AllocationSize = cpu_to_le64((u64)seof); + sinfo->EndOfFile = cpu_to_le64((u64)seof); } sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); sinfo->DeletePending = delete_pending; @@ -5535,8 +5560,10 @@ static int get_file_all_info(struct ksmbd_work *work, file_info->AllocationSize = cpu_to_le64(fp->allocation_size); file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); } else { - file_info->AllocationSize = cpu_to_le64(fp->stream.size); - file_info->EndOfFile = cpu_to_le64(fp->stream.size); + loff_t seof = ksmbd_stream_eof(fp); + + file_info->AllocationSize = cpu_to_le64((u64)seof); + file_info->EndOfFile = cpu_to_le64((u64)seof); } file_info->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); @@ -5813,8 +5840,10 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp, file_info->AllocationSize = cpu_to_le64(fp->allocation_size); file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); } else { - file_info->AllocationSize = cpu_to_le64(fp->stream.size); - file_info->EndOfFile = cpu_to_le64(fp->stream.size); + loff_t seof = ksmbd_stream_eof(fp); + + file_info->AllocationSize = cpu_to_le64((u64)seof); + file_info->EndOfFile = cpu_to_le64((u64)seof); } file_info->Reserved = cpu_to_le32(0); rsp->OutputBufferLength = @@ -5945,8 +5974,10 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp, file_info->EndOfFile = cpu_to_le64(stat.size); file_info->AllocationSize = cpu_to_le64(fp->allocation_size); } else { - file_info->EndOfFile = cpu_to_le64(fp->stream.size); - file_info->AllocationSize = cpu_to_le64(fp->stream.size); + loff_t seof = ksmbd_stream_eof(fp); + + file_info->EndOfFile = cpu_to_le64((u64)seof); + file_info->AllocationSize = cpu_to_le64((u64)seof); } file_info->HardLinks = cpu_to_le32(stat.nlink); file_info->Mode = cpu_to_le32(stat.mode & 0777); -- 2.43.0