Linux network filesystem support library
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: Steve French <sfrench@samba.org>
Cc: David Howells <dhowells@redhat.com>,
	Paulo Alcantara <pc@manguebit.org>,
	Shyam Prasad N <sprasad@microsoft.com>,
	Tom Talpey <tom@talpey.com>, Stefan Metzmacher <metze@samba.org>,
	Mina Almasry <almasrymina@google.com>,
	linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org,
	netfs@lists.linux.dev, linux-fsdevel@vger.kernel.org
Subject: [RFC PATCH 25/36] cifs: Add more pieces to smb_message
Date: Tue, 19 May 2026 11:21:43 +0100	[thread overview]
Message-ID: <20260519102158.592165-26-dhowells@redhat.com> (raw)
In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com>

Add more pieces to the smb_message struct to facilitate future changes.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/cifsglob.h      |  10 ++
 fs/smb/client/cifsproto.h     |  18 +++
 fs/smb/client/smb2misc.c      |  15 +++
 fs/smb/client/smb2ops.c       |  10 ++
 fs/smb/client/smb2pdu.c       | 202 ++++++++++++++++++++++++++++++++++
 fs/smb/client/smb2proto.h     |   1 +
 fs/smb/client/smb2transport.c | 122 ++++++++++++++------
 fs/smb/client/transport.c     |  89 +++++++++++----
 8 files changed, 413 insertions(+), 54 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 3a2f684cede9..9aa9eb72ec6b 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -1672,6 +1672,7 @@ struct smb_message {
 	wait_queue_head_t	waitq;		/* Wait queue for message events */
 	refcount_t		ref;
 	unsigned int		debug_id;	/* Debugging ID for tracing */
+	bool			new_style;	/* New style request (not using ->rqst) */
 	bool			sensitive;	/* Request contains sensitive data */
 	bool			cancelled;	/* T if cancelled */
 	unsigned int		sr_flags;	/* Flags passed to send_recv() */
@@ -1711,7 +1712,13 @@ struct smb_message {
 	u8			command_trace;	/* enum smb_command_trace - Command trace ID */
 	__le16			command;	/* smb command code */
 	s16			pre_offset;	/* Offset of pre-headers from ->body (negative) */
+	u16			ext_offset;	/* Offset of extensions from ->body */
+	u16			latest_record;	/* Offset of latest context record (or 0) */
+	u16			offset;		/* Running offset during assembly */
+	u16			data_offset;	/* Offset of data in message (maybe in ->body) */
 	unsigned int		total_len;	/* Total length of from hdr_offset onwards */
+	struct iov_iter		data_iter;	/* Data iterator */
+	struct iov_iter		req_iter;	/* Request iterator */
 	/* Response */
 	//u32			response_pdu_len; /* Size of response PDU */
 	void			*response;	/* Protocol part of response */
@@ -1724,6 +1731,9 @@ struct smb_message {
 	struct bvecq		*response_data;	/* Storage for response data (or NULL) */
 	/* Compat with old code */
 	struct smb_rqst		rqst;
+	/* Variable-length request fragment list - must be last! */
+	struct bvecq		bvecq;		/* List of request frags (passed to socket) */
+	struct bio_vec		__bvecq_bv[3];
 };
 
 struct close_cancelled_open {
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 3067056f8ef9..bbb59761fb9f 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -86,6 +86,7 @@ void smb_see_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_get_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_message(struct smb_message *smb, enum smb_message_trace trace);
 void smb_put_messages(struct smb_message *smb);
+void smb_clear_request(struct smb_message *smb);
 void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb);
 void cifs_wake_up_task(struct TCP_Server_Info *server,
 		       struct smb_message *smb);
@@ -93,6 +94,9 @@ char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dirsep);
 int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
 int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
 bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
+int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
+			   struct TCP_Server_Info *server,
+			   struct smb_message *head_smb, const int flags);
 int cifs_call_async(struct TCP_Server_Info *server, struct smb_message *smb,
 		    const int flags, const struct cifs_credits *exist_credits);
 struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses);
@@ -511,4 +515,18 @@ int smb_rxqueue_consume(struct TCP_Server_Info *server, struct netfs_rxqueue *rx
 void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size);
 void cifs_free_tx_buf(void *p);
 
