[PATCH OLK-6.6] cifs: Fix establishing NetBIOS session for SMB2+ connection
From: Pali Rohár <pali@kernel.org> stable inclusion from stable-v6.6.93 commit ee68e068cf92f8192ef61557789a6bb7f4b49ce0 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/8333 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=... -------------------------------- [ Upstream commit 781802aa5a5950f99899f13ff9d760f5db81d36d ] 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 <pali@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Wang Zhaolong <wangzhaolong@huaweicloud.com> --- 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 7f97e5468652..858492220437 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -29,10 +29,13 @@ extern void cifs_buf_release(void *); extern struct smb_hdr *cifs_small_buf_get(void); 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() \ ({ \ unsigned int __xid = _get_xid(); \ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 23e0b902239a..3eae50bfdb6b 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -3049,12 +3049,14 @@ ip_rfc1001_connect(struct TCP_Server_Info *server) * some servers require RFC1001 sessinit before sending * negprot - BB check reconnection in case where second * 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); if (server->server_RFC1001_name[0] != 0) rfc1002mangle(req.trailer.session_req.called_name, @@ -3079,23 +3081,31 @@ 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. * This is a simple solution that works without complicating the code * and causes no significant slowing down on mount for everyone else */ usleep_range(1000, 2000); - return rc; + return 0; } static int generic_ip_connect(struct TCP_Server_Info *server) { diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 8f045db44319..1d796400680c 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -177,11 +177,11 @@ delete_mid(struct mid_q_entry *mid) * @sent: amount of data sent on socket is stored here * * 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) { int rc = 0; int retries = 0; -- 2.34.3
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://atomgit.com/openeuler/kernel/merge_requests/20005 邮件列表地址:https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6XR... FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://atomgit.com/openeuler/kernel/merge_requests/20005 Mailing list address: https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/6XR...
participants (2)
-
patchwork bot -
Wang Zhaolong