mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
[SMB3] send channel sequence number in SMB3 requests after reconnects
The ChannelSequence field in the SMB3 header is supposed to be increased after reconnect to allow the server to distinguish requests from before and after the reconnect. We had always been setting it to zero. There are cases where incrementing ChannelSequence on requests after network reconnects can reduce the chance of data corruptions. See MS-SMB2 3.2.4.1 and 3.2.7.1 Signed-off-by: Steve French <stfrench@microsoft.com> Cc: stable@vger.kernel.org # 5.16+
This commit is contained in:
parent
b6d44d4231
commit
09ee7a3bf8
@ -747,6 +747,7 @@ struct TCP_Server_Info {
|
||||
*/
|
||||
#define CIFS_SERVER_IS_CHAN(server) (!!(server)->primary_server)
|
||||
struct TCP_Server_Info *primary_server;
|
||||
__u16 channel_sequence_num; /* incremented on primary channel on each chan reconnect */
|
||||
|
||||
#ifdef CONFIG_CIFS_SWN_UPCALL
|
||||
bool use_swn_dstaddr;
|
||||
|
@ -1686,6 +1686,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
|
||||
ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
|
||||
tcp_ses->session_estab = false;
|
||||
tcp_ses->sequence_number = 0;
|
||||
tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */
|
||||
tcp_ses->reconnect_instance = 1;
|
||||
tcp_ses->lstrp = jiffies;
|
||||
tcp_ses->compress_algorithm = cpu_to_le16(ctx->compression);
|
||||
|
@ -172,8 +172,17 @@ smb2_set_credits(struct TCP_Server_Info *server, const int val)
|
||||
|
||||
spin_lock(&server->req_lock);
|
||||
server->credits = val;
|
||||
if (val == 1)
|
||||
if (val == 1) {
|
||||
server->reconnect_instance++;
|
||||
/*
|
||||
* ChannelSequence updated for all channels in primary channel so that consistent
|
||||
* across SMB3 requests sent on any channel. See MS-SMB2 3.2.4.1 and 3.2.7.1
|
||||
*/
|
||||
if (CIFS_SERVER_IS_CHAN(server))
|
||||
server->primary_server->channel_sequence_num++;
|
||||
else
|
||||
server->channel_sequence_num++;
|
||||
}
|
||||
scredits = server->credits;
|
||||
in_flight = server->in_flight;
|
||||
spin_unlock(&server->req_lock);
|
||||
|
@ -88,9 +88,20 @@ smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
|
||||
const struct cifs_tcon *tcon,
|
||||
struct TCP_Server_Info *server)
|
||||
{
|
||||
struct smb3_hdr_req *smb3_hdr;
|
||||
shdr->ProtocolId = SMB2_PROTO_NUMBER;
|
||||
shdr->StructureSize = cpu_to_le16(64);
|
||||
shdr->Command = smb2_cmd;
|
||||
if (server->dialect >= SMB30_PROT_ID) {
|
||||
/* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
|
||||
smb3_hdr = (struct smb3_hdr_req *)shdr;
|
||||
/* if primary channel is not set yet, use default channel for chan sequence num */
|
||||
if (CIFS_SERVER_IS_CHAN(server))
|
||||
smb3_hdr->ChannelSequence =
|
||||
cpu_to_le16(server->primary_server->channel_sequence_num);
|
||||
else
|
||||
smb3_hdr->ChannelSequence = cpu_to_le16(server->channel_sequence_num);
|
||||
}
|
||||
if (server) {
|
||||
spin_lock(&server->req_lock);
|
||||
/* Request up to 10 credits but don't go over the limit. */
|
||||
|
@ -153,6 +153,28 @@ struct smb2_hdr {
|
||||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
struct smb3_hdr_req {
|
||||
__le32 ProtocolId; /* 0xFE 'S' 'M' 'B' */
|
||||
__le16 StructureSize; /* 64 */
|
||||
__le16 CreditCharge; /* MBZ */
|
||||
__le16 ChannelSequence; /* See MS-SMB2 3.2.4.1 and 3.2.7.1 */
|
||||
__le16 Reserved;
|
||||
__le16 Command;
|
||||
__le16 CreditRequest; /* CreditResponse */
|
||||
__le32 Flags;
|
||||
__le32 NextCommand;
|
||||
__le64 MessageId;
|
||||
union {
|
||||
struct {
|
||||
__le32 ProcessId;
|
||||
__le32 TreeId;
|
||||
} __packed SyncId;
|
||||
__le64 AsyncId;
|
||||
} __packed Id;
|
||||
__le64 SessionId;
|
||||
__u8 Signature[16];
|
||||
} __packed;
|
||||
|
||||
struct smb2_pdu {
|
||||
struct smb2_hdr hdr;
|
||||
__le16 StructureSize2; /* size of wct area (varies, request specific) */
|
||||
|
Loading…
Reference in New Issue
Block a user