+/*
+ * Add a segment to a message.  This should be allocated with
+ * cifs_allocate_tx_buf() so that it can be used with MSG_SPLICE_PAGES.
+ */
+static inline void smb_add_segment_to_tx_buf(struct smb_message *smb,
+					     void *buf, size_t size)
+{
+	unsigned int nr = smb->bvecq.nr_slots;
+
+	bvec_set_virt(&smb->bvecq.bv[nr], buf, size);
+	smb->bvecq.nr_slots = nr + 1;
+	smb->total_len += size;
+}
+
 #endif			/* _CIFSPROTO_H */
diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c
index d28812107e8f..7c9dc3ede8b8 100644
--- a/fs/smb/client/smb2misc.c
+++ b/fs/smb/client/smb2misc.c
@@ -9,6 +9,7 @@
  */
 #include <crypto/sha2.h>
 #include <linux/ctype.h>
+#include <linux/iov_iter.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "smb2proto.h"
@@ -836,6 +837,15 @@ smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *serve
 	return rc;
 }
 
+static size_t smb_sha512_step(void *iter_base, size_t progress, size_t len,
+			      void *priv, void *priv2)
+{
+	struct sha512_ctx *ctx = priv;
+
+	sha512_update(ctx, iter_base, len);
+	return 0;
+}
+
 /**
  * smb311_update_preauth_hash - update @ses hash from the message
  * @ses:	server session structure
@@ -878,6 +888,11 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server,
 
 	if (hash_resp) {
 		sha512_update(&sha_ctx,  smb->response, smb->resp_len);
+	} else if (smb->new_style) {
+		struct iov_iter tmp = smb->req_iter;
+
+		iterate_and_advance_kernel(&tmp, smb->total_len,
+					   &sha_ctx, NULL, smb_sha512_step);
 	} else {
 		struct kvec *iov = smb->rqst.rq_iov;
 
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index b655c0f626f5..f9cefc47d084 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -2729,6 +2729,16 @@ smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst)
 	shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
 }
 
+void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_message *smb)
+{
+	struct smb2_hdr *shdr = smb->request;
+
+	if (server->dialect < SMB30_PROT_ID)
+		return;
+
+	shdr->Flags |= SMB2_FLAGS_REPLAY_OPERATION;
+}
+
 void
 smb2_set_related(struct smb_rqst *rqst)
 {
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index f4ea7256b09d..f907ee4faa3a 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -91,6 +91,208 @@ int smb3_encryption_required(const struct cifs_tcon *tcon)
 	return 0;
 }
 
+static void smb2_enc_header(struct smb_message *smb,
+			    const struct cifs_tcon *tcon,
+			    struct TCP_Server_Info *server)
+{
+	struct smb2_hdr *shdr = smb->request;
+	struct smb3_hdr_req *smb3_hdr = (struct smb3_hdr_req *)shdr;
+
+	shdr->ProtocolId	= SMB2_PROTO_NUMBER;
+	shdr->StructureSize	= cpu_to_le16(64);
+	shdr->CreditCharge	= 0;
+	shdr->Status		= 0; /* ChanSeq for smb3 */
+	shdr->Command		= smb->command;
+	shdr->CreditRequest	= cpu_to_le16(2);
+	shdr->Flags		= 0;
+	shdr->NextCommand	= 0;
+	shdr->MessageId		= 0;
+	shdr->Id.SyncId.ProcessId = cpu_to_le32((__u16)current->tgid);
+	shdr->SessionId		= 0;
+
+	if (server) {
+		/* After reconnect SMB3 must set ChannelSequence on subsequent reqs */
+		if (server->dialect >= SMB30_PROT_ID) {
+			/*
+			 * if primary channel is not set yet, use default
+			 * channel for chan sequence num
+			 */
+			if (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);
+		}
+		spin_lock(&server->req_lock);
+		/* Request up to 10 credits but don't go over the limit. */
+		if (server->credits >= server->max_credits)
+			shdr->CreditRequest = cpu_to_le16(0);
+		else
+			shdr->CreditRequest = cpu_to_le16(
+				min_t(int, server->max_credits -
+						server->credits, 10));
+		spin_unlock(&server->req_lock);
+	}
+
+	if (tcon) {
+		/* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */
+		/* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */
+		if (server && (server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU))
+			shdr->CreditCharge = cpu_to_le16(1);
+		/* else CreditCharge MBZ */
+
+		shdr->Id.SyncId.TreeId = cpu_to_le32(tcon->tid);
+		/* Uid is not converted */
+		if (tcon->ses)
+			shdr->SessionId = cpu_to_le64(tcon->ses->Suid);
+
+		/*
+		 * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also
+		 * would have to pass the path on the Open SMB prefixed by
+		 * \\server\share.  Not sure when we would need to do the
+		 * augmented path (if ever) and setting this flag breaks the
+		 * SMB2 open operation since it is illegal to send an empty
+		 * path name (without \\server\share prefix) when the DFS flag
+		 * is set in the SMB open header. We could consider setting the
+		 * flag on all operations other than open but it is safer to
+		 * net set it for now.
+		 */
+/*	if (tcon->share_flags & SHI1005_FLAGS_DFS)
+	shdr->Flags |= SMB2_FLAGS_DFS_OPERATIONS; */
+
+		if (server && server->sign && !smb3_encryption_required(tcon))
+			shdr->Flags |= SMB2_FLAGS_SIGNED;
+	}
+}
+
+/* Flags for smb2_create_request() */
+#define SMB2_REQ_DYNAMIC	0x01	/* Dynamic request */
+#define SMB2_REQ_HEAD		0x02	/* Head of compound */
+#define SMB2_REQ_SENSITIVE	0x04	/* May contain sensitive crypto data */
+
+/*
+ * smb2_create_request: Allocate and set up a request
+ * @command: The command type we're going to issue
+ * @server: The server the command is going to go to
+ * @header_size: The size of the base protocol structure
+ * @protocol_size: The size of the header plus extensions
+ * @data_size: The size of the data payload
+ * @head: If this is the head of a compound
+ * @flags: Mask of SMB2_REQ_* flags
+ *
+ * Create a request and allocate netmem memory to hold the netbios header (if
+ * appropriate) and the protocol part of the message.  Memory will also be
+ * allocated for the data part of the message if this is to be encrypted by the
+ * CPU.  The allocated buffers will be attached to a bvec-queue struct so that
+ * they can be chained together and passed to the socket.
+ */
+static struct smb_message *smb2_create_request(__le16 command,
+					       struct TCP_Server_Info *server,
+					       struct cifs_tcon *tcon,
+					       size_t header_size,
+					       size_t protocol_size,
+					       size_t data_size,
+					       unsigned int flags)
+{
+	struct smb_message *smb;
+	const size_t max_slots = ARRAY_SIZE(smb->__bvecq_bv); // Preallocated slots
+	size_t pre_size;
+	void *body;
+	bool encrypted = false; //, rdma = false;
+	u16 ssize;
+
+	smb = smb_message_alloc(command, GFP_NOFS);
+	if (!smb)
+		return NULL;
+
+	smb->new_style = true; /* I.e. we're not using smb->rqst. */
+	smb->command = command;
+	smb->command_trace = command;
+	smb->sensitive = flags & SMB2_REQ_SENSITIVE;
+
+	/* We allocate space for inter-SMB padding or rfc1002 header plus
+	 * transform headers (as needed), but don't add them in at this time.
+	 */
+	pre_size = 8;
+	if (encrypted)
+		pre_size += sizeof(struct smb2_transform_hdr);
+	smb->pre_offset = -pre_size;
+
+	if (encrypted)
+		/* We want the encrypted blob to be correctly aligned. */
+		pre_size = round_up(pre_size, 16);
+
+	/* Allocate space for the SMB header, the request struct (both in
+	 * header_size) plus any extension bits, bearing in mind that some bits
+	 * may follow the header directly (header_added_size) and some may have
+	 * to be padded to an 8-byte alignment first (extension_size).  The
+	 * Negotiate Request has both.
+	 */
+	smb->ext_offset	 = header_size;
+	smb->offset	 = header_size;
+	smb->data_offset = protocol_size;
+	smb->total_len	 = data_size;
+
+	body = cifs_allocate_tx_buf(server, pre_size + protocol_size);
+	if (!body) {
+		kfree(smb);
+		return NULL;
+	}
+
+	smb->bvecq.max_slots = max_slots;
+	smb_add_segment_to_tx_buf(smb, body + pre_size, protocol_size);
+	smb->request = body + pre_size;
+
+	struct smb2_pdu *spdu = smb->request;
+	memset(spdu, 0, header_size);
+
+	smb2_enc_header(smb, tcon, server);
+	ssize = header_size - sizeof(spdu->hdr);
+	if (flags & SMB2_REQ_DYNAMIC)
+		ssize |= SMB2_STRUCT_HAS_DYNAMIC_PART;
+	spdu->StructureSize2 = cpu_to_le16(ssize);
+
+	if (tcon) {
+		cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[command]);
+		cifs_stats_inc(&tcon->num_smbs_sent);
+	}
+
+#if 0
+	/* Include the buffer from the start of the RFC1002 header in the
+	 * iterator, but may need to adjust it later.
+	 */
+	iov_iter_bvec_queue(&smb->iter, ITER_SOURCE, &smb->bvecq, 0,
+			    pre_size, protocol_size);
+#endif
+	return smb;
+}
+
+static void cifs_pad_to_8(struct smb_message *smb)
+{
+	size_t offset = smb->offset;
+	u8 *p = smb->request;
+
+	while (offset & 7)
+		p[offset++] = 0;
+	smb->offset = offset;
+}
+
+/*
+ * Begin adding an extension to a message.  The offset is padded to an 8-byte
+ * alignment;
+ */
+static void *cifs_begin_extension(struct smb_message *smb)
+{
+	cifs_pad_to_8(smb);
+	return smb->request + smb->offset;
+}
+
+static void cifs_end_extension(struct smb_message *smb, size_t size)
+{
+	smb->offset += size;
+}
+
 static void
 smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd,
 		  const struct cifs_tcon *tcon,
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index bac01d15b94a..6571a6a7b147 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -121,6 +121,7 @@ unsigned long smb_rqst_len(struct TCP_Server_Info *server,
 void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst);
 void smb2_set_related(struct smb_rqst *rqst);
 void smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst);
