From patchwork Sun Dec 22 16:30:45 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918159 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 076FD148FF5; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=bRc5zzksQlCnc+S9xtHd7jF35U/BkSbBgA8UGaoFwfQQHKsSF/awjOF+kVJ6ePppybwTxsvWceHW/KbLP3Rld96XqcYxR8rje6986znhN4622dFFGIv84QiSiDn0hXPc5QkT1uReZTLyc8RyyuH+KuLN9eD67W4t23hy/f/2Eqw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=6mF6fFD1dpZLaf92pqiPx4MGnM0g/bhvYec0tCCgVo0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=FL7R/t3xsbkHDmAFOYQmAHoyVtjXFlhFINHxLK+CX6PH171X0Z6dHzqYGW6EEfsosoUTcq/VWrE4Rlse0YFAvJimwK9PrVQRKG5Mce5GHzgDZsHpT+OYTPT6ezHsJzeYMKQO/1VbXVD2he4C5g6dmVSWWB0f4gkmhKaCnHFAdUA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uO5yACPc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uO5yACPc" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 50BDCC4CEDD; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885097; bh=6mF6fFD1dpZLaf92pqiPx4MGnM0g/bhvYec0tCCgVo0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uO5yACPcCOUaeBKbBwVut1TbXSGSpD3bPVFjWvnRnYB5yDTLkHT4TKe6O98k7fjTZ IqcNROdB+PnNU13sRlMQLNA34h0Q0HbwIvFT9fpsbdBMU9QIQpV1xIK1xQdhWhaqx4 seIBT3ZjaPsxdBMoh6pAfMM1FpSuZI/00rYVSPLGHqKNDNSRnUPYIUMtMpUNt0vSdF Qo8iFmxk/sSYfP8bQT42RovbBlhu/I+Yqm6pdn8QRIlG509tpSjNZujg+QfG5K7stY 5ftw4clVn1C7jh6IS1f2Lcx/bdgWDBbVqn/lGAbQ1d0EXmfb99OzGHpXDsR/VJnT1m RpFHiuZoVyX1w== Received: by pali.im (Postfix) id 00819982; Sun, 22 Dec 2024 17:31:26 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/6] cifs: Allow to disable or force initialization of NetBIOS session Date: Sun, 22 Dec 2024 17:30:45 +0100 Message-Id: <20241222163050.24359-2-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Currently SMB client always tries to initialize NetBIOS session when the server port is 139. This is useful for default cases, but nowadays when using non-standard routing or testing between VMs, it is common that servers are listening on non-standard ports. So add a new mount option -o nbsessinit and -o nonbsessinit which either forces initialization or disables initialization regardless of server port number. This allows Linux SMB client to connect to older SMB1 server listening on non-standard port, which requires initialization of NetBIOS session, by using additional mount options -o port= and -o nbsessinit. Signed-off-by: Pali Rohár --- fs/smb/client/cifsglob.h | 1 + fs/smb/client/connect.c | 11 ++++++++++- fs/smb/client/fs_context.c | 14 +++++++++++++- fs/smb/client/fs_context.h | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index d4c60d85d7a4..bea4b8a8b30e 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -716,6 +716,7 @@ struct TCP_Server_Info { spinlock_t srv_lock; /* protect anything here that is not protected */ __u64 conn_id; /* connection identifier (useful for debugging) */ int srv_count; /* reference counter */ + int rfc1001_sessinit; /* whether to estasblish netbios session */ /* 15 character server name + 0x20 16th byte indicating type = srv */ char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; struct smb_version_operations *ops; diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 20b8bb957468..9cbfdc31cdda 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1738,6 +1738,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, ctx->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); memcpy(tcp_ses->server_RFC1001_name, ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); + tcp_ses->rfc1001_sessinit = ctx->rfc1001_sessinit; tcp_ses->session_estab = false; tcp_ses->sequence_number = 0; tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */ @@ -3206,7 +3207,15 @@ generic_ip_connect(struct TCP_Server_Info *server) return rc; } trace_smb3_connect_done(server->hostname, server->conn_id, &server->dstaddr); - if (sport == htons(RFC1001_PORT)) + + /* + * Establish RFC1001 NetBIOS session when it was explicitly requested + * by mount option -o nbsessinit, or when connecting to default RFC1001 + * server port (139) and it was not explicitly disabled by mount option + * -o nonbsessinit. + */ + if (server->rfc1001_sessinit == 1 || + (server->rfc1001_sessinit == -1 && sport == htons(RFC1001_PORT))) rc = ip_rfc1001_connect(server); return rc; diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index e2ae9819b5ba..3774f02f45c9 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -134,6 +134,7 @@ const struct fs_parameter_spec smb3_fs_parameters[] = { fsparam_flag("compress", Opt_compress), fsparam_flag("witness", Opt_witness), fsparam_flag_no("unicode", Opt_unicode), + fsparam_flag_no("nbsessinit", Opt_nbsessinit), /* Mount options which take uid or gid */ fsparam_uid("backupuid", Opt_backupuid), @@ -965,6 +966,10 @@ static int smb3_verify_reconfigure_ctx(struct fs_context *fc, cifs_errorf(fc, "can not change unicode during remount\n"); return -EINVAL; } + if (new_ctx->rfc1001_sessinit != old_ctx->rfc1001_sessinit) { + cifs_errorf(fc, "can not change nbsessinit during remount\n"); + return -EINVAL; + } return 0; } @@ -1585,6 +1590,10 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, if (i == RFC1001_NAME_LEN && param->string[i] != 0) pr_warn("server netbiosname longer than 15 truncated\n"); break; + case Opt_nbsessinit: + ctx->rfc1001_sessinit = !result.negated; + cifs_dbg(FYI, "rfc1001_sessinit set to %d\n", ctx->rfc1001_sessinit); + break; case Opt_ver: /* version of mount userspace tools, not dialect */ /* If interface changes in mount.cifs bump to new ver */ @@ -1872,13 +1881,16 @@ int smb3_init_fs_context(struct fs_context *fc) memset(ctx->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) ctx->source_rfc1001_name[i] = toupper(nodename[i]); - ctx->source_rfc1001_name[RFC1001_NAME_LEN] = 0; + /* * null target name indicates to use *SMBSERVR default called name * if we end up sending RFC1001 session initialize */ ctx->target_rfc1001_name[0] = 0; + + ctx->rfc1001_sessinit = -1; /* autodetect based on port number */ + ctx->cred_uid = current_uid(); ctx->linux_uid = current_uid(); ctx->linux_gid = current_gid(); diff --git a/fs/smb/client/fs_context.h b/fs/smb/client/fs_context.h index af2d94022a30..e6b22a5fbd0f 100644 --- a/fs/smb/client/fs_context.h +++ b/fs/smb/client/fs_context.h @@ -174,6 +174,7 @@ enum cifs_param { Opt_iocharset, Opt_netbiosname, Opt_servern, + Opt_nbsessinit, Opt_ver, Opt_vers, Opt_sec, @@ -216,6 +217,7 @@ struct smb3_fs_context { char *iocharset; /* local code page for mapping to and from Unicode */ char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ + int rfc1001_sessinit; kuid_t cred_uid; kuid_t linux_uid; kgid_t linux_gid; From patchwork Sun Dec 22 16:30:46 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918160 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 0774116BE3A; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=N6W8k9w2+v6wlO5tXjjhbF7GtJrhFWAG7QsHSJqWKOEE4CULf0uSbMKGZnD6w2WLYNsj9CMVqZmEz9CTazppL7R6K24PlVdmpZgZ4n9e9haV1lm67HmWTN3IMF3RSFlzK6zDdaVFm0WNBQ8c8tA0pzgYEWbB3G/Egf+RyDnYHDo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=niPFbWXtqM9OfYghrmofmbZBuIsFf29aqObb4aYx3F4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=RsTwxSkyOZuMmAnmE1doCgbb/twXD3a6G6+XJf80vxhRrAySR86/x6OPf6z164cGvIf1t+WElXnKtd6VBm+CAkUXGrZIAxsdbl4mt7S1sY44OhZa8YUbNq8emJ83hOVEUNUZ4FRaXAZxM3h143V+stMlrYU36QlJWXaoKgQW3Pg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VFj9GRmN; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VFj9GRmN" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C230C4CECD; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885097; bh=niPFbWXtqM9OfYghrmofmbZBuIsFf29aqObb4aYx3F4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VFj9GRmNFktnbNlbX3qvhKpY0/PQXSf7vVHIgo+dbyzXNrFRoyfaET5IvRb0zzbqX fyMqET6VDizVT2ud0wyTQfU0Dv2076AYjqqx8LuNtxEGrxp3RtqSYX5b/2OIJnQIge IeVI0CeaZgpdA9WOwaAteeqdnOiYzzvUP50lmSCwXcQcR1eX5C6x5r+GMgRKBS9+Sn knB6/kcDRtimL3eUgbLv6gkzedhHY/y4Efcs090jLexf6MfZmh4t7QJVMJshTwUpA3 aPZ0E9RdMoEv3SEpLxtrU/tG8QcQFd00M3Q0pOpg02zX+UPT4Qx3SUOgSrFrEUK/zI LIo+y0dbV0YHA== Received: by pali.im (Postfix) id 2FEF1B9A; Sun, 22 Dec 2024 17:31:27 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 2/6] cifs: Fix establishing NetBIOS session for SMB2+ connection Date: Sun, 22 Dec 2024 17:30:46 +0100 Message-Id: <20241222163050.24359-3-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Function ip_rfc1001_connect() which establish NetBIOS session for SMB connections, currently uses smb_send() function for sending NetBIOS Session Request packet. This function expects that the passed buffer is SMB packet and for SMB2+ connections it mangles packet header, which breaks prepared NetBIOS Session Request packet. Result is that this function send garbage packet for SMB2+ connection, which SMB2+ server cannot parse. That function is not mangling packets for SMB1 connections, so it somehow works for SMB1. Fix this problem and instead of smb_send(), use smb_send_kvec() function which does not mangle prepared packet, this function send them as is. Just API of this function takes struct msghdr (kvec) instead of packet buffer. [MS-SMB2] specification allows SMB2 protocol to use NetBIOS as a transport protocol. NetBIOS can be used over TCP via port 139. So this is a valid configuration, just not so common. And even recent Windows versions (e.g. Windows Server 2022) still supports this configuration: SMB over TCP port 139, including for modern SMB2 and SMB3 dialects. This change fixes SMB2 and SMB3 connections over TCP port 139 which requires establishing of NetBIOS session. Tested that this change fixes establishing of SMB2 and SMB3 connections with Windows Server 2022. Signed-off-by: Pali Rohár --- fs/smb/client/cifsproto.h | 3 +++ fs/smb/client/connect.c | 20 +++++++++++++++----- fs/smb/client/transport.c | 2 +- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 5aa2769a42f3..f0ca99e6090c 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -31,6 +31,9 @@ extern void cifs_small_buf_release(void *); extern void free_rsp_buf(int, void *); extern int smb_send(struct TCP_Server_Info *, struct smb_hdr *, unsigned int /* length */); +extern int smb_send_kvec(struct TCP_Server_Info *server, + struct msghdr *msg, + size_t *sent); extern unsigned int _get_xid(void); extern void _free_xid(unsigned int); #define get_xid() \ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 9cbfdc31cdda..812487325bc7 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3059,8 +3059,10 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) * sessinit is sent but no second negprot */ struct rfc1002_session_packet req = {}; - struct smb_hdr *smb_buf = (struct smb_hdr *)&req; + struct msghdr msg = {}; + struct kvec iov = {}; unsigned int len; + size_t sent; req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name); @@ -3089,10 +3091,18 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) * As per rfc1002, @len must be the number of bytes that follows the * length field of a rfc1002 session request payload. */ - len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req); + len = sizeof(req.trailer.session_req); + req.type = RFC1002_SESSION_REQUEST; + req.flags = 0; + req.length = cpu_to_be16(len); + len += offsetof(typeof(req), trailer.session_req); + iov.iov_base = &req; + iov.iov_len = len; + iov_iter_kvec(&msg.msg_iter, ITER_SOURCE, &iov, 1, len); + rc = smb_send_kvec(server, &msg, &sent); + if (rc < 0 || len != sent) + return (rc == -EINTR || rc == -EAGAIN) ? rc : -ECONNABORTED; - smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len); - rc = smb_send(server, smb_buf, len); /* * RFC1001 layer in at least one server requires very short break before * negprot presumably because not expecting negprot to follow so fast. @@ -3101,7 +3111,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) */ usleep_range(1000, 2000); - return rc; + return 0; } static int diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 0dc80959ce48..03434dbe9374 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -179,7 +179,7 @@ delete_mid(struct mid_q_entry *mid) * Our basic "send data to server" function. Should be called with srv_mutex * held. The caller is responsible for handling the results. */ -static int +int smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg, size_t *sent) { From patchwork Sun Dec 22 16:30:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918161 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 0E12918BB9C; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=QrO28nTW6uTHkKGr7cVza5DfsOX/PjcliPytIXFT/yk1MxIVY1+VMICfkW+eurc/rneRtqmNrKbOMN6hqE8xajNuJhwEIwdbwuJORF+9aLyz4Hq7P+8bZEFnN9CeFOnK7BFHBcE9UWezwyjg7aKectFt7518cOUZLnIgxpEcJ9g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=BKn6qJJyEh7iZf6t/GAlhryB7fb7xvjVO94LMY4hvcE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=XxtaERHbAYUuzcDHt6f1rGmesEY3uwmLEbojt1owSE29lK9G1qmKuIS8ofdRmhXijznsCzrKR5pWt+N2LBJjAmbe0IA8vkPk97syAklJvY/cjVRaG1OoDbiKHTAZCgnY9NWscY+Lpxzhbqj2qt5AacRHn2gJSuZ+2O15LYVLhMM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MKeSM2OZ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MKeSM2OZ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 624C3C4CEDE; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885097; bh=BKn6qJJyEh7iZf6t/GAlhryB7fb7xvjVO94LMY4hvcE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MKeSM2OZNZE/NDBvCU4R++8n0qItHveSDZlcw5WTGHLUWOpgalkplU0N1zUAhjMU+ yhR70HkbmFbWkcx6O6QT2uvHOIDhRWXoo8X/nhUOygrrSlRPx67xVH4DlmBVa9tXWY 9ar3d7YWzdfB8S0HffLJbZr1WR9yVUPn/3J8vLRf7L2mXj8wnwQd3PrVvfEVp5GaZy jrEGJQcYC/l3c7tiU2C2AAF2VdH7c5NQF+HcD9pT9GgVgiwGCfIf6NYsT1ReppihOH rVzDoB27oApcnTt4heXAmj/yb23J5ilYdonIHWZPeJDwTrQmBujSvOQ/F4o8u5aJZu TRaOWw2d/Pu0Q== Received: by pali.im (Postfix) id 5A7E5D48; Sun, 22 Dec 2024 17:31:27 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 3/6] cifs: Improve establishing SMB connection with NetBIOS session Date: Sun, 22 Dec 2024 17:30:47 +0100 Message-Id: <20241222163050.24359-4-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Function ip_rfc1001_connect() send NetBIOS session request but currently does not read response. It even does not wait for the response. Instead it just calls usleep_range(1000, 2000) and explain in comment that some servers require short break before sending SMB negotiate packet. Response is later handled in generic is_smb_response() function called from cifs_demultiplex_thread(). That comment probably refers to the old DOS SMB server which cannot process incoming SMB negotiate packet if it has not sent NetBIOS session response packet. Note that current sleep timeout is too small when trying to establish connection to DOS SMB server running in qemu virtual machine connected over qemu user networking with guestfwd netcat options. So that usleep_range() call is not useful at all. NetBIOS session response packet contains useful error information, like the server name specified NetBIOS session request packet is incorrect. Old Windows SMB servers and even the latest SMB server on the latest Windows Server 2022 version requires that the name is the correct server name, otherwise they return error RFC1002_NOT_PRESENT. This applies for all SMB dialects (old SMB1, and also modern SMB2 and SMB3). Therefore read the reply of NetBIOS session request and implement parsing of the reply. Log received error to dmesg to help debugging reason why connection was refused. Also convert NetBIOS error to useful errno. Note that ip_rfc1001_connect() function is used only when doing connection over port 139. So the common SMB scenario over port 445 is not affected by this change at all. Signed-off-by: Pali Rohár --- fs/smb/client/connect.c | 137 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 3 deletions(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 812487325bc7..ac2e5e1d23b1 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3049,6 +3049,44 @@ bind_socket(struct TCP_Server_Info *server) return rc; } +static int +smb_recv_kvec(struct TCP_Server_Info *server, struct msghdr *msg, size_t *recv) +{ + int rc = 0; + int retries = 0; + int msg_flags = server->noblocksnd ? MSG_DONTWAIT : 0; + + *recv = 0; + + while (msg_data_left(msg)) { + rc = sock_recvmsg(server->ssocket, msg, msg_flags); + if (rc == -EAGAIN) { + retries++; + if (retries >= 14 || + (!server->noblocksnd && (retries > 2))) { + cifs_server_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", + server->ssocket); + return -EAGAIN; + } + msleep(1 << retries); + continue; + } + + if (rc < 0) + return rc; + + if (rc == 0) { + cifs_dbg(FYI, "Received no data (TCP RST)\n"); + return -ECONNABORTED; + } + + /* recv was at least partially successful */ + *recv += rc; + retries = 0; /* in case we get ENOSPC on the next send */ + } + return 0; +} + static int ip_rfc1001_connect(struct TCP_Server_Info *server) { @@ -3059,10 +3097,12 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) * sessinit is sent but no second negprot */ struct rfc1002_session_packet req = {}; + struct rfc1002_session_packet resp = {}; struct msghdr msg = {}; struct kvec iov = {}; unsigned int len; size_t sent; + size_t recv; req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name); @@ -3106,10 +3146,101 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) /* * RFC1001 layer in at least one server requires very short break before * negprot presumably because not expecting negprot to follow so fast. - * This is a simple solution that works without complicating the code - * and causes no significant slowing down on mount for everyone else + * For example DOS SMB servers cannot process negprot if it was received + * before the server sent response for SESSION_REQUEST packet. So, wait + * for the response, read it and parse it as it can contain useful error + * information (e.g. specified server name was incorrect). For example + * even the latest Windows Server 2022 SMB1 server over port 139 send + * error if its server name was in SESSION_REQUEST packet incorrect. + * Nowadays usage of port 139 is not common, so waiting for reply here + * does not slowing down mounting of common case (over port 445). */ - usleep_range(1000, 2000); + len = offsetof(typeof(resp), trailer); + iov.iov_base = &resp; + iov.iov_len = len; + iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len); + rc = smb_recv_kvec(server, &msg, &recv); + if (rc < 0 || recv != len) + return (rc == -EINTR || rc == -EAGAIN) ? rc : -ECONNABORTED; + + switch (resp.type) { + case RFC1002_POSITIVE_SESSION_RESPONSE: + if (be16_to_cpu(resp.length) != 0) { + cifs_dbg(VFS, "RFC 1002 positive session response but with invalid non-zero length %u\n", + be16_to_cpu(resp.length)); + return -EIO; + } + cifs_dbg(FYI, "RFC 1002 positive session response"); + break; + case RFC1002_NEGATIVE_SESSION_RESPONSE: + /* Read RFC1002 response error code and convert it to errno in rc */ + len = sizeof(resp.trailer.neg_ses_resp_error_code); + iov.iov_base = &resp.trailer.neg_ses_resp_error_code; + iov.iov_len = len; + iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len); + if (be16_to_cpu(resp.length) == len && + smb_recv_kvec(server, &msg, &recv) == 0 && + recv == len) { + cifs_dbg(VFS, "RFC 1002 negative session response with error 0x%x\n", + resp.trailer.neg_ses_resp_error_code); + switch (resp.trailer.neg_ses_resp_error_code) { + case RFC1002_NOT_LISTENING_CALLED: + /* server does not listen for specified server name */ + fallthrough; + case RFC1002_NOT_PRESENT: + /* server name is incorrect */ + rc = -ENOENT; + cifs_dbg(VFS, "Server rejected NetBIOS servername %.15s\n", + server->server_RFC1001_name[0] ? + server->server_RFC1001_name : + DEFAULT_CIFS_CALLED_NAME); + cifs_dbg(VFS, "Specify correct NetBIOS servername in source path or with -o servern= option\n"); + break; + case RFC1002_NOT_LISTENING_CALLING: + /* client name was not accepted by server */ + rc = -EACCES; + cifs_dbg(VFS, "Server rejected NetBIOS clientname %.15s\n", + server->workstation_RFC1001_name[0] ? + server->workstation_RFC1001_name : + "LINUX_CIFS_CLNT"); + cifs_dbg(VFS, "Specify correct NetBIOS clientname with -o netbiosname= option\n"); + break; + case RFC1002_INSUFFICIENT_RESOURCE: + /* remote server resource error */ + rc = -EREMOTEIO; + break; + case RFC1002_UNSPECIFIED_ERROR: + default: + /* other/unknown error */ + rc = -EIO; + break; + } + } else { + cifs_dbg(VFS, "RFC 1002 negative session response\n"); + rc = -EIO; + } + return rc; + case RFC1002_RETARGET_SESSION_RESPONSE: + cifs_dbg(VFS, "RFC 1002 retarget session response\n"); + if (be16_to_cpu(resp.length) == sizeof(resp.trailer.retarget_resp)) { + len = sizeof(resp.trailer.retarget_resp); + iov.iov_base = &resp.trailer.retarget_resp; + iov.iov_len = len; + iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, len); + if (smb_recv_kvec(server, &msg, &recv) == 0 && recv == len) { + cifs_dbg(VFS, "Server wants to redirect connection\n"); + cifs_dbg(VFS, "Remount with options -o ip=%pI4,port=%u\n", + &resp.trailer.retarget_resp.retarget_ip_addr, + be16_to_cpu(resp.trailer.retarget_resp.port)); + } + } + cifs_dbg(VFS, "Closing connection\n"); + /* FIXME: Should we automatically redirect to new retarget_resp server? */ + return -EMULTIHOP; + default: + cifs_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", resp.type); + return -EIO; + } return 0; } From patchwork Sun Dec 22 16:30:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918164 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 C30B3192B62; Sun, 22 Dec 2024 16:31:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=dgfGEFr28SodvJkoUVe020ATJvVteFXvvavtvSSMpOWmTeJeNQvdtoesC0MIL/KH2diyOTmbKBMNXdnLMhlaWzNFsJjTV6cr12JHhQfWNaimYLDit1kPKhOdiMrpTnxQFYhNB18m3JmSqgjEMbSM53y1hOhLQRneS7+aXt8Dr6E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=kCnrqYnrhXWoZnzA9iIB4hqNpNg9Ig0gbeOajZtaOkI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=Y8tInnYI6LbmS2qMUz7mEFx8rE/xvP4tmpHNjLhK1adhgPO3Ot8OBBI5kWYl8vZJQZSeCKZQVcHgPR23Yp24IpKSPS560Kw8cLd8+BleIyrgdA0a2m4BDyVzLSwSjVTKEyGWD/8lP2FlruuzJT6DdJA3jciCTziWy4QEDLnS7Tc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lboOst4/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="lboOst4/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5B1FEC4CED3; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885098; bh=kCnrqYnrhXWoZnzA9iIB4hqNpNg9Ig0gbeOajZtaOkI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lboOst4/B9dHFIu83MRV6lfnPQ3M4QofV0kUPmoFxD0ZGj+oDpdBitYXWZuC2p/ku G3Uop7daby6NGiFyrvZB4FURSQOH8fJKz6eq07LftAVBKiPBThRbq835gCWxASZI/z fZVbqyZk/1LzYLefPqk6lT+j4ICueet1mDgQD3IgTQ9pklExEtsTVacN0gyL8zuonL UShUPybQtNFn1kk05NjwWQUMN4gEzEoKX+nREZUbcaOOL65pKhSMGP/LeNyyfP0LJj e2dTHnY6RqXIzSL4U38l+4hVqnrRh8l7eFrOshksc3c9NGFf6A6TZ2rE2TPZQsFQLC o5fOb/zSRT4CQ== Received: by pali.im (Postfix) id 86313EEC; Sun, 22 Dec 2024 17:31:27 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 4/6] cifs: Improve handling of NetBIOS packets Date: Sun, 22 Dec 2024 17:30:48 +0100 Message-Id: <20241222163050.24359-5-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Now all NetBIOS session logic is handled in ip_rfc1001_connect() function, so cleanup is_smb_response() function which contains generic handling of incoming SMB packets. Note that function is_smb_response() is not used directly or indirectly (e.g. over cifs_demultiplex_thread() by ip_rfc1001_connect() function. Except the Negative Session Response and the Session Keep Alive packet, the cifs_demultiplex_thread() should not receive any NetBIOS session packets. And Session Keep Alive packet may be received only when the NetBIOS session was established by ip_rfc1001_connect() function. So treat any such packet as error and schedule reconnect. Negative Session Response packet is returned from Windows SMB server (from Windows 98 and also from Windows Server 2022) if client sent over port 139 SMB negotiate request without previously establishing a NetBIOS session. The common scenario is that Negative Session Response packet is returned for the SMB negotiate packet, which is the first one which SMB client sends (if it is not establishing a NetBIOS session). Note that server port 139 may be forwarded and mapped between virtual machines to different number. And Linux SMB client do not call function ip_rfc1001_connect() when prot is not 139. So nowadays when using port mapping or port forwarding between VMs, it is not so uncommon to see this error. Currently the logic on Negative Session Response packet changes server port to 445 and force reconnection. But this logic does not work when using non-standard port numbers and also does not help if the server on specified port is requiring establishing a NetBIOS session. Fix this Negative Session Response logic and instead of changing server port (on which server does not have to listen), force reconnection with establishing a NetBIOS session. Signed-off-by: Pali Rohár --- fs/smb/client/cifsglob.h | 3 + fs/smb/client/connect.c | 140 +++++++++++++++++++++++++++++++++----- fs/smb/client/transport.c | 3 + 3 files changed, 128 insertions(+), 18 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index bea4b8a8b30e..b56fca6dd195 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -717,6 +717,7 @@ struct TCP_Server_Info { __u64 conn_id; /* connection identifier (useful for debugging) */ int srv_count; /* reference counter */ int rfc1001_sessinit; /* whether to estasblish netbios session */ + bool with_rfc1001; /* if netbios session is used */ /* 15 character server name + 0x20 16th byte indicating type = srv */ char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; struct smb_version_operations *ops; @@ -1728,6 +1729,7 @@ struct mid_q_entry { void *resp_buf; /* pointer to received SMB header */ unsigned int resp_buf_size; int mid_state; /* wish this were enum but can not pass to wait_event */ + int mid_rc; /* rc for MID_RC */ unsigned int mid_flags; __le16 command; /* smb command code */ unsigned int optype; /* operation type */ @@ -1890,6 +1892,7 @@ static inline bool is_replayable_error(int error) #define MID_RESPONSE_MALFORMED 0x10 #define MID_SHUTDOWN 0x20 #define MID_RESPONSE_READY 0x40 /* ready for other process handle the rsp */ +#define MID_RC 0x80 /* mid_rc contains custom rc */ /* Flags */ #define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index ac2e5e1d23b1..9a76cdf71086 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -386,7 +386,7 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num * */ static int __cifs_reconnect(struct TCP_Server_Info *server, - bool mark_smb_session) + bool mark_smb_session, bool once) { int rc = 0; @@ -414,6 +414,9 @@ static int __cifs_reconnect(struct TCP_Server_Info *server, if (rc) { cifs_server_unlock(server); cifs_dbg(FYI, "%s: reconnect error %d\n", __func__, rc); + /* If was asked to reconnect only once, do not try it more times */ + if (once) + break; msleep(3000); } else { atomic_inc(&tcpSesReconnectCount); @@ -573,24 +576,38 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server) return rc; } -int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) +static int +_cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session, bool once) { mutex_lock(&server->refpath_lock); if (!server->leaf_fullpath) { mutex_unlock(&server->refpath_lock); - return __cifs_reconnect(server, mark_smb_session); + return __cifs_reconnect(server, mark_smb_session, once); } mutex_unlock(&server->refpath_lock); return reconnect_dfs_server(server); } #else -int cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) +static int +_cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session, bool once) { - return __cifs_reconnect(server, mark_smb_session); + return __cifs_reconnect(server, mark_smb_session, once); } #endif +int +cifs_reconnect(struct TCP_Server_Info *server, bool mark_smb_session) +{ + return _cifs_reconnect(server, mark_smb_session, false); +} + +static int +cifs_reconnect_once(struct TCP_Server_Info *server) +{ + return _cifs_reconnect(server, true, true); +} + static void cifs_echo_request(struct work_struct *work) { @@ -817,26 +834,110 @@ is_smb_response(struct TCP_Server_Info *server, unsigned char type) /* Regular SMB response */ return true; case RFC1002_SESSION_KEEP_ALIVE: + /* + * RFC 1002 session keep alive can sent by the server only when + * we established a RFC 1002 session. But Samba servers send + * RFC 1002 session keep alive also over port 445 on which + * RFC 1002 session is not established. + */ cifs_dbg(FYI, "RFC 1002 session keep alive\n"); break; case RFC1002_POSITIVE_SESSION_RESPONSE: - cifs_dbg(FYI, "RFC 1002 positive session response\n"); + /* + * RFC 1002 positive session response cannot be returned + * for SMB request. RFC 1002 session response is handled + * exclusively in ip_rfc1001_connect() function. + */ + cifs_server_dbg(VFS, "RFC 1002 positive session response (unexpected)\n"); + cifs_reconnect(server, true); break; case RFC1002_NEGATIVE_SESSION_RESPONSE: /* * We get this from Windows 98 instead of an error on - * SMB negprot response. - */ - cifs_dbg(FYI, "RFC 1002 negative session response\n"); - /* give server a second to clean up */ - msleep(1000); - /* - * Always try 445 first on reconnect since we get NACK - * on some if we ever connected to port 139 (the NACK - * is since we do not begin with RFC1001 session - * initialize frame). + * SMB negprot response, when we have not established + * RFC 1002 session (which means ip_rfc1001_connect() + * was skipped). Note that same still happens with + * Windows Server 2022 when connecting via port 139. + * So for this case when mount option -o nonbsessinit + * was not specified, try to reconnect with establishing + * RFC 1002 session. If new socket establishment with + * RFC 1002 session was successful then return to the + * mid's caller -EAGAIN, so it can retry the request. */ - cifs_set_port((struct sockaddr *)&server->dstaddr, CIFS_PORT); + if (!cifs_rdma_enabled(server) && + server->tcpStatus == CifsInNegotiate && + !server->with_rfc1001 && + server->rfc1001_sessinit != 0) { + int rc, mid_rc; + struct mid_q_entry *mid, *nmid; + LIST_HEAD(dispose_list); + + cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate, retrying with NetBIOS session\n"); + + /* + * Before reconnect, delete all pending mids for this + * server, so reconnect would not signal connection + * aborted error to mid's callbacks. Note that for this + * server there should be exactly one pending mid + * corresponding to SMB1/SMB2 Negotiate packet. + */ + spin_lock(&server->mid_lock); + list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) { + kref_get(&mid->refcount); + list_move(&mid->qhead, &dispose_list); + mid->mid_flags |= MID_DELETED; + } + spin_unlock(&server->mid_lock); + + /* Now try to reconnect once with NetBIOS session. */ + server->with_rfc1001 = true; + rc = cifs_reconnect_once(server); + + /* + * If reconnect was successful then indicate -EAGAIN + * to mid's caller. If reconnect failed with -EAGAIN + * then mask it as -EHOSTDOWN, so mid's caller would + * know that it failed. + */ + if (rc == 0) + mid_rc = -EAGAIN; + else if (rc == -EAGAIN) + mid_rc = -EHOSTDOWN; + else + mid_rc = rc; + + /* + * After reconnect (either successful or unsuccessful) + * deliver reconnect status to mid's caller via mid's + * callback. Use MID_RC state which indicates that the + * return code should be read from mid_rc member. + */ + list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) { + list_del_init(&mid->qhead); + mid->mid_rc = mid_rc; + mid->mid_state = MID_RC; + mid->callback(mid); + release_mid(mid); + } + + /* + * If reconnect failed then wait two seconds. In most + * cases we were been called from the mount context and + * delivered failure to mid's callback will stop this + * receiver task thread and fails the mount process. + * So wait two seconds to prevent another reconnect + * in this task thread, which would be useless as the + * mount context will fail at all. + */ + if (rc != 0) + msleep(2000); + } else { + cifs_server_dbg(VFS, "RFC 1002 negative session response (unexpected)\n"); + cifs_reconnect(server, true); + } + break; + case RFC1002_RETARGET_SESSION_RESPONSE: + cifs_server_dbg(VFS, "RFC 1002 retarget session response (unexpected)\n"); cifs_reconnect(server, true); break; default: @@ -1739,6 +1840,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, memcpy(tcp_ses->server_RFC1001_name, ctx->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); tcp_ses->rfc1001_sessinit = ctx->rfc1001_sessinit; + tcp_ses->with_rfc1001 = false; tcp_ses->session_estab = false; tcp_ses->sequence_number = 0; tcp_ses->channel_sequence_num = 0; /* only tracked for primary channel */ @@ -3242,6 +3344,7 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) return -EIO; } + server->with_rfc1001 = true; return 0; } @@ -3355,7 +3458,8 @@ generic_ip_connect(struct TCP_Server_Info *server) * server port (139) and it was not explicitly disabled by mount option * -o nonbsessinit. */ - if (server->rfc1001_sessinit == 1 || + if (server->with_rfc1001 || + server->rfc1001_sessinit == 1 || (server->rfc1001_sessinit == -1 && sport == htons(RFC1001_PORT))) rc = ip_rfc1001_connect(server); diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 03434dbe9374..266af17aa7d9 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -894,6 +894,9 @@ cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *server) case MID_SHUTDOWN: rc = -EHOSTDOWN; break; + case MID_RC: + rc = mid->mid_rc; + break; default: if (!(mid->mid_flags & MID_DELETED)) { list_del_init(&mid->qhead); From patchwork Sun Dec 22 16:30:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918162 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 64D46191494; Sun, 22 Dec 2024 16:31:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=C+fc5PQPiVSgA1W9ukjyCJpjdunxZOHcw1A0Z5LdaLFiw8WsGduaFQxipXaEdLcEbJpSet9HmCP+yRB6hKo7+65l+oUJQzG7VLMYcY/UoaaLrD4kTDI6VLzpQdRuFuAjObX73XCSprG+evLIudganzXz8rCsQ5a14ZoUL5NcI08= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=NRRD2uElNzPne/pT6ZpTaz7mf1/D4UiWgY+uhccv2l0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=DiV6B+CR3NvlWT+eHLJowe/djC8s2MZ6rZWwSmto8+4je4dp12G5vL3uWNnItEpEjgibZAmevtur7CJxW8JzGYrOLKg5ni4ehN/2pz8hu4BCdJ6e63aGYYS7l8Iezv9kTDF0bcvMEXKlrHdLpLx69SaPobgGw2T5Q0nFSo/0cP8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uGjb6QIJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uGjb6QIJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E06F4C4CEDC; Sun, 22 Dec 2024 16:31:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885098; bh=NRRD2uElNzPne/pT6ZpTaz7mf1/D4UiWgY+uhccv2l0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uGjb6QIJzmtCS6Us5/vgHCRG5Vs9dxlv4AToOib9mD3SIXRdvR6XXFKJb3oLxZVuC lIEL7sZYw5YHL7vESYxduYa1VDkxVeerCoK11RZEgdab2KmAcxVCu2KBQq9wITvHAD 6bSz76yqRJH8EqkFPp3RKMRXfpBqo653tV3z1EsvU6ZYEMuBHaFPAa0njELHdqtMUF emL+C6H5cLCLdkhoX0/YEmg+j1JvTPyVfj1fPKFrSRemN1H6asA03Ren29YLTJ42SY 66Twz/m2FFOLiZS5lHXxHHzKOcYX2D4+GdORmAGYpDL7J+CUlmJ6S7fp28UMk8WWtF DQsDtUeNu3icQ== Received: by pali.im (Postfix) id BC88EF38; Sun, 22 Dec 2024 17:31:27 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 5/6] cifs: Fix negotiate retry functionality Date: Sun, 22 Dec 2024 17:30:49 +0100 Message-Id: <20241222163050.24359-6-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 SMB negotiate retry functionality in cifs_negotiate() is currently broken and does not work when doing socket reconnect. Caller of this function, which is cifs_negotiate_protocol() requires that tcpStatus after successful execution of negotiate callback stay in CifsInNegotiate. But if the CIFSSMBNegotiate() called from cifs_negotiate() fails due to connection issues then tcpStatus is changed as so repeated CIFSSMBNegotiate() call does not help. Fix this problem by moving retrying code from negotiate callback (which is either cifs_negotiate() or smb2_negotiate()) to cifs_negotiate_protocol() which is caller of those callbacks. This allows to properly handle and implement correct transistions between tcpStatus states as function cifs_negotiate_protocol() already handles it. With this change, cifs_negotiate_protocol() now handles also -EAGAIN error set by the RFC1002_NEGATIVE_SESSION_RESPONSE processing after reconnecting with NetBIOS session. Signed-off-by: Pali Rohár --- fs/smb/client/connect.c | 10 ++++++++++ fs/smb/client/smb1ops.c | 7 ------- fs/smb/client/smb2ops.c | 3 --- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 9a76cdf71086..fdeeb0b9000d 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -4206,11 +4206,13 @@ int cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { + bool in_retry = false; int rc = 0; if (!server->ops->need_neg || !server->ops->negotiate) return -ENOSYS; +retry: /* only send once per connect */ spin_lock(&server->srv_lock); if (server->tcpStatus != CifsGood && @@ -4230,6 +4232,14 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses, spin_unlock(&server->srv_lock); rc = server->ops->negotiate(xid, ses, server); + if (rc == -EAGAIN) { + /* Allow one retry attempt */ + if (!in_retry) { + in_retry = true; + goto retry; + } + rc = -EHOSTDOWN; + } if (rc == 0) { spin_lock(&server->srv_lock); if (server->tcpStatus == CifsInNegotiate) diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 01a7d6b23c7e..0533aca770fc 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -426,13 +426,6 @@ cifs_negotiate(const unsigned int xid, { int rc; rc = CIFSSMBNegotiate(xid, ses, server); - if (rc == -EAGAIN) { - /* retry only once on 1st time connection */ - set_credits(server, 1); - rc = CIFSSMBNegotiate(xid, ses, server); - if (rc == -EAGAIN) - rc = -EHOSTDOWN; - } return rc; } diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 50adb5cdfce9..119ecb6641d1 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -464,9 +464,6 @@ smb2_negotiate(const unsigned int xid, server->CurrentMid = 0; spin_unlock(&server->mid_lock); rc = SMB2_negotiate(xid, ses, server); - /* BB we probably don't need to retry with modern servers */ - if (rc == -EAGAIN) - rc = -EHOSTDOWN; return rc; } From patchwork Sun Dec 22 16:30:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 13918163 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 BAAC31925AF; Sun, 22 Dec 2024 16:31:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; cv=none; b=AcW19yJK61GvKv/9RXEXLK1M/GYQ1qaPNlHWy55qOViYttCGduzoxZGIPXiekcMWUcH4/YWuFJxpBS7Niv3+OzLYvtG383tuQhyHHN1mpXbYLSHQCF84TDm79WAqteGjiRxX9WPsH5nx8i2nUXFSglln7sZYixNnGjA3PSTn74Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734885098; c=relaxed/simple; bh=roMvo+vaCtZhM+ffAECwM9kTdTDexaaoB04VHkeB1IU=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version:Content-Type; b=c1XnYZYWmvU/EhDYtf/jo5UlNJsIg0mdFIgH/QtSK3gBHEoOTfQkZme10fgSOeATsYnlOmxaY3f2GAGdVkFV3oxpFBz06Etudm6esp5tFCQBlqjhBWI9Jd9JiCIcemRbwVX7i1Yu25O4FrFu+C4kItaMriUqIBj2wvJaNHjk8Rw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bou9qV7T; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="bou9qV7T" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 18DD2C4CEDF; Sun, 22 Dec 2024 16:31:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1734885098; bh=roMvo+vaCtZhM+ffAECwM9kTdTDexaaoB04VHkeB1IU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bou9qV7TQncyJim9svbw5bDJcXfV9Hz/dIiV1AVFg0lVZ03jVFE9h3sKIKPfjq0P8 5+DbhVH4jukBG+e1U4WQJvGh2FYEJn5jgQ/DTZyRvD3bs/XHt1pciXA060sAB+UnE1 nm8Hdt29RGguaqEn59K8sDruan4hqI+IyY1mrkaa2zvwJ9pcrK9cvi57ZkFF/85Jx/ MRxgL0l6EJXjzJyeH5dT0VdrurGLIw0JNZziAfDO7xOg4kBK0+YQZCybHmTQR5jEwH 41k+510l3/zyJ1sQ205TcRvkyOD1dCJsc3LbbBqigUoXIaP+aNuBAhqmhZy3NFEDBG SSWEqUT6MONtQ== Received: by pali.im (Postfix) id EF695F3C; Sun, 22 Dec 2024 17:31:27 +0100 (CET) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Steve French , Paulo Alcantara , Ronnie Sahlberg Cc: linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 6/6] cifs: Set default Netbios RFC1001 server name to hostname in UNC Date: Sun, 22 Dec 2024 17:30:50 +0100 Message-Id: <20241222163050.24359-7-pali@kernel.org> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241222163050.24359-1-pali@kernel.org> References: <20241222163050.24359-1-pali@kernel.org> Precedence: bulk X-Mailing-List: linux-cifs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Windows SMB servers (including SMB2+) which are working over RFC1001 require that Netbios server name specified in RFC1001 Session Request packet is same as the UNC host name. Netbios server name can be already specified manually via -o servern= option. With this change the RFC1001 server name is set automatically by extracting the hostname from the mount source. Signed-off-by: Pali Rohár --- fs/smb/client/fs_context.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index 3774f02f45c9..0bda7ada4f81 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -1125,6 +1125,7 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, int i, opt; bool is_smb3 = !strcmp(fc->fs_type->name, "smb3"); bool skip_parsing = false; + char *hostname; cifs_dbg(FYI, "CIFS: parsing cifs mount option '%s'\n", param->key); @@ -1447,6 +1448,16 @@ static int smb3_fs_context_parse_param(struct fs_context *fc, cifs_errorf(fc, "OOM when copying UNC string\n"); goto cifs_parse_mount_err; } + hostname = extract_hostname(ctx->UNC); + if (IS_ERR(hostname)) { + cifs_errorf(fc, "Cannot extract hostname from UNC string\n"); + goto cifs_parse_mount_err; + } + /* last byte, type, is 0x20 for servr type */ + memset(ctx->target_rfc1001_name, 0x20, RFC1001_NAME_LEN_WITH_NULL); + for (i = 0; i < RFC1001_NAME_LEN && hostname[i] != 0; i++) + ctx->target_rfc1001_name[i] = toupper(hostname[i]); + kfree(hostname); break; case Opt_user: kfree(ctx->username);