mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
ksmbd: handle set/get info file for streamed file
The bug only appears when: - windows 11 copies a file that has an alternate data stream - streams_xattr is enabled on the share configuration. Microsoft Edge adds a ZoneIdentifier data stream containing the URL for files it downloads. Another way to create a test file: - open cmd.exe - echo "hello from default data stream" > hello.txt - echo "hello again from ads" > hello.txt:ads.txt If you open the file using notepad, we'll see the first message. If you run "notepad hello.txt:ads.txt" in cmd.exe, we should see the second message. dir /s /r should least all streams for the file. The truncation happens because the windows 11 client sends a SetInfo/EndOfFile message on the ADS, but it is instead applied on the main file, because we don't check fp->stream. When receiving set/get info file for a stream file, Change to process requests using stream position and size. Truncate is unnecessary for stream files, so we skip set_file_allocation_info and set_end_of_file_info operations. Reported-by: Marios Makassikis <mmakassikis@freebox.fr> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
This commit is contained in:
parent
7ac5b66aca
commit
4ea0bb8aae
3 changed files with 54 additions and 15 deletions
|
@ -4872,8 +4872,13 @@ static int get_file_standard_info(struct smb2_query_info_rsp *rsp,
|
|||
sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
|
||||
delete_pending = ksmbd_inode_pending_delete(fp);
|
||||
|
||||
sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
|
||||
if (ksmbd_stream_fd(fp) == false) {
|
||||
sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
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);
|
||||
}
|
||||
sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
|
||||
sinfo->DeletePending = delete_pending;
|
||||
sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
|
||||
|
@ -4936,9 +4941,14 @@ static int get_file_all_info(struct ksmbd_work *work,
|
|||
file_info->ChangeTime = cpu_to_le64(time);
|
||||
file_info->Attributes = fp->f_ci->m_fattr;
|
||||
file_info->Pad1 = 0;
|
||||
file_info->AllocationSize =
|
||||
cpu_to_le64(stat.blocks << 9);
|
||||
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
|
||||
if (ksmbd_stream_fd(fp) == false) {
|
||||
file_info->AllocationSize =
|
||||
cpu_to_le64(stat.blocks << 9);
|
||||
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);
|
||||
}
|
||||
file_info->NumberOfLinks =
|
||||
cpu_to_le32(get_nlink(&stat) - delete_pending);
|
||||
file_info->DeletePending = delete_pending;
|
||||
|
@ -4947,7 +4957,10 @@ static int get_file_all_info(struct ksmbd_work *work,
|
|||
file_info->IndexNumber = cpu_to_le64(stat.ino);
|
||||
file_info->EASize = 0;
|
||||
file_info->AccessFlags = fp->daccess;
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
|
||||
if (ksmbd_stream_fd(fp) == false)
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
|
||||
else
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos);
|
||||
file_info->Mode = fp->coption;
|
||||
file_info->AlignmentRequirement = 0;
|
||||
conv_len = smbConvertToUTF16((__le16 *)file_info->FileName, filename,
|
||||
|
@ -5135,8 +5148,13 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
|
|||
time = ksmbd_UnixTimeToNT(stat.ctime);
|
||||
file_info->ChangeTime = cpu_to_le64(time);
|
||||
file_info->Attributes = fp->f_ci->m_fattr;
|
||||
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
|
||||
if (ksmbd_stream_fd(fp) == false) {
|
||||
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
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);
|
||||
}
|
||||
file_info->Reserved = cpu_to_le32(0);
|
||||
rsp->OutputBufferLength =
|
||||
cpu_to_le32(sizeof(struct smb2_file_ntwrk_info));
|
||||
|
@ -5159,7 +5177,11 @@ static void get_file_position_info(struct smb2_query_info_rsp *rsp,
|
|||
struct smb2_file_pos_info *file_info;
|
||||
|
||||
file_info = (struct smb2_file_pos_info *)rsp->Buffer;
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
|
||||
if (ksmbd_stream_fd(fp) == false)
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
|
||||
else
|
||||
file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos);
|
||||
|
||||
rsp->OutputBufferLength =
|
||||
cpu_to_le32(sizeof(struct smb2_file_pos_info));
|
||||
}
|
||||
|
@ -5248,8 +5270,13 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
|
|||
file_info->ChangeTime = cpu_to_le64(time);
|
||||
file_info->DosAttributes = fp->f_ci->m_fattr;
|
||||
file_info->Inode = cpu_to_le64(stat.ino);
|
||||
file_info->EndOfFile = cpu_to_le64(stat.size);
|
||||
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
if (ksmbd_stream_fd(fp) == false) {
|
||||
file_info->EndOfFile = cpu_to_le64(stat.size);
|
||||
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
|
||||
} else {
|
||||
file_info->EndOfFile = cpu_to_le64(fp->stream.size);
|
||||
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
|
||||
}
|
||||
file_info->HardLinks = cpu_to_le32(stat.nlink);
|
||||
file_info->Mode = cpu_to_le32(stat.mode & 0777);
|
||||
switch (stat.mode & S_IFMT) {
|
||||
|
@ -6191,6 +6218,9 @@ static int set_file_allocation_info(struct ksmbd_work *work,
|
|||
if (!(fp->daccess & FILE_WRITE_DATA_LE))
|
||||
return -EACCES;
|
||||
|
||||
if (ksmbd_stream_fd(fp) == true)
|
||||
return 0;
|
||||
|
||||
rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
|
||||
AT_STATX_SYNC_AS_STAT);
|
||||
if (rc)
|
||||
|
@ -6249,7 +6279,8 @@ static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,
|
|||
* truncate of some filesystem like FAT32 fill zero data in
|
||||
* truncated range.
|
||||
*/
|
||||
if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) {
|
||||
if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC &&
|
||||
ksmbd_stream_fd(fp) == false) {
|
||||
ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize);
|
||||
rc = ksmbd_vfs_truncate(work, fp, newsize);
|
||||
if (rc) {
|
||||
|
@ -6322,7 +6353,13 @@ static int set_file_position_info(struct ksmbd_file *fp,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
fp->filp->f_pos = current_byte_offset;
|
||||
if (ksmbd_stream_fd(fp) == false)
|
||||
fp->filp->f_pos = current_byte_offset;
|
||||
else {
|
||||
if (current_byte_offset > XATTR_SIZE_MAX)
|
||||
current_byte_offset = XATTR_SIZE_MAX;
|
||||
fp->stream.pos = current_byte_offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -293,6 +293,7 @@ static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,
|
|||
|
||||
if (v_len - *pos < count)
|
||||
count = v_len - *pos;
|
||||
fp->stream.pos = v_len;
|
||||
|
||||
memcpy(buf, &stream_buf[*pos], count);
|
||||
|
||||
|
@ -456,8 +457,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
|
|||
true);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
|
||||
fp->filp->f_pos = *pos;
|
||||
else
|
||||
fp->stream.pos = size;
|
||||
err = 0;
|
||||
out:
|
||||
kvfree(stream_buf);
|
||||
|
|
|
@ -44,6 +44,7 @@ struct ksmbd_lock {
|
|||
struct stream {
|
||||
char *name;
|
||||
ssize_t size;
|
||||
loff_t pos;
|
||||
};
|
||||
|
||||
struct ksmbd_inode {
|
||||
|
|
Loading…
Add table
Reference in a new issue