+void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_message *smb);
 bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries,
 			int *pcur_sleep);
 void smb2_add_credits_from_hdr(struct smb2_hdr *shdr,
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 14ee09b33f2c..f63eaff4935a 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -207,16 +207,24 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
 	return tcon;
 }
 
+static inline size_t smb2_hmac_sha256_step(void *iter_base, size_t progress,
+					   size_t len, void *priv, void *priv2)
+{
+	struct hmac_sha256_ctx *hmac_ctx = priv;
+
+	hmac_sha256_update(hmac_ctx, iter_base, len);
+	return 0;
+}
+
 static int
 smb2_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 		    bool for_recv)
 {
 	int rc;
 	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
-	struct kvec *iov = smb->rqst.rq_iov;
 	struct smb2_hdr *shdr = for_recv ? smb->response : smb->request;
 	struct hmac_sha256_ctx hmac_ctx;
-	struct smb_rqst drqst;
+	size_t size, did;
 	__u64 sid = le64_to_cpu(shdr->SessionId);
 	u8 key[SMB2_NTLMV2_SESSKEY_SIZE];
 
@@ -232,27 +240,32 @@ smb2_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 
 	hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key));
 
-	/*
-	 * For SMB2+, __cifs_calc_signature() expects to sign only the actual
-	 * data, that is, iov[0] should not contain a rfc1002 length.
-	 *
-	 * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
-	 * __cifs_calc_signature().
-	 */
-	drqst = smb->rqst;
-	if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
-		hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len);
-		drqst.rq_iov++;
-		drqst.rq_nvec--;
+	if (smb->new_style) {
+		struct iov_iter req_iter = smb->req_iter;
+
+		size = iov_iter_count(&req_iter);
+		did = iterate_and_advance_kernel(&req_iter, size, &hmac_ctx, NULL,
+						 smb2_hmac_sha256_step);
+		if (did != size)
+			return smb_EIO2(smb_eio_trace_sig_iter, did, size);
+	} else {
+		for (int i = 0; i < smb->rqst.rq_nvec; i++)
+			hmac_sha256_update(&hmac_ctx,
+					   smb->rqst.rq_iov[i].iov_base,
+					   smb->rqst.rq_iov[i].iov_len);
 	}
 
-	rc = __cifs_calc_signature(
-		&drqst, server, smb2_signature,
-		&(struct cifs_calc_sig_ctx){ .hmac = &hmac_ctx });
-	if (!rc)
-		memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE);
+	struct iov_iter data_iter = smb->data_iter;
 
-	return rc;
+	size = iov_iter_count(&data_iter);
+	did = iterate_and_advance_kernel(&data_iter, size, &hmac_ctx, NULL,
+					 smb2_hmac_sha256_step);
+	if (did != size)
+		return smb_EIO2(smb_eio_trace_sig_iter, did, size);
+
+	hmac_sha256_final(&hmac_ctx, smb2_signature);
+	memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE);
+	return 0;
 }
 
 static void generate_key(struct cifs_ses *ses, struct kvec label,
@@ -460,17 +473,25 @@ generate_smb311signingkey(struct cifs_ses *ses,
 	return generate_smb3signingkey(ses, server, &triplet);
 }
 
+static inline size_t smb3_aes_cmac_step(void *iter_base, size_t progress,
+					size_t len, void *priv, void *priv2)
+{
+	struct aes_cmac_ctx *cmac_ctx = priv;
+
+	aes_cmac_update(cmac_ctx, iter_base, len);
+	return 0;
+}
+
 static int
 smb3_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 		    bool for_recv)
 {
 	int rc;
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
-	struct kvec kv;
 	struct smb2_hdr *shdr = for_recv ? smb->response : smb->request;
 	struct aes_cmac_key cmac_key;
 	struct aes_cmac_ctx cmac_ctx;
-	struct smb_rqst drqst;
+	size_t size, did;
 	u8 key[SMB3_SIGN_KEY_SIZE];
 
 	if (server->vals->protocol_id <= SMB21_PROT_ID)
@@ -494,22 +515,55 @@ smb3_calc_signature(struct smb_message *smb, struct TCP_Server_Info *server,
 	aes_cmac_init(&cmac_ctx, &cmac_key);
 
 	if (for_recv) {
-		kv.iov_base = smb->response;
-		kv.iov_len  = smb->resp_len;
-		drqst.rq_nvec = 1;
-		drqst.rq_iov  = &kv;
-		drqst.rq_iter = smb->response_iter;
-		iov_iter_truncate(&drqst.rq_iter, smb->resp_data_len);
+		struct iov_iter resp_iter = smb->response_iter;
+
+		size = smb->resp_len;
+		did = 0;
+
+		aes_cmac_update(&cmac_ctx, smb->response, size);
+		rc = -EIO;
+		size = iov_iter_count(&resp_iter);
+		did = iterate_and_advance_kernel(&resp_iter, size, &cmac_ctx,
+						  NULL, smb3_aes_cmac_step);
+		if (did != size)
+			goto eio;
 	} else {
-		drqst = smb->rqst;
+		if (smb->new_style) {
+			struct iov_iter req_iter = smb->req_iter;
+
+			size = iov_iter_count(&req_iter);
+			did = iterate_and_advance_kernel(&req_iter, size,
+							 &cmac_ctx, NULL,
+							 smb3_aes_cmac_step);
+			if (did != size)
+				goto eio;
+		} else {
+			for (int i = 0; i < smb->rqst.rq_nvec; i++) {
+				size = smb->rqst.rq_iov[i].iov_len;
+				aes_cmac_update(&cmac_ctx,
+						smb->rqst.rq_iov[i].iov_base,
+						size);
+			}
+		}
+
+		struct iov_iter data_iter = smb->data_iter;
+
+		size = iov_iter_count(&data_iter);
+		did = iterate_and_advance_kernel(&data_iter, size, &cmac_ctx,
+						 NULL, smb3_aes_cmac_step);
+		if (did != size)
+			return smb_EIO2(smb_eio_trace_sig_iter, did, size);
 	}
 
-	rc = __cifs_calc_signature(
-		&drqst, server, smb3_signature,
-		&(struct cifs_calc_sig_ctx){ .cmac = &cmac_ctx });
-	if (!rc)
-		memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
+	aes_cmac_final(&cmac_ctx, smb3_signature);
+
+	memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
+	rc = 0;
+out:
 	return rc;
+eio:
+	smb_EIO2(smb_eio_trace_sig_iter, did, size);
+	goto out;
 }
 
 /* must be called with server->srv_mutex held */
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 1599afb9e5cf..212894c8d2bd 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -67,6 +67,7 @@ struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gfp)
 		smb->command_trace = cmd;
 		smb->when_alloc	= jiffies;
 		smb->pid	= current->pid;
+		smb->bvecq.bv	= smb->__bvecq_bv;
 
 		/*
 		 * The default is for the mid to be synchronous, so the default
@@ -97,9 +98,26 @@ static void smb_free_message(struct smb_message *smb)
 {
 	trace_smb3_message(smb->debug_id, refcount_read(&smb->ref),
 			   smb_message_trace_free);
+	if (smb->new_style)
+		cifs_free_tx_buf(smb->request + smb->pre_offset);
 	mempool_free(smb, &smb_message_pool);
 }
 
+/*
+ * Clear the request parts of a message.
+ */
+void smb_clear_request(struct smb_message *smb)
+{
+	for (; smb; smb = smb->next) {
+		if (smb->request) {
+			if (smb->sensitive)
+				memzero_explicit(smb->request, smb->data_offset);
+			cifs_free_tx_buf(smb->request);
+			smb->request = NULL;
+		}
+	}
+}
+
 /*
  * Drop a ref on a message.  This does not touch the chained messages.
  */
@@ -123,6 +141,8 @@ void smb_put_messages(struct smb_message *smb)
 {
 	struct smb_message *next;
 
+	smb_clear_request(smb);
+
 	for (; smb; smb = next) {
 		unsigned int debug_id = smb->debug_id;
 		bool dead;
@@ -561,8 +581,7 @@ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
 	iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len);
 
 	for (smb = head_smb; smb; smb = smb->next) {
-		size_t size = iov_iter_count(&smb->rqst.rq_iter);
-		size_t got;
+		size_t size, got;
 
 		if (offset & 7) {
 			unsigned int tmp = offset;
@@ -570,25 +589,54 @@ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server,
 			iov_iter_zero(offset - tmp, iter);
 		}
 
-		for (int i = 0; i < smb->rqst.rq_nvec; i++) {
-			size_t len = smb->rqst.rq_iov[i].iov_len;
-			got = copy_to_iter(smb->rqst.rq_iov[i].iov_base, len, iter);
-			if (got != len) {
-				rc = smb_EIO2(smb_eio_trace_tx_copy_to_buf, got, size);
+		if (smb->new_style) {
+			struct iov_iter req_iter = smb->req_iter;
+
+			size = iov_iter_count(&req_iter);
+			got = iterate_and_advance_kernel(&req_iter,
+							 size, iter, NULL,
+							 smb3_copy_data_iter);
+			if (got != size) {
+				rc = smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size);
 				goto error;
 			}
-			offset += len;
-		}
+			offset += size;
 
-		got = iterate_and_advance_kernel(&smb->rqst.rq_iter,
-						 size, iter, NULL,
-						 smb3_copy_data_iter);
-		if (got != size) {
-			rc = smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size);
-			goto error;
-		}
+			struct iov_iter data_iter = smb->data_iter;
 
-		offset += size;
+			size = iov_iter_count(&data_iter);
+			got = iterate_and_advance_kernel(&data_iter,
+							 size, iter, NULL,
+							 smb3_copy_data_iter);
+			if (got != size) {
+				rc = smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size);
+				goto error;
+			}
+			offset += size;
+		} else {
+			/* Old-style with an rqst. */
+			size = iov_iter_count(&smb->rqst.rq_iter);
+
+			for (int i = 0; i < smb->rqst.rq_nvec; i++) {
+				size_t len = smb->rqst.rq_iov[i].iov_len;
+				got = copy_to_iter(smb->rqst.rq_iov[i].iov_base,
+						   len, iter);
+				if (got != len) {
+					rc = smb_EIO2(smb_eio_trace_tx_copy_to_buf, got, size);
+					goto error;
+				}
+				offset += len;
+			}
+
+			got = iterate_and_advance_kernel(&smb->rqst.rq_iter,
+							 size, iter, NULL,
+							 smb3_copy_data_iter);
+			if (got != size) {
+				rc = smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size);
+				goto error;
+			}
+			offset += size;
+		}
 	}
 
 	if (WARN_ONCE(offset != total_len,
@@ -1139,9 +1187,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses)
 /*
  * Send a single message or a string of messages as a compound.
  */
-static int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
-				  struct TCP_Server_Info *server,
-				  struct smb_message *head_smb, const int flags)
+int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses,
+			   struct TCP_Server_Info *server,
+			   struct smb_message *head_smb, const int flags)
 {
 	unsigned int instance;
 	int nr_reqs, i, optype, rc = 0;
@@ -1384,6 +1432,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses,
 		smb->request		= request;
 		smb->rqst		= *rq;
 		smb->sr_flags		= flags;
+		smb->data_iter		= rq->rq_iter;
 
 		if (is_smb1(server)) {
 			smb->command = 0;


  parent reply	other threads:[~2026-05-19 10:24 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260519102158.592165-1-dhowells@redhat.com>
2026-05-19 10:21 ` [RFC PATCH 01/36] net: Perform special handling for a splice from a bvecq David Howells
2026-05-19 10:21 ` [RFC PATCH 02/36] netfs: Add a facility to splice TCP receive buffers into " David Howells
2026-05-19 10:21 ` [RFC PATCH 03/36] netfs: Add some TCP receive queue helpers David Howells
2026-05-19 10:21 ` [RFC PATCH 04/36] cifs, nls: Provide unicode size determination func David Howells
2026-05-19 10:21 ` [RFC PATCH 05/36] cifs: Introduce an ALIGN8() macro David Howells
2026-05-19 10:21 ` [RFC PATCH 06/36] cifs: Rename mid_q_entry to smb_message David Howells
2026-05-19 10:21 ` [RFC PATCH 07/36] cifs: Add "Has dynamic part" flag form SMB2/3 StructureSize LSB David Howells
2026-05-19 10:21 ` [RFC PATCH 09/36] cifs: Institute message managing struct David Howells
2026-05-19 10:21 ` [RFC PATCH 10/36] cifs: Split crypt_message() into encrypt and decrypt variants David Howells
2026-05-19 10:21 ` [RFC PATCH 11/36] cifs: Add new AEAD alloc and setup routines that draw from an iterator David Howells
2026-05-19 10:21 ` [RFC PATCH 12/36] cifs: [WIP] Rewrite base Rx to put data off the socket into a bvecq David Howells
2026-05-19 10:21 ` [RFC PATCH 13/36] cifs: Remove validate_t2() David Howells
2026-05-19 10:21 ` [RFC PATCH 14/36] cifs: Remove cifs_io_subrequest::got_bytes David Howells
2026-05-19 10:21 ` [RFC PATCH 15/36] cifs: Pass smb_message to cifs_verify_signature() David Howells
2026-05-19 10:21 ` [RFC PATCH 16/36] cifs: Rewrite base TCP transmission David Howells
2026-05-19 10:36   ` Stefan Metzmacher
2026-05-19 10:21 ` [RFC PATCH 17/36] cifs: Don't use corking David Howells
2026-05-19 10:21 ` [RFC PATCH 20/36] cifs: Pass smb_message structs down into the transport layer David Howells
2026-05-19 10:21 ` [RFC PATCH 21/36] cifs: Add a tracepoint to trace the smb_message refcount David Howells
2026-05-19 10:21 ` [RFC PATCH 22/36] cifs: Trace smb1/2_copy_to_prepped_buffers() David Howells
2026-05-19 10:21 ` [RFC PATCH 23/36] cifs: Clean up mid->callback_data and kill off mid->creator David Howells
2026-05-19 10:21 ` [RFC PATCH 24/36] cifs: Add netmem allocation functions David Howells
2026-05-19 10:21 ` David Howells [this message]
2026-05-19 10:21 ` [RFC PATCH 26/36] cifs: Convert SMB2 Negotiate Protocol request David Howells
2026-05-19 10:21 ` [RFC PATCH 27/36] cifs: Convert SMB2 Session Setup request David Howells
2026-05-19 10:21 ` [RFC PATCH 28/36] cifs: Convert SMB2 Logoff request David Howells
2026-05-19 10:21 ` [RFC PATCH 29/36] cifs: Convert SMB2 Tree Connect request David Howells
2026-05-19 10:21 ` [RFC PATCH 30/36] cifs: Convert SMB2 Tree Disconnect request David Howells
2026-05-19 10:21 ` [RFC PATCH 31/36] cifs: Convert SMB2 Read request David Howells
2026-05-19 10:21 ` [RFC PATCH 32/36] cifs: Convert SMB2 Write request David Howells
2026-05-19 10:21 ` [RFC PATCH 33/36] cifs: [WIP] Don't copy new-style smb_messages to a set of pages David Howells
2026-05-19 10:21 ` [RFC PATCH 34/36] cifs: [WIP] Rearrange Create request subfuncs David Howells
2026-05-19 10:21 ` [RFC PATCH 35/36] cifs: [WIP] Convert SMB2 Posix Mkdir request David Howells
2026-05-19 10:21 ` [RFC PATCH 36/36] cifs: [WIP] Convert SMB2 Open request David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260519102158.592165-26-dhowells@redhat.com \
    --to=dhowells@redhat.com \
    --cc=almasrymina@google.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=netfs@lists.linux.dev \
    --cc=pc@manguebit.org \
    --cc=sfrench@samba.org \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox