Skip to content

Commit 4ea0bb8

Browse files
namjaejeonSteve French
authored andcommitted
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 <[email protected]> Signed-off-by: Namjae Jeon <[email protected]> Signed-off-by: Steve French <[email protected]>
1 parent 7ac5b66 commit 4ea0bb8

File tree

3 files changed

+54
-15
lines changed

3 files changed

+54
-15
lines changed

fs/smb/server/smb2pdu.c

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4872,8 +4872,13 @@ static int get_file_standard_info(struct smb2_query_info_rsp *rsp,
48724872
sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
48734873
delete_pending = ksmbd_inode_pending_delete(fp);
48744874

4875-
sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
4876-
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4875+
if (ksmbd_stream_fd(fp) == false) {
4876+
sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9);
4877+
sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4878+
} else {
4879+
sinfo->AllocationSize = cpu_to_le64(fp->stream.size);
4880+
sinfo->EndOfFile = cpu_to_le64(fp->stream.size);
4881+
}
48774882
sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
48784883
sinfo->DeletePending = delete_pending;
48794884
sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0;
@@ -4936,9 +4941,14 @@ static int get_file_all_info(struct ksmbd_work *work,
49364941
file_info->ChangeTime = cpu_to_le64(time);
49374942
file_info->Attributes = fp->f_ci->m_fattr;
49384943
file_info->Pad1 = 0;
4939-
file_info->AllocationSize =
4940-
cpu_to_le64(stat.blocks << 9);
4941-
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4944+
if (ksmbd_stream_fd(fp) == false) {
4945+
file_info->AllocationSize =
4946+
cpu_to_le64(stat.blocks << 9);
4947+
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
4948+
} else {
4949+
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
4950+
file_info->EndOfFile = cpu_to_le64(fp->stream.size);
4951+
}
49424952
file_info->NumberOfLinks =
49434953
cpu_to_le32(get_nlink(&stat) - delete_pending);
49444954
file_info->DeletePending = delete_pending;
@@ -4947,7 +4957,10 @@ static int get_file_all_info(struct ksmbd_work *work,
49474957
file_info->IndexNumber = cpu_to_le64(stat.ino);
49484958
file_info->EASize = 0;
49494959
file_info->AccessFlags = fp->daccess;
4950-
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
4960+
if (ksmbd_stream_fd(fp) == false)
4961+
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
4962+
else
4963+
file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos);
49514964
file_info->Mode = fp->coption;
49524965
file_info->AlignmentRequirement = 0;
49534966
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,
51355148
time = ksmbd_UnixTimeToNT(stat.ctime);
51365149
file_info->ChangeTime = cpu_to_le64(time);
51375150
file_info->Attributes = fp->f_ci->m_fattr;
5138-
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
5139-
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
5151+
if (ksmbd_stream_fd(fp) == false) {
5152+
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
5153+
file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
5154+
} else {
5155+
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
5156+
file_info->EndOfFile = cpu_to_le64(fp->stream.size);
5157+
}
51405158
file_info->Reserved = cpu_to_le32(0);
51415159
rsp->OutputBufferLength =
51425160
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,
51595177
struct smb2_file_pos_info *file_info;
51605178

51615179
file_info = (struct smb2_file_pos_info *)rsp->Buffer;
5162-
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
5180+
if (ksmbd_stream_fd(fp) == false)
5181+
file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos);
5182+
else
5183+
file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos);
5184+
51635185
rsp->OutputBufferLength =
51645186
cpu_to_le32(sizeof(struct smb2_file_pos_info));
51655187
}
@@ -5248,8 +5270,13 @@ static int find_file_posix_info(struct smb2_query_info_rsp *rsp,
52485270
file_info->ChangeTime = cpu_to_le64(time);
52495271
file_info->DosAttributes = fp->f_ci->m_fattr;
52505272
file_info->Inode = cpu_to_le64(stat.ino);
5251-
file_info->EndOfFile = cpu_to_le64(stat.size);
5252-
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
5273+
if (ksmbd_stream_fd(fp) == false) {
5274+
file_info->EndOfFile = cpu_to_le64(stat.size);
5275+
file_info->AllocationSize = cpu_to_le64(stat.blocks << 9);
5276+
} else {
5277+
file_info->EndOfFile = cpu_to_le64(fp->stream.size);
5278+
file_info->AllocationSize = cpu_to_le64(fp->stream.size);
5279+
}
52535280
file_info->HardLinks = cpu_to_le32(stat.nlink);
52545281
file_info->Mode = cpu_to_le32(stat.mode & 0777);
52555282
switch (stat.mode & S_IFMT) {
@@ -6191,6 +6218,9 @@ static int set_file_allocation_info(struct ksmbd_work *work,
61916218
if (!(fp->daccess & FILE_WRITE_DATA_LE))
61926219
return -EACCES;
61936220

6221+
if (ksmbd_stream_fd(fp) == true)
6222+
return 0;
6223+
61946224
rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS,
61956225
AT_STATX_SYNC_AS_STAT);
61966226
if (rc)
@@ -6249,7 +6279,8 @@ static int set_end_of_file_info(struct ksmbd_work *work, struct ksmbd_file *fp,
62496279
* truncate of some filesystem like FAT32 fill zero data in
62506280
* truncated range.
62516281
*/
6252-
if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) {
6282+
if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC &&
6283+
ksmbd_stream_fd(fp) == false) {
62536284
ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize);
62546285
rc = ksmbd_vfs_truncate(work, fp, newsize);
62556286
if (rc) {
@@ -6322,7 +6353,13 @@ static int set_file_position_info(struct ksmbd_file *fp,
63226353
return -EINVAL;
63236354
}
63246355

6325-
fp->filp->f_pos = current_byte_offset;
6356+
if (ksmbd_stream_fd(fp) == false)
6357+
fp->filp->f_pos = current_byte_offset;
6358+
else {
6359+
if (current_byte_offset > XATTR_SIZE_MAX)
6360+
current_byte_offset = XATTR_SIZE_MAX;
6361+
fp->stream.pos = current_byte_offset;
6362+
}
63266363
return 0;
63276364
}
63286365

fs/smb/server/vfs.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@ static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,
293293

294294
if (v_len - *pos < count)
295295
count = v_len - *pos;
296+
fp->stream.pos = v_len;
296297

297298
memcpy(buf, &stream_buf[*pos], count);
298299

@@ -456,8 +457,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
456457
true);
457458
if (err < 0)
458459
goto out;
459-
460-
fp->filp->f_pos = *pos;
460+
else
461+
fp->stream.pos = size;
461462
err = 0;
462463
out:
463464
kvfree(stream_buf);

fs/smb/server/vfs_cache.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct ksmbd_lock {
4444
struct stream {
4545
char *name;
4646
ssize_t size;
47+
loff_t pos;
4748
};
4849

4950
struct ksmbd_inode {

0 commit comments

Comments
 (0)