Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag '6.16-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd

Pull smb server fixes from Steve French:

- Fix alternate data streams bug

- Important fix for null pointer deref with Kerberos authentication

- Fix oops in smbdirect (RDMA) in free_transport

* tag '6.16-rc2-ksmbd-server-fixes' of git://git.samba.org/ksmbd:
ksmbd: handle set/get info file for streamed file
ksmbd: fix null pointer dereference in destroy_previous_session
ksmbd: add free_transport ops in ksmbd connection

+72 -24
+1 -1
fs/smb/server/connection.c
··· 40 40 kvfree(conn->request_buf); 41 41 kfree(conn->preauth_info); 42 42 if (atomic_dec_and_test(&conn->refcnt)) { 43 - ksmbd_free_transport(conn->transport); 43 + conn->transport->ops->free_transport(conn->transport); 44 44 kfree(conn); 45 45 } 46 46 }
+1
fs/smb/server/connection.h
··· 133 133 void *buf, unsigned int len, 134 134 struct smb2_buffer_desc_v1 *desc, 135 135 unsigned int desc_len); 136 + void (*free_transport)(struct ksmbd_transport *kt); 136 137 }; 137 138 138 139 struct ksmbd_transport {
+56 -18
fs/smb/server/smb2pdu.c
··· 1607 1607 out_len = work->response_sz - 1608 1608 (le16_to_cpu(rsp->SecurityBufferOffset) + 4); 1609 1609 1610 - /* Check previous session */ 1611 - prev_sess_id = le64_to_cpu(req->PreviousSessionId); 1612 - if (prev_sess_id && prev_sess_id != sess->id) 1613 - destroy_previous_session(conn, sess->user, prev_sess_id); 1614 - 1615 1610 retval = ksmbd_krb5_authenticate(sess, in_blob, in_len, 1616 1611 out_blob, &out_len); 1617 1612 if (retval) { 1618 1613 ksmbd_debug(SMB, "krb5 authentication failed\n"); 1619 1614 return -EINVAL; 1620 1615 } 1616 + 1617 + /* Check previous session */ 1618 + prev_sess_id = le64_to_cpu(req->PreviousSessionId); 1619 + if (prev_sess_id && prev_sess_id != sess->id) 1620 + destroy_previous_session(conn, sess->user, prev_sess_id); 1621 + 1621 1622 rsp->SecurityBufferLength = cpu_to_le16(out_len); 1622 1623 1623 1624 if ((conn->sign || server_conf.enforced_signing) || ··· 4872 4871 sinfo = (struct smb2_file_standard_info *)rsp->Buffer; 4873 4872 delete_pending = ksmbd_inode_pending_delete(fp); 4874 4873 4875 - sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9); 4876 - sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 4874 + if (ksmbd_stream_fd(fp) == false) { 4875 + sinfo->AllocationSize = cpu_to_le64(stat.blocks << 9); 4876 + sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 4877 + } else { 4878 + sinfo->AllocationSize = cpu_to_le64(fp->stream.size); 4879 + sinfo->EndOfFile = cpu_to_le64(fp->stream.size); 4880 + } 4877 4881 sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending); 4878 4882 sinfo->DeletePending = delete_pending; 4879 4883 sinfo->Directory = S_ISDIR(stat.mode) ? 1 : 0; ··· 4941 4935 file_info->ChangeTime = cpu_to_le64(time); 4942 4936 file_info->Attributes = fp->f_ci->m_fattr; 4943 4937 file_info->Pad1 = 0; 4944 - file_info->AllocationSize = 4945 - cpu_to_le64(stat.blocks << 9); 4946 - file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 4938 + if (ksmbd_stream_fd(fp) == false) { 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); 4942 + } else { 4943 + file_info->AllocationSize = cpu_to_le64(fp->stream.size); 4944 + file_info->EndOfFile = cpu_to_le64(fp->stream.size); 4945 + } 4947 4946 file_info->NumberOfLinks = 4948 4947 cpu_to_le32(get_nlink(&stat) - delete_pending); 4949 4948 file_info->DeletePending = delete_pending; ··· 4957 4946 file_info->IndexNumber = cpu_to_le64(stat.ino); 4958 4947 file_info->EASize = 0; 4959 4948 file_info->AccessFlags = fp->daccess; 4960 - file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); 4949 + if (ksmbd_stream_fd(fp) == false) 4950 + file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); 4951 + else 4952 + file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos); 4961 4953 file_info->Mode = fp->coption; 4962 4954 file_info->AlignmentRequirement = 0; 4963 4955 conv_len = smbConvertToUTF16((__le16 *)file_info->FileName, filename, ··· 5148 5134 time = ksmbd_UnixTimeToNT(stat.ctime); 5149 5135 file_info->ChangeTime = cpu_to_le64(time); 5150 5136 file_info->Attributes = fp->f_ci->m_fattr; 5151 - file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 5152 - file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 5137 + if (ksmbd_stream_fd(fp) == false) { 5138 + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 5139 + file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size); 5140 + } else { 5141 + file_info->AllocationSize = cpu_to_le64(fp->stream.size); 5142 + file_info->EndOfFile = cpu_to_le64(fp->stream.size); 5143 + } 5153 5144 file_info->Reserved = cpu_to_le32(0); 5154 5145 rsp->OutputBufferLength = 5155 5146 cpu_to_le32(sizeof(struct smb2_file_ntwrk_info)); ··· 5177 5158 struct smb2_file_pos_info *file_info; 5178 5159 5179 5160 file_info = (struct smb2_file_pos_info *)rsp->Buffer; 5180 - file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); 5161 + if (ksmbd_stream_fd(fp) == false) 5162 + file_info->CurrentByteOffset = cpu_to_le64(fp->filp->f_pos); 5163 + else 5164 + file_info->CurrentByteOffset = cpu_to_le64(fp->stream.pos); 5165 + 5181 5166 rsp->OutputBufferLength = 5182 5167 cpu_to_le32(sizeof(struct smb2_file_pos_info)); 5183 5168 } ··· 5270 5247 file_info->ChangeTime = cpu_to_le64(time); 5271 5248 file_info->DosAttributes = fp->f_ci->m_fattr; 5272 5249 file_info->Inode = cpu_to_le64(stat.ino); 5273 - file_info->EndOfFile = cpu_to_le64(stat.size); 5274 - file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 5250 + if (ksmbd_stream_fd(fp) == false) { 5251 + file_info->EndOfFile = cpu_to_le64(stat.size); 5252 + file_info->AllocationSize = cpu_to_le64(stat.blocks << 9); 5253 + } else { 5254 + file_info->EndOfFile = cpu_to_le64(fp->stream.size); 5255 + file_info->AllocationSize = cpu_to_le64(fp->stream.size); 5256 + } 5275 5257 file_info->HardLinks = cpu_to_le32(stat.nlink); 5276 5258 file_info->Mode = cpu_to_le32(stat.mode & 0777); 5277 5259 switch (stat.mode & S_IFMT) { ··· 6218 6190 if (!(fp->daccess & FILE_WRITE_DATA_LE)) 6219 6191 return -EACCES; 6220 6192 6193 + if (ksmbd_stream_fd(fp) == true) 6194 + return 0; 6195 + 6221 6196 rc = vfs_getattr(&fp->filp->f_path, &stat, STATX_BASIC_STATS, 6222 6197 AT_STATX_SYNC_AS_STAT); 6223 6198 if (rc) ··· 6279 6248 * truncate of some filesystem like FAT32 fill zero data in 6280 6249 * truncated range. 6281 6250 */ 6282 - if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC) { 6251 + if (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC && 6252 + ksmbd_stream_fd(fp) == false) { 6283 6253 ksmbd_debug(SMB, "truncated to newsize %lld\n", newsize); 6284 6254 rc = ksmbd_vfs_truncate(work, fp, newsize); 6285 6255 if (rc) { ··· 6353 6321 return -EINVAL; 6354 6322 } 6355 6323 6356 - fp->filp->f_pos = current_byte_offset; 6324 + if (ksmbd_stream_fd(fp) == false) 6325 + fp->filp->f_pos = current_byte_offset; 6326 + else { 6327 + if (current_byte_offset > XATTR_SIZE_MAX) 6328 + current_byte_offset = XATTR_SIZE_MAX; 6329 + fp->stream.pos = current_byte_offset; 6330 + } 6357 6331 return 0; 6358 6332 } 6359 6333
+8 -2
fs/smb/server/transport_rdma.c
··· 159 159 }; 160 160 161 161 #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport)) 162 - 162 + #define SMBD_TRANS(t) ((struct smb_direct_transport *)container_of(t, \ 163 + struct smb_direct_transport, transport)) 163 164 enum { 164 165 SMB_DIRECT_MSG_NEGOTIATE_REQ = 0, 165 166 SMB_DIRECT_MSG_DATA_TRANSFER ··· 411 410 return NULL; 412 411 } 413 412 413 + static void smb_direct_free_transport(struct ksmbd_transport *kt) 414 + { 415 + kfree(SMBD_TRANS(kt)); 416 + } 417 + 414 418 static void free_transport(struct smb_direct_transport *t) 415 419 { 416 420 struct smb_direct_recvmsg *recvmsg; ··· 461 455 462 456 smb_direct_destroy_pools(t); 463 457 ksmbd_conn_free(KSMBD_TRANS(t)->conn); 464 - kfree(t); 465 458 } 466 459 467 460 static struct smb_direct_sendmsg ··· 2286 2281 .read = smb_direct_read, 2287 2282 .rdma_read = smb_direct_rdma_read, 2288 2283 .rdma_write = smb_direct_rdma_write, 2284 + .free_transport = smb_direct_free_transport, 2289 2285 };
+2 -1
fs/smb/server/transport_tcp.c
··· 93 93 return t; 94 94 } 95 95 96 - void ksmbd_free_transport(struct ksmbd_transport *kt) 96 + static void ksmbd_tcp_free_transport(struct ksmbd_transport *kt) 97 97 { 98 98 struct tcp_transport *t = TCP_TRANS(kt); 99 99 ··· 656 656 .read = ksmbd_tcp_read, 657 657 .writev = ksmbd_tcp_writev, 658 658 .disconnect = ksmbd_tcp_disconnect, 659 + .free_transport = ksmbd_tcp_free_transport, 659 660 };
+3 -2
fs/smb/server/vfs.c
··· 293 293 294 294 if (v_len - *pos < count) 295 295 count = v_len - *pos; 296 + fp->stream.pos = v_len; 296 297 297 298 memcpy(buf, &stream_buf[*pos], count); 298 299 ··· 457 456 true); 458 457 if (err < 0) 459 458 goto out; 460 - 461 - fp->filp->f_pos = *pos; 459 + else 460 + fp->stream.pos = size; 462 461 err = 0; 463 462 out: 464 463 kvfree(stream_buf);
+1
fs/smb/server/vfs_cache.h
··· 44 44 struct stream { 45 45 char *name; 46 46 ssize_t size; 47 + loff_t pos; 47 48 }; 48 49 49 50 struct ksmbd_inode {