From nobody Sat Feb 7 10:44:34 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.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 47FA134EEEC for ; Mon, 22 Dec 2025 22:31:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766442720; cv=none; b=gfk13QEYOkF8wMbyPl5GupI+38ohBryAIF8EWGb3C4DwWNIm0ioGwYm2uhxjMXQXfC9CekoBASA7uq/6J95E/M6Qrmy9z34t5i7ojd7iRuWZ01SmDrbg6W8/C+6OF8qGn4HT1tP/g1pgGyBnZBOhjaEgp6il0dQSlyYlKJKHZ5E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766442720; c=relaxed/simple; bh=ZDKu2++B7BFkwdi1cw+860rqZEWpPkElme+Du6P9Xos=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pX1cgz3K2pPRugTqiYLnJTC7v2JT6gQ0Qt+r4O9YR5gR17K5EMrHtUjVCmv5GnxSzCEvUYTgw6b9DyVqtyXrPz4Aqj8dV0lr6YDGTzVR+UIUyTvIbGVAz2pRyii1mURPgui72JgaCLkdVTo2AQ8iP2eBfcjltY8v0jM6iP3nBaE= 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=UbJzVV//; arc=none smtp.client-ip=170.10.129.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="UbJzVV//" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1766442717; 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=K2bHUFjgtHnt0pzv9uZhJdA2s3CnNTbaaTJ1v0TSe+M=; b=UbJzVV//b0vBVz+HlupHF7cRvTnQcE49LJAy0QffEIJz1jnFr3wazmrqCnybyaMDJNmPvR 7S//pqCjV8DtZe36LGAO8LITIxVQs3yVmJ2DYrPXLKu+1xjFvYY0jBE/gXb0o5meIMIs1i SOA/kTXal3HS3neZnaR+MRxJhtZKE28= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-193-xicOQjEKMWaWPOP1ZFxkAw-1; Mon, 22 Dec 2025 17:31:52 -0500 X-MC-Unique: xicOQjEKMWaWPOP1ZFxkAw-1 X-Mimecast-MFC-AGG-ID: xicOQjEKMWaWPOP1ZFxkAw_1766442711 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9943618002C9; Mon, 22 Dec 2025 22:31:51 +0000 (UTC) Received: from warthog.procyon.org.uk.com (unknown [10.42.28.4]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D844519560A7; Mon, 22 Dec 2025 22:31:49 +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 32/37] cifs: SMB1 split: misc.c Date: Mon, 22 Dec 2025 22:29:57 +0000 Message-ID: <20251222223006.1075635-33-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.12 Content-Type: text/plain; charset="utf-8" Split SMB1 bits from misc.c to smb1misc.c. 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/Makefile | 1 + fs/smb/client/cifsproto.h | 4 - fs/smb/client/misc.c | 165 ----------------------------------- fs/smb/client/smb1misc.c | 177 ++++++++++++++++++++++++++++++++++++++ fs/smb/client/smb1proto.h | 7 ++ 5 files changed, 185 insertions(+), 169 deletions(-) create mode 100644 fs/smb/client/smb1misc.c diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile index c51f67a5caaa..5288f9de07cd 100644 --- a/fs/smb/client/Makefile +++ b/fs/smb/client/Makefile @@ -35,6 +35,7 @@ cifs-$(CONFIG_CIFS_ROOT) +=3D cifsroot.o cifs-$(CONFIG_CIFS_ALLOW_INSECURE_LEGACY) +=3D \ cifssmb.o \ smb1debug.o \ + smb1misc.o \ smb1ops.o \ smb1transport.o =20 diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 6cf084aeb30e..fc97c6c452d2 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -131,7 +131,6 @@ void cifs_signal_cifsd_for_reconnect(struct TCP_Server_= Info *server, void cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session); -bool is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv); bool backup_cred(struct cifs_sb_info *cifs_sb); bool is_size_safe_to_change(struct cifsInodeInfo *cifsInode, __u64 end_of_= file, bool from_readdir); @@ -157,9 +156,6 @@ void cifs_set_port(struct sockaddr *addr, const unsigne= d short int port); int map_smb_to_linux_error(char *buf, bool logErr); int map_and_check_smb_error(struct TCP_Server_Info *server, struct mid_q_entry *mid, bool logErr); -unsigned int header_assemble(struct smb_hdr *buffer, char smb_command, - const struct cifs_tcon *treeCon, int word_count - /* length of fixed section (word count) in two byte units */); int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server, const struct nls_table *nls_cp); diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c index 273c54d39857..1773e3b471aa 100644 --- a/fs/smb/client/misc.c +++ b/fs/smb/client/misc.c @@ -262,171 +262,6 @@ free_rsp_buf(int resp_buftype, void *rsp) cifs_buf_release(rsp); } =20 -/* NB: MID can not be set if treeCon not passed in, in that - case it is responsibility of caller to set the mid */ -unsigned int -header_assemble(struct smb_hdr *buffer, char smb_command, - const struct cifs_tcon *treeCon, int word_count - /* length of fixed section (word count) in two byte units */) -{ - unsigned int in_len; - char *temp =3D (char *) buffer; - - memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ - - in_len =3D (2 * word_count) + sizeof(struct smb_hdr) + - 2 /* for bcc field itself */; - - buffer->Protocol[0] =3D 0xFF; - buffer->Protocol[1] =3D 'S'; - buffer->Protocol[2] =3D 'M'; - buffer->Protocol[3] =3D 'B'; - buffer->Command =3D smb_command; - buffer->Flags =3D 0x00; /* case sensitive */ - buffer->Flags2 =3D SMBFLG2_KNOWS_LONG_NAMES; - buffer->Pid =3D cpu_to_le16((__u16)current->tgid); - buffer->PidHigh =3D cpu_to_le16((__u16)(current->tgid >> 16)); - if (treeCon) { - buffer->Tid =3D treeCon->tid; - if (treeCon->ses) { - if (treeCon->ses->capabilities & CAP_UNICODE) - buffer->Flags2 |=3D SMBFLG2_UNICODE; - if (treeCon->ses->capabilities & CAP_STATUS32) - buffer->Flags2 |=3D SMBFLG2_ERR_STATUS; - - /* Uid is not converted */ - buffer->Uid =3D treeCon->ses->Suid; - if (treeCon->ses->server) - buffer->Mid =3D get_next_mid(treeCon->ses->server); - } - if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) - buffer->Flags2 |=3D SMBFLG2_DFS; - if (treeCon->nocase) - buffer->Flags |=3D SMBFLG_CASELESS; - if ((treeCon->ses) && (treeCon->ses->server)) - if (treeCon->ses->server->sign) - buffer->Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; - } - -/* endian conversion of flags is now done just before sending */ - buffer->WordCount =3D (char) word_count; - return in_len; -} - -bool -is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) -{ - struct smb_hdr *buf =3D (struct smb_hdr *)buffer; - struct smb_com_lock_req *pSMB =3D (struct smb_com_lock_req *)buf; - struct TCP_Server_Info *pserver; - struct cifs_ses *ses; - struct cifs_tcon *tcon; - struct cifsInodeInfo *pCifsInode; - struct cifsFileInfo *netfile; - - cifs_dbg(FYI, "Checking for oplock break or dnotify response\n"); - if ((pSMB->hdr.Command =3D=3D SMB_COM_NT_TRANSACT) && - (pSMB->hdr.Flags & SMBFLG_RESPONSE)) { - struct smb_com_transaction_change_notify_rsp *pSMBr =3D - (struct smb_com_transaction_change_notify_rsp *)buf; - struct file_notify_information *pnotify; - __u32 data_offset =3D 0; - size_t len =3D srv->total_read - srv->pdu_size; - - if (get_bcc(buf) > sizeof(struct file_notify_information)) { - data_offset =3D le32_to_cpu(pSMBr->DataOffset); - - if (data_offset > - len - sizeof(struct file_notify_information)) { - cifs_dbg(FYI, "Invalid data_offset %u\n", - data_offset); - return true; - } - pnotify =3D (struct file_notify_information *) - ((char *)&pSMBr->hdr.Protocol + data_offset); - cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n", - pnotify->FileName, pnotify->Action); - /* cifs_dump_mem("Rcvd notify Data: ",buf, - sizeof(struct smb_hdr)+60); */ - return true; - } - if (pSMBr->hdr.Status.CifsError) { - cifs_dbg(FYI, "notify err 0x%x\n", - pSMBr->hdr.Status.CifsError); - return true; - } - return false; - } - if (pSMB->hdr.Command !=3D SMB_COM_LOCKING_ANDX) - return false; - if (pSMB->hdr.Flags & SMBFLG_RESPONSE) { - /* no sense logging error on invalid handle on oplock - break - harmless race between close request and oplock - break response is expected from time to time writing out - large dirty files cached on the client */ - if ((NT_STATUS_INVALID_HANDLE) =3D=3D - le32_to_cpu(pSMB->hdr.Status.CifsError)) { - cifs_dbg(FYI, "Invalid handle on oplock break\n"); - return true; - } else if (ERRbadfid =3D=3D - le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { - return true; - } else { - return false; /* on valid oplock brk we get "request" */ - } - } - if (pSMB->hdr.WordCount !=3D 8) - return false; - - cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n", - pSMB->LockType, pSMB->OplockLevel); - if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) - return false; - - /* If server is a channel, select the primary channel */ - pserver =3D SERVER_IS_CHAN(srv) ? srv->primary_server : srv; - - /* look up tcon based on tid & uid */ - spin_lock(&cifs_tcp_ses_lock); - list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { - if (cifs_ses_exiting(ses)) - continue; - list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { - if (tcon->tid !=3D buf->Tid) - continue; - - cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); - spin_lock(&tcon->open_file_lock); - list_for_each_entry(netfile, &tcon->openFileList, tlist) { - if (pSMB->Fid !=3D netfile->fid.netfid) - continue; - - cifs_dbg(FYI, "file id match, oplock break\n"); - pCifsInode =3D CIFS_I(d_inode(netfile->dentry)); - - set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, - &pCifsInode->flags); - - netfile->oplock_epoch =3D 0; - netfile->oplock_level =3D pSMB->OplockLevel; - netfile->oplock_break_cancelled =3D false; - cifs_queue_oplock_break(netfile); - - spin_unlock(&tcon->open_file_lock); - spin_unlock(&cifs_tcp_ses_lock); - return true; - } - spin_unlock(&tcon->open_file_lock); - spin_unlock(&cifs_tcp_ses_lock); - cifs_dbg(FYI, "No matching file for oplock break\n"); - return true; - } - } - spin_unlock(&cifs_tcp_ses_lock); - cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n= "); - return true; -} - void dump_smb(void *buf, int smb_buf_length) { diff --git a/fs/smb/client/smb1misc.c b/fs/smb/client/smb1misc.c new file mode 100644 index 000000000000..d73ef87f55d0 --- /dev/null +++ b/fs/smb/client/smb1misc.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * + * Copyright (C) International Business Machines Corp., 2002,2008 + * Author(s): Steve French (sfrench@us.ibm.com) + * + */ + +#include "smb1proto.h" +#include "smberr.h" +#include "nterr.h" +#include "cifs_debug.h" + +/* NB: MID can not be set if treeCon not passed in, in that + case it is responsibility of caller to set the mid */ +unsigned int +header_assemble(struct smb_hdr *buffer, char smb_command, + const struct cifs_tcon *treeCon, int word_count + /* length of fixed section (word count) in two byte units */) +{ + unsigned int in_len; + char *temp =3D (char *) buffer; + + memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */ + + in_len =3D (2 * word_count) + sizeof(struct smb_hdr) + + 2 /* for bcc field itself */; + + buffer->Protocol[0] =3D 0xFF; + buffer->Protocol[1] =3D 'S'; + buffer->Protocol[2] =3D 'M'; + buffer->Protocol[3] =3D 'B'; + buffer->Command =3D smb_command; + buffer->Flags =3D 0x00; /* case sensitive */ + buffer->Flags2 =3D SMBFLG2_KNOWS_LONG_NAMES; + buffer->Pid =3D cpu_to_le16((__u16)current->tgid); + buffer->PidHigh =3D cpu_to_le16((__u16)(current->tgid >> 16)); + if (treeCon) { + buffer->Tid =3D treeCon->tid; + if (treeCon->ses) { + if (treeCon->ses->capabilities & CAP_UNICODE) + buffer->Flags2 |=3D SMBFLG2_UNICODE; + if (treeCon->ses->capabilities & CAP_STATUS32) + buffer->Flags2 |=3D SMBFLG2_ERR_STATUS; + + /* Uid is not converted */ + buffer->Uid =3D treeCon->ses->Suid; + if (treeCon->ses->server) + buffer->Mid =3D get_next_mid(treeCon->ses->server); + } + if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) + buffer->Flags2 |=3D SMBFLG2_DFS; + if (treeCon->nocase) + buffer->Flags |=3D SMBFLG_CASELESS; + if ((treeCon->ses) && (treeCon->ses->server)) + if (treeCon->ses->server->sign) + buffer->Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; + } + +/* endian conversion of flags is now done just before sending */ + buffer->WordCount =3D (char) word_count; + return in_len; +} + +bool +is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) +{ + struct smb_hdr *buf =3D (struct smb_hdr *)buffer; + struct smb_com_lock_req *pSMB =3D (struct smb_com_lock_req *)buf; + struct TCP_Server_Info *pserver; + struct cifs_ses *ses; + struct cifs_tcon *tcon; + struct cifsInodeInfo *pCifsInode; + struct cifsFileInfo *netfile; + + cifs_dbg(FYI, "Checking for oplock break or dnotify response\n"); + if ((pSMB->hdr.Command =3D=3D SMB_COM_NT_TRANSACT) && + (pSMB->hdr.Flags & SMBFLG_RESPONSE)) { + struct smb_com_transaction_change_notify_rsp *pSMBr =3D + (struct smb_com_transaction_change_notify_rsp *)buf; + struct file_notify_information *pnotify; + __u32 data_offset =3D 0; + size_t len =3D srv->total_read - srv->pdu_size; + + if (get_bcc(buf) > sizeof(struct file_notify_information)) { + data_offset =3D le32_to_cpu(pSMBr->DataOffset); + + if (data_offset > + len - sizeof(struct file_notify_information)) { + cifs_dbg(FYI, "Invalid data_offset %u\n", + data_offset); + return true; + } + pnotify =3D (struct file_notify_information *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + cifs_dbg(FYI, "dnotify on %s Action: 0x%x\n", + pnotify->FileName, pnotify->Action); + /* cifs_dump_mem("Rcvd notify Data: ",buf, + sizeof(struct smb_hdr)+60); */ + return true; + } + if (pSMBr->hdr.Status.CifsError) { + cifs_dbg(FYI, "notify err 0x%x\n", + pSMBr->hdr.Status.CifsError); + return true; + } + return false; + } + if (pSMB->hdr.Command !=3D SMB_COM_LOCKING_ANDX) + return false; + if (pSMB->hdr.Flags & SMBFLG_RESPONSE) { + /* no sense logging error on invalid handle on oplock + break - harmless race between close request and oplock + break response is expected from time to time writing out + large dirty files cached on the client */ + if ((NT_STATUS_INVALID_HANDLE) =3D=3D + le32_to_cpu(pSMB->hdr.Status.CifsError)) { + cifs_dbg(FYI, "Invalid handle on oplock break\n"); + return true; + } else if (ERRbadfid =3D=3D + le16_to_cpu(pSMB->hdr.Status.DosError.Error)) { + return true; + } else { + return false; /* on valid oplock brk we get "request" */ + } + } + if (pSMB->hdr.WordCount !=3D 8) + return false; + + cifs_dbg(FYI, "oplock type 0x%x level 0x%x\n", + pSMB->LockType, pSMB->OplockLevel); + if (!(pSMB->LockType & LOCKING_ANDX_OPLOCK_RELEASE)) + return false; + + /* If server is a channel, select the primary channel */ + pserver =3D SERVER_IS_CHAN(srv) ? srv->primary_server : srv; + + /* look up tcon based on tid & uid */ + spin_lock(&cifs_tcp_ses_lock); + list_for_each_entry(ses, &pserver->smb_ses_list, smb_ses_list) { + if (cifs_ses_exiting(ses)) + continue; + list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { + if (tcon->tid !=3D buf->Tid) + continue; + + cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); + spin_lock(&tcon->open_file_lock); + list_for_each_entry(netfile, &tcon->openFileList, tlist) { + if (pSMB->Fid !=3D netfile->fid.netfid) + continue; + + cifs_dbg(FYI, "file id match, oplock break\n"); + pCifsInode =3D CIFS_I(d_inode(netfile->dentry)); + + set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, + &pCifsInode->flags); + + netfile->oplock_epoch =3D 0; + netfile->oplock_level =3D pSMB->OplockLevel; + netfile->oplock_break_cancelled =3D false; + cifs_queue_oplock_break(netfile); + + spin_unlock(&tcon->open_file_lock); + spin_unlock(&cifs_tcp_ses_lock); + return true; + } + spin_unlock(&tcon->open_file_lock); + spin_unlock(&cifs_tcp_ses_lock); + cifs_dbg(FYI, "No matching file for oplock break\n"); + return true; + } + } + spin_unlock(&cifs_tcp_ses_lock); + cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n= "); + return true; +} diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index de021e17dc4b..259cfafacfab 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -220,6 +220,13 @@ int CIFSSMBSetEA(const unsigned int xid, struct cifs_t= con *tcon, void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server); =20 +/* + * smb1misc.c + */ +unsigned int header_assemble(struct smb_hdr *buffer, char smb_command, + const struct cifs_tcon *treeCon, int word_count); +bool is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv); + /* * smb1ops.c */