From nobody Sun Feb 8 23:23:25 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0560434CFCF for ; Mon, 22 Dec 2025 22:31:28 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766442693; cv=none; b=o+z8iCFTwiJ39cQ+/FNh4HnSkPu5Ae5YPTnfJv0fbTV+j5BmmmSWUz5L0y5A9fJva8DAgR8w8dPjdODaW6l1wwdxA0+hqHbUkBAoP945xrdkEpxxZYd9DidHURrpAM9DyQjFtxcJVQG5hZG/29SfJoYck7RWqb7fZTiUeHmwKvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766442693; c=relaxed/simple; bh=YRUisPfZu/AQV0uuf0IzTu4Qpe3E5mjzYodKWFmosdI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=F/rE4VkYuAanRvNw0+ESQJ8AKENDThE1pT6yP/R8Uyyud4TD9L/ZtHMPEBKGE1MfEAYJ9lT8SoVNbVnyXV8JCXTR6sFnLy/QrhBdmJS9WIFh/gJo/6Yw20KBLslj4TR0SbAWuw5CJiosFBJYzIL/fsc6uF1tR57jaYai74G9cY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=YZHieMfU; arc=none smtp.client-ip=170.10.133.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="YZHieMfU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1766442686; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=/AW7C8kDmu+70zsNdeONVj+m6HXmbipkdP4JqQmwQcA=; b=YZHieMfUDhVEsvMULyLxghq/H/zOstYMfeNA5GSfHGrXBXZnge1htpKPDni/idXHzEgLvy ePgcj+CIcA0EZi1m8crKc/RBB9TL5y7rjQjjkQiWeNKSFeIzLf/yPV904ipg2R2veSJD0B B7SZD3HXL9j6Yp/L7Y5c76Q1a2FAPE4= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-584-Qg6IjSpYN6aWwOR2s2BoTQ-1; Mon, 22 Dec 2025 17:31:21 -0500 X-MC-Unique: Qg6IjSpYN6aWwOR2s2BoTQ-1 X-Mimecast-MFC-AGG-ID: Qg6IjSpYN6aWwOR2s2BoTQ_1766442680 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 836DC195605B; Mon, 22 Dec 2025 22:31:20 +0000 (UTC) Received: from warthog.procyon.org.uk.com (unknown [10.42.28.4]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BD73C1955F43; Mon, 22 Dec 2025 22:31:18 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Enzo Matsumiya , linux-cifs@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 22/37] cifs: SMB1 split: Move some SMB1 receive bits to smb1transport.c Date: Mon, 22 Dec 2025 22:29:47 +0000 Message-ID: <20251222223006.1075635-23-dhowells@redhat.com> In-Reply-To: <20251222223006.1075635-1-dhowells@redhat.com> References: <20251222223006.1075635-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" Move some SMB1 receive bits to smb1transport.c from smb1ops.c where they're mixed in with unrelated code to do with encoding, decoding and processing PDUs. Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: Enzo Matsumiya cc: linux-cifs@vger.kernel.org cc: linux-fsdevel@vger.kernel.org cc: linux-kernel@vger.kernel.org --- fs/smb/client/smb1ops.c | 171 ---------------------------------- fs/smb/client/smb1proto.h | 2 + fs/smb/client/smb1transport.c | 171 ++++++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+), 171 deletions(-) diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 9729b56bd9d4..2534113596c7 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -284,146 +284,6 @@ cifs_get_next_mid(struct TCP_Server_Info *server) return mid; } =20 -/* - return codes: - 0 not a transact2, or all data present - >0 transact2 with that much data missing - -EINVAL invalid transact2 - */ -static int -check2ndT2(char *buf) -{ - struct smb_hdr *pSMB =3D (struct smb_hdr *)buf; - struct smb_t2_rsp *pSMBt; - int remaining; - __u16 total_data_size, data_in_this_rsp; - - if (pSMB->Command !=3D SMB_COM_TRANSACTION2) - return 0; - - /* check for plausible wct, bcc and t2 data and parm sizes */ - /* check for parm and data offset going beyond end of smb */ - if (pSMB->WordCount !=3D 10) { /* coalesce_t2 depends on this */ - cifs_dbg(FYI, "Invalid transact2 word count\n"); - return -EINVAL; - } - - pSMBt =3D (struct smb_t2_rsp *)pSMB; - - total_data_size =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); - data_in_this_rsp =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); - - if (total_data_size =3D=3D data_in_this_rsp) - return 0; - else if (total_data_size < data_in_this_rsp) { - cifs_dbg(FYI, "total data %d smaller than data in frame %d\n", - total_data_size, data_in_this_rsp); - return -EINVAL; - } - - remaining =3D total_data_size - data_in_this_rsp; - - cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n", - remaining); - if (total_data_size > CIFSMaxBufSize) { - cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n", - total_data_size, CIFSMaxBufSize); - return -EINVAL; - } - return remaining; -} - -static int -coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pd= u_len) -{ - struct smb_t2_rsp *pSMBs =3D (struct smb_t2_rsp *)second_buf; - struct smb_t2_rsp *pSMBt =3D (struct smb_t2_rsp *)target_hdr; - char *data_area_of_tgt; - char *data_area_of_src; - int remaining; - unsigned int byte_count, total_in_tgt; - __u16 tgt_total_cnt, src_total_cnt, total_in_src; - - src_total_cnt =3D get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount); - tgt_total_cnt =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); - - if (tgt_total_cnt !=3D src_total_cnt) - cifs_dbg(FYI, "total data count of primary and secondary t2 differ sourc= e=3D%hu target=3D%hu\n", - src_total_cnt, tgt_total_cnt); - - total_in_tgt =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); - - remaining =3D tgt_total_cnt - total_in_tgt; - - if (remaining < 0) { - cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=3D%hu total_in_t= gt=3D%u\n", - tgt_total_cnt, total_in_tgt); - return -EPROTO; - } - - if (remaining =3D=3D 0) { - /* nothing to do, ignore */ - cifs_dbg(FYI, "no more data remains\n"); - return 0; - } - - total_in_src =3D get_unaligned_le16(&pSMBs->t2_rsp.DataCount); - if (remaining < total_in_src) - cifs_dbg(FYI, "transact2 2nd response contains too much data\n"); - - /* find end of first SMB data area */ - data_area_of_tgt =3D (char *)&pSMBt->hdr.Protocol + - get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); - - /* validate target area */ - data_area_of_src =3D (char *)&pSMBs->hdr.Protocol + - get_unaligned_le16(&pSMBs->t2_rsp.DataOffset); - - data_area_of_tgt +=3D total_in_tgt; - - total_in_tgt +=3D total_in_src; - /* is the result too big for the field? */ - if (total_in_tgt > USHRT_MAX) { - cifs_dbg(FYI, "coalesced DataCount too large (%u)\n", - total_in_tgt); - return -EPROTO; - } - put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount); - - /* fix up the BCC */ - byte_count =3D get_bcc(target_hdr); - byte_count +=3D total_in_src; - /* is the result too big for the field? */ - if (byte_count > USHRT_MAX) { - cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count); - return -EPROTO; - } - put_bcc(byte_count, target_hdr); - - byte_count =3D *pdu_len; - byte_count +=3D total_in_src; - /* don't allow buffer to overflow */ - if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { - cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n", - byte_count); - return -ENOBUFS; - } - *pdu_len =3D byte_count; - - /* copy second buffer into end of first buffer */ - memcpy(data_area_of_tgt, data_area_of_src, total_in_src); - - if (remaining !=3D total_in_src) { - /* more responses to go */ - cifs_dbg(FYI, "waiting for more secondary responses\n"); - return 1; - } - - /* we are done */ - cifs_dbg(FYI, "found the last secondary response\n"); - return 0; -} - static void cifs_downgrade_oplock(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, __u32 oplock, @@ -432,37 +292,6 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server, cifs_set_oplock_level(cinode, oplock); } =20 -static bool -cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server, - char *buf, int malformed) -{ - if (malformed) - return false; - if (check2ndT2(buf) <=3D 0) - return false; - mid->multiRsp =3D true; - if (mid->resp_buf) { - /* merge response - fix up 1st*/ - malformed =3D coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len); - if (malformed > 0) - return true; - /* All parts received or packet is malformed. */ - mid->multiEnd =3D true; - dequeue_mid(server, mid, malformed); - return true; - } - if (!server->large_buf) { - /*FIXME: switch to already allocated largebuf?*/ - cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n"); - } else { - /* Have first buffer */ - mid->resp_buf =3D buf; - mid->large_buf =3D true; - server->bigbuf =3D NULL; - } - return true; -} - static bool cifs_need_neg(struct TCP_Server_Info *server) { diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 1fd4fd0bbb7a..bf24974fbb00 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -233,6 +233,8 @@ int SendReceive(const unsigned int xid, struct cifs_ses= *ses, struct smb_hdr *in_buf, unsigned int in_len, struct smb_hdr *out_buf, int *pbytes_returned, const int flags); +bool cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *se= rver, + char *buf, int malformed); =20 =20 #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 28d1cee90625..5f95bffc8e44 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -261,3 +261,174 @@ SendReceive(const unsigned int xid, struct cifs_ses *= ses, free_rsp_buf(resp_buf_type, resp_iov.iov_base); return rc; } + +/* + return codes: + 0 not a transact2, or all data present + >0 transact2 with that much data missing + -EINVAL invalid transact2 + */ +static int +check2ndT2(char *buf) +{ + struct smb_hdr *pSMB =3D (struct smb_hdr *)buf; + struct smb_t2_rsp *pSMBt; + int remaining; + __u16 total_data_size, data_in_this_rsp; + + if (pSMB->Command !=3D SMB_COM_TRANSACTION2) + return 0; + + /* check for plausible wct, bcc and t2 data and parm sizes */ + /* check for parm and data offset going beyond end of smb */ + if (pSMB->WordCount !=3D 10) { /* coalesce_t2 depends on this */ + cifs_dbg(FYI, "Invalid transact2 word count\n"); + return -EINVAL; + } + + pSMBt =3D (struct smb_t2_rsp *)pSMB; + + total_data_size =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); + data_in_this_rsp =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); + + if (total_data_size =3D=3D data_in_this_rsp) + return 0; + else if (total_data_size < data_in_this_rsp) { + cifs_dbg(FYI, "total data %d smaller than data in frame %d\n", + total_data_size, data_in_this_rsp); + return -EINVAL; + } + + remaining =3D total_data_size - data_in_this_rsp; + + cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n", + remaining); + if (total_data_size > CIFSMaxBufSize) { + cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n", + total_data_size, CIFSMaxBufSize); + return -EINVAL; + } + return remaining; +} + +static int +coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pd= u_len) +{ + struct smb_t2_rsp *pSMBs =3D (struct smb_t2_rsp *)second_buf; + struct smb_t2_rsp *pSMBt =3D (struct smb_t2_rsp *)target_hdr; + char *data_area_of_tgt; + char *data_area_of_src; + int remaining; + unsigned int byte_count, total_in_tgt; + __u16 tgt_total_cnt, src_total_cnt, total_in_src; + + src_total_cnt =3D get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount); + tgt_total_cnt =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); + + if (tgt_total_cnt !=3D src_total_cnt) + cifs_dbg(FYI, "total data count of primary and secondary t2 differ sourc= e=3D%hu target=3D%hu\n", + src_total_cnt, tgt_total_cnt); + + total_in_tgt =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); + + remaining =3D tgt_total_cnt - total_in_tgt; + + if (remaining < 0) { + cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=3D%hu total_in_t= gt=3D%u\n", + tgt_total_cnt, total_in_tgt); + return -EPROTO; + } + + if (remaining =3D=3D 0) { + /* nothing to do, ignore */ + cifs_dbg(FYI, "no more data remains\n"); + return 0; + } + + total_in_src =3D get_unaligned_le16(&pSMBs->t2_rsp.DataCount); + if (remaining < total_in_src) + cifs_dbg(FYI, "transact2 2nd response contains too much data\n"); + + /* find end of first SMB data area */ + data_area_of_tgt =3D (char *)&pSMBt->hdr.Protocol + + get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); + + /* validate target area */ + data_area_of_src =3D (char *)&pSMBs->hdr.Protocol + + get_unaligned_le16(&pSMBs->t2_rsp.DataOffset); + + data_area_of_tgt +=3D total_in_tgt; + + total_in_tgt +=3D total_in_src; + /* is the result too big for the field? */ + if (total_in_tgt > USHRT_MAX) { + cifs_dbg(FYI, "coalesced DataCount too large (%u)\n", + total_in_tgt); + return -EPROTO; + } + put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount); + + /* fix up the BCC */ + byte_count =3D get_bcc(target_hdr); + byte_count +=3D total_in_src; + /* is the result too big for the field? */ + if (byte_count > USHRT_MAX) { + cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count); + return -EPROTO; + } + put_bcc(byte_count, target_hdr); + + byte_count =3D *pdu_len; + byte_count +=3D total_in_src; + /* don't allow buffer to overflow */ + if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { + cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n", + byte_count); + return -ENOBUFS; + } + *pdu_len =3D byte_count; + + /* copy second buffer into end of first buffer */ + memcpy(data_area_of_tgt, data_area_of_src, total_in_src); + + if (remaining !=3D total_in_src) { + /* more responses to go */ + cifs_dbg(FYI, "waiting for more secondary responses\n"); + return 1; + } + + /* we are done */ + cifs_dbg(FYI, "found the last secondary response\n"); + return 0; +} + +bool +cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server, + char *buf, int malformed) +{ + if (malformed) + return false; + if (check2ndT2(buf) <=3D 0) + return false; + mid->multiRsp =3D true; + if (mid->resp_buf) { + /* merge response - fix up 1st*/ + malformed =3D coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len); + if (malformed > 0) + return true; + /* All parts received or packet is malformed. */ + mid->multiEnd =3D true; + dequeue_mid(server, mid, malformed); + return true; + } + if (!server->large_buf) { + /*FIXME: switch to already allocated largebuf?*/ + cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n"); + } else { + /* Have first buffer */ + mid->resp_buf =3D buf; + mid->large_buf =3D true; + server->bigbuf =3D NULL; + } + return true; +}