Skip to contentSkip to conversation

failure to reconnect on SMB server restart with custom TCP port (not 445): Host is down (at least since 6.6.95)

REGRESSION Dr. Thomas Orgis 5 participants 11 messages Mar 10 – Apr 13

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

Dear Linux-CIFS maintainer(s),

I stumbled upon a regression in the Linux cifs/smb3 client when working with a smbd using a non-standard port. I am not the first to note this, see

	https://bbs.archlinux.org/viewtopic.php?id=306712

which is a report from mid last year, indicating the problem sometime after Linux 6.6.72. It is a very simple issue, where details of the kernel builds or mount setup don't seem to matter much: Older kernels reconnect to a SMB server that was restarted (old processes killed and replaced), newer kernels do not and just have a defunct mount.

I reproduced this in our HPC cluster environment with such smb.conf on the server side

[global]
security = user
map to guest = Bad Password
server role = standalone server
smb ports = 1445

[public]
path = /some/path
guest ok = yes
read only = yes

and such a mount command on the client:

mount -t smb3 -o port=1445,user=guest,password=foo //server/public dir

When I kill and re-start smbd on the server, older client kernels reconnect and continue to return listings and files from the share, while newer kernels give this:

$ ls dir
ls: cannot access 'dir': Host is down

I also see that no smbd process is spawned for the client connection. The client simply seems not to try to talk to the server anymore. This apparently is only the case with the changed SMB port. With the default 445, the same setup works. I once tested that with root running smbd or by forwarding port 445 to 1445 via socat on the server, things are back to normal. The share continues working, server processes are spawned and talked to by the client.

Also, it seems that this only covers cases with actual network transfer. Mounting on the server from itself (localhost) seems to be fine on either port.

I narrowed this down to these kernels working in the same system (which is a HPC node booting a Debian 12 image with our custom kernel built from vanilla kernel.org sources, barely changed):

6.6.53: good
6.6.78: good
6.6.86: good

Also, an Ubuntu client with 5.15.0-164-generic in a distinct setup, talking to a differing server, was also fine. So I assume clients reconnecting is baseline behaviour. I tested these kernel versions to have the regression:

6.6.95: bad
6.6.97: bad
6.6.101: bad
6.12.47: bad
6.12.55: bad
6.18.16: bad
7.0.0-rc3: bad

The last one is torvalds/linux.git as of today, commit 1f318b96cc84d7c2ab792fcc0bfd42a7ca890681.

So it looks like something backported into 6.6 series between 6.6.86 and 6.6.95 broke the behaviour and this stayed with us up to the current RC. This matches the report in the Arch Linux forums. I tested by building kernels and booting real hardware … so this already took some time and effort. I can test a specific patch/version quite easily, but don't have a fully automatic bisecting setup.

The issue should be obvious in any environment, though. It seems to be universal once you choose a custom port and have some real (or emulated?) network between client and server.

Hopefully an easy fix for someone close to the code?

Alrighty then,

Thomas

PS: $ grep -e SMB -e CIFS .config |grep -i -v -e SMBUS -e SMBIOS CONFIG_RMI4_SMB=m
# CONFIG_CHARGER_SMB347 is not set
CONFIG_CIFS=m
CONFIG_CIFS_STATS2=y CONFIG_CIFS_ALLOW_INSECURE_LEGACY=y CONFIG_CIFS_UPCALL=y
CONFIG_CIFS_XATTR=y
CONFIG_CIFS_POSIX=y
CONFIG_CIFS_DEBUG=y
# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_DEBUG_DUMP_KEYS is not set CONFIG_CIFS_DFS_UPCALL=y
# CONFIG_CIFS_SWN_UPCALL is not set
# CONFIG_CIFS_SMB_DIRECT is not set CONFIG_CIFS_FSCACHE=y
# CONFIG_CIFS_COMPRESSION is not set CONFIG_SMB_SERVER=m
# CONFIG_SMB_SERVER_SMBDIRECT is not set CONFIG_SMB_SERVER_CHECK_CAP_NET_ADMIN=y
# CONFIG_SMB_SERVER_KERBEROS5 is not set
CONFIG_SMBFS=m

PPS: I am testing running Samba smbd as unprivileged user on a non-standard port to find a cheap/simple least-privilege way to re-export a custom FUSE fs to clients, read-only. Samba smbd doesn't really like that, but can be coerced, esp. in a mount namespace where the hardcoded paths it uses can be remapped. I could add more layers to map the port back to 445 or do something else entirely, but maybe this is a half-reasonable scenario why one would like to talk SMB on a different port.

Signature · 2 lines
Dr. Thomas Orgis
HPC @ Universität Hamburg
#1 lore raw
Quoted 27 lines · Dr. Thomas Orgis

Dear Linux-CIFS maintainer(s),

I stumbled upon a regression in the Linux cifs/smb3 client when working with a smbd using a non-standard port. I am not the first to note this, see

	https://bbs.archlinux.org/viewtopic.php?id=306712

which is a report from mid last year, indicating the problem sometime after Linux 6.6.72. It is a very simple issue, where details of the kernel builds or mount setup don't seem to matter much: Older kernels reconnect to a SMB server that was restarted (old processes killed and replaced), newer kernels do not and just have a defunct mount.

I reproduced this in our HPC cluster environment with such smb.conf on the server side

[global]
security = user
map to guest = Bad Password
server role = standalone server
smb ports = 1445

[public]
path = /some/path
guest ok = yes
read only = yes

Quoted 8 lines

and such a mount command on the client:

mount -t smb3 -o port=1445,user=guest,password=foo //server/public dir

When I kill and re-start smbd on the server, older client kernels reconnect and continue to return listings and files from the share, while newer kernels give this:

My suspicion is that the regression was introduced by:

5713127da855 ("cifs: update dstaddr whenever channel iface is updated")

That change causes parse_server_interfaces() -- should this be running without multichannel mount option? -- to overwrite the port stored in server->dstaddr with CIFS_PORT.

The attached patch preserves the existing port from server->dstaddr.

Note that I have not yet tested this patch or confirmed the regression with a bisect. If you can't, I will try to do that tomorrow.

Signature · 2 lines
Henrique
SUSE Labs

From 1218840331eef3a6b523ad39e851a412f570b7d8 Mon Sep 17 00:00:00 2001
From: Henrique Carvalho <[email protected]>
Date: Tue, 10 Mar 2026 22:52:52 -0300
Subject: [PATCH] smb: client: preserve destination port when parsing server
interfaces

parse_server_interfaces() initializes interface socket addresses with CIFS_PORT. When the mount uses a non-default port this overwrites the configured destination port.

Later, cifs_chan_update_iface() copies this sockaddr into server->dstaddr, causing reconnect attempts to use the wrong port after server interface updates.

Use the existing port from server->dstaddr instead.

Fixes 5713127da855 ("cifs: update dstaddr whenever channel iface is updated")
---
 fs/smb/client/smb2ops.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
fs/smb/client/smb2ops.c +5 -2
index 7f2d3459cbf9..d3cbfb3fdfc9 100644
@@ -628,6 +628,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
 	struct smb_sockaddr_in6 *p6;
 	struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
 	struct cifs_server_iface tmp_iface;
+	__be16 port;
 	ssize_t bytes_left;
 	size_t next = 0;
 	int nb_iface = 0;
@@ -676,18 +677,20 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
 		 * conversion explicit in case either one changes.
 		 */
 		case INTERNETWORK:
+			port = ((struct sockaddr_in *)&ses->server->dstaddr)->sin_port;
 			addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
 			p4 = (struct smb_sockaddr_in *)p->Buffer;
 			addr4->sin_family = AF_INET;
 			memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
 
 			/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
-			addr4->sin_port = cpu_to_be16(CIFS_PORT);
+			addr4->sin_port = port;
 
 			cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
 				 &addr4->sin_addr);
 			break;
 		case INTERNETWORKV6:
+			port = ((struct sockaddr_in6 *)&ses->server->dstaddr)->sin6_port;
 			addr6 =	(struct sockaddr_in6 *)&tmp_iface.sockaddr;
 			p6 = (struct smb_sockaddr_in6 *)p->Buffer;
 			addr6->sin6_family = AF_INET6;
@@ -696,7 +699,7 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
 			/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
 			addr6->sin6_flowinfo = 0;
 			addr6->sin6_scope_id = 0;
-			addr6->sin6_port = cpu_to_be16(CIFS_PORT);
+			addr6->sin6_port = port;
 
 			cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
 				 &addr6->sin6_addr);
Signature · 1 line
2.52.0
#2 lore raw

Am Tue, 10 Mar 2026 23:06:24 -0300
schrieb Henrique Carvalho <[email protected]>:

Quoted 9 lines

My suspicion is that the regression was introduced by:

5713127da855 ("cifs: update dstaddr whenever channel iface is updated")

That change causes parse_server_interfaces() -- should this be running without multichannel mount option? -- to overwrite the port stored in server->dstaddr with CIFS_PORT.

The attached patch preserves the existing port from server->dstaddr.

Splendit! This is the simple something that would've taken me long to find among all the ongoing changes in the SMB subsystem.

I just built a 6.6.129 kernel with the slightly adapted patch (as that is my production series right now before I jump to newer LTS) and can confirm that this fixes the issue.

Do you need a confirmation with 7.0.0-rc3? I guess the picture is clear enough as-is. I've started a build and can give a short follow-up later.

Alrighty then,

Thomas

Signature · 2 lines
Dr. Thomas Orgis
HPC @ Universität Hamburg
fs/smb/client/smb2ops.c renamed from fs/smb/client/smb2ops.c.orig +5 -2
@@ -586,6 +586,7 @@
 	struct iface_info_ipv6 *p6;
 	struct cifs_server_iface *info = NULL, *iface = NULL, *niface = NULL;
 	struct cifs_server_iface tmp_iface;
+	__be16 port;
 	ssize_t bytes_left;
 	size_t next = 0;
 	int nb_iface = 0;
@@ -634,18 +635,20 @@
 		 * conversion explicit in case either one changes.
 		 */
 		case INTERNETWORK:
+			port = ((struct sockaddr_in *)&ses->server->dstaddr)->sin_port;
 			addr4 = (struct sockaddr_in *)&tmp_iface.sockaddr;
 			p4 = (struct iface_info_ipv4 *)p->Buffer;
 			addr4->sin_family = AF_INET;
 			memcpy(&addr4->sin_addr, &p4->IPv4Address, 4);
 
 			/* [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these */
-			addr4->sin_port = cpu_to_be16(CIFS_PORT);
+			addr4->sin_port = port;
 
 			cifs_dbg(FYI, "%s: ipv4 %pI4\n", __func__,
 				 &addr4->sin_addr);
 			break;
 		case INTERNETWORKV6:
+			port = ((struct sockaddr_in6 *)&ses->server->dstaddr)->sin6_port;
 			addr6 =	(struct sockaddr_in6 *)&tmp_iface.sockaddr;
 			p6 = (struct iface_info_ipv6 *)p->Buffer;
 			addr6->sin6_family = AF_INET6;
@@ -654,7 +657,7 @@
 			/* [MS-SMB2] 2.2.32.5.1.2 Clients MUST ignore these */
 			addr6->sin6_flowinfo = 0;
 			addr6->sin6_scope_id = 0;
-			addr6->sin6_port = cpu_to_be16(CIFS_PORT);
+			addr6->sin6_port = port;
 
 			cifs_dbg(FYI, "%s: ipv6 %pI6\n", __func__,
 				 &addr6->sin6_addr);
#3 lore raw

Am Wed, 11 Mar 2026 09:16:53 +0100
schrieb "Dr. Thomas Orgis" <[email protected]>:

Quoted 2 lines

Do you need a confirmation with 7.0.0-rc3? I guess the picture is clear enough as-is. I've started a build and can give a short follow-up later.

I can confirm that the unmodified patch works with 7.0.0-rc3 in my setup.

Alrighty then,

Thomas

Signature · 2 lines
Dr. Thomas Orgis
HPC @ Universität Hamburg
#4 lore raw
Quoted 9 lines · Dr. Thomas Orgis

Am Wed, 11 Mar 2026 09:16:53 +0100
schrieb "Dr. Thomas Orgis" <[email protected]>:

Quoted 2 lines

Do you need a confirmation with 7.0.0-rc3? I guess the picture is clear enough as-is. I've started a build and can give a short follow-up later.

I can confirm that the unmodified patch works with 7.0.0-rc3 in my setup.

Thank you, Dr. Thomas, for testing this and confirming the fix works.

Can we add your "Tested-by: Dr. Thomas Orgis <[email protected]>" ?

Signature · 2 lines
Henrique
SUSE Labs
#5 lore raw

Am Wed, 11 Mar 2026 13:12:25 -0300
schrieb Henrique Carvalho <[email protected]>:

Quoted 1 line

Can we add your "Tested-by: Dr. Thomas Orgis <[email protected]>" ?

Sure! Thanks for the quick action!

Alrighty then,

Thomas

Signature · 2 lines
Dr. Thomas Orgis
HPC @ Universität Hamburg
#6 lore raw
In reply to Henrique Carvalho
Quoted 46 lines · Henrique Carvalho
Quoted 27 lines · Dr. Thomas Orgis

Dear Linux-CIFS maintainer(s),

I stumbled upon a regression in the Linux cifs/smb3 client when working with a smbd using a non-standard port. I am not the first to note this, see

      https://bbs.archlinux.org/viewtopic.php?id=306712

which is a report from mid last year, indicating the problem sometime after Linux 6.6.72. It is a very simple issue, where details of the kernel builds or mount setup don't seem to matter much: Older kernels reconnect to a SMB server that was restarted (old processes killed and replaced), newer kernels do not and just have a defunct mount.

I reproduced this in our HPC cluster environment with such smb.conf on the server side

[global]
security = user
map to guest = Bad Password
server role = standalone server
smb ports = 1445

[public]
path = /some/path
guest ok = yes
read only = yes

Quoted 8 lines

and such a mount command on the client:

mount -t smb3 -o port=1445,user=guest,password=foo //server/public dir

When I kill and re-start smbd on the server, older client kernels reconnect and continue to return listings and files from the share, while newer kernels give this:

My suspicion is that the regression was introduced by:

5713127da855 ("cifs: update dstaddr whenever channel iface is updated")

That change causes parse_server_interfaces() -- should this be running without multichannel mount option? -- to overwrite the port stored in server->dstaddr with CIFS_PORT.

Quoted 8 lines

The attached patch preserves the existing port from server->dstaddr.

Note that I have not yet tested this patch or confirmed the regression with a bisect. If you can't, I will try to do that tomorrow.

--
Henrique
SUSE Labs

Hi Henrique,

AFAIK, the ignoring of port from the results was by design and part of the original code back in 2018:
CIFS: parse and store info on iface queries

Also, the comment in the code just above says why this is so. [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these

I checked this section and it says:
Port (2 bytes): This field MUST NOT be used and MUST be reserved. The server SHOULD set this field to zero, and the client MUST ignore it on receipt.

Based on the conversations here, it looks like smbd ignores this.

I think the right fix would be to make sure that cifs_chan_update_iface gets called only for secondary channels. That way, it will not get called for single channel scenarios.

Signature · 2 lines
Regards,
Shyam
#7 lore raw
Quoted 71 lines · Shyam Prasad N
Quoted 46 lines · Henrique Carvalho
Quoted 27 lines · Dr. Thomas Orgis

Dear Linux-CIFS maintainer(s),

I stumbled upon a regression in the Linux cifs/smb3 client when working with a smbd using a non-standard port. I am not the first to note this, see

      https://bbs.archlinux.org/viewtopic.php?id=306712

which is a report from mid last year, indicating the problem sometime after Linux 6.6.72. It is a very simple issue, where details of the kernel builds or mount setup don't seem to matter much: Older kernels reconnect to a SMB server that was restarted (old processes killed and replaced), newer kernels do not and just have a defunct mount.

I reproduced this in our HPC cluster environment with such smb.conf on the server side

[global]
security = user
map to guest = Bad Password
server role = standalone server
smb ports = 1445

[public]
path = /some/path
guest ok = yes
read only = yes

Quoted 8 lines

and such a mount command on the client:

mount -t smb3 -o port=1445,user=guest,password=foo //server/public dir

When I kill and re-start smbd on the server, older client kernels reconnect and continue to return listings and files from the share, while newer kernels give this:

My suspicion is that the regression was introduced by:

5713127da855 ("cifs: update dstaddr whenever channel iface is updated")

That change causes parse_server_interfaces() -- should this be running without multichannel mount option? -- to overwrite the port stored in server->dstaddr with CIFS_PORT.

Quoted 8 lines

The attached patch preserves the existing port from server->dstaddr.

Note that I have not yet tested this patch or confirmed the regression with a bisect. If you can't, I will try to do that tomorrow.

--
Henrique
SUSE Labs

Hi Henrique,

AFAIK, the ignoring of port from the results was by design and part of the original code back in 2018:
CIFS: parse and store info on iface queries

Also, the comment in the code just above says why this is so. [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these

I checked this section and it says:
Port (2 bytes): This field MUST NOT be used and MUST be reserved. The server SHOULD set this field to zero, and the client MUST ignore it on receipt.

Quoted 5 lines

Based on the conversations here, it looks like smbd ignores this.

I think the right fix would be to make sure that cifs_chan_update_iface gets called only for secondary channels. That way, it will not get called for single channel scenarios.

Sure, I read the comment in the code and the MS-SMB2 protocol. The protocol states that "client MUST ignore [Port] on receipt". Since we are not using p->Port, I don'se see how this is a protocol violation.

We're using the port that was selected on mount and copied over to server->dstaddr, so that when server->dstaddr is overwridden, server->dstaddr keeps the user selected port.

Now, even if we only fix that for primary channels, the secondary channels will still get the wrong port when they are overwridden, no? So I don't see how that fixes the issue.

Apologies if I'm missing something.

Best regards,

Signature · 2 lines
Henrique
SUSE Labs
#8 lore raw
Quoted 75 lines · Henrique Carvalho
Quoted 73 lines · Shyam Prasad N
Quoted 46 lines · Henrique Carvalho
Quoted 27 lines · Dr. Thomas Orgis

Dear Linux-CIFS maintainer(s),

I stumbled upon a regression in the Linux cifs/smb3 client when working with a smbd using a non-standard port. I am not the first to note this, see

      https://bbs.archlinux.org/viewtopic.php?id=306712

which is a report from mid last year, indicating the problem sometime after Linux 6.6.72. It is a very simple issue, where details of the kernel builds or mount setup don't seem to matter much: Older kernels reconnect to a SMB server that was restarted (old processes killed and replaced), newer kernels do not and just have a defunct mount.

I reproduced this in our HPC cluster environment with such smb.conf on the server side

[global]
security = user
map to guest = Bad Password
server role = standalone server
smb ports = 1445

[public]
path = /some/path
guest ok = yes
read only = yes

Quoted 8 lines

and such a mount command on the client:

mount -t smb3 -o port=1445,user=guest,password=foo //server/public dir

When I kill and re-start smbd on the server, older client kernels reconnect and continue to return listings and files from the share, while newer kernels give this:

My suspicion is that the regression was introduced by:

5713127da855 ("cifs: update dstaddr whenever channel iface is updated")

That change causes parse_server_interfaces() -- should this be running without multichannel mount option? -- to overwrite the port stored in server->dstaddr with CIFS_PORT.

Quoted 8 lines

The attached patch preserves the existing port from server->dstaddr.

Note that I have not yet tested this patch or confirmed the regression with a bisect. If you can't, I will try to do that tomorrow.

--
Henrique
SUSE Labs

Hi Henrique,

AFAIK, the ignoring of port from the results was by design and part of the original code back in 2018:
CIFS: parse and store info on iface queries

Also, the comment in the code just above says why this is so. [MS-SMB2] 2.2.32.5.1.1 Clients MUST ignore these

I checked this section and it says:
Port (2 bytes): This field MUST NOT be used and MUST be reserved. The server SHOULD set this field to zero, and the client MUST ignore it on receipt.

Based on the conversations here, it looks like smbd ignores this.

Quoted 7 lines
Quoted 3 lines

I think the right fix would be to make sure that cifs_chan_update_iface gets called only for secondary channels. That way, it will not get called for single channel scenarios.

Sure, I read the comment in the code and the MS-SMB2 protocol. The protocol states that "client MUST ignore [Port] on receipt". Since we are not using p->Port, I don't see how this is a protocol violation.

Agree. Looks harmless

Quoted 16 lines

We're using the port that was selected on mount and copied over to server->dstaddr, so that when server->dstaddr is overwridden, server->dstaddr keeps the user selected port.

Now, even if we only fix that for primary channels, the secondary channels will still get the wrong port when they are overwridden, no? So I don't see how that fixes the issue.

Apologies if I'm missing something.

Best regards,

--
Henrique
SUSE Labs

Signature · 3 lines
Thanks,

Steve
#9 lore raw
In reply to Henrique Carvalho
Quoted 9 lines · Henrique Carvalho

Sure, I read the comment in the code and the MS-SMB2 protocol. The protocol states that "client MUST ignore [Port] on receipt". Since we are not using p->Port, I don'se see how this is a protocol violation.

We're using the port that was selected on mount and copied over to server->dstaddr, so that when server->dstaddr is overwridden, server->dstaddr keeps the user selected port.

Quoted 5 lines

Now, even if we only fix that for primary channels, the secondary channels will still get the wrong port when they are overwridden, no? So I don't see how that fixes the issue.

Apologies if I'm missing something.

Lo! What happened to this? I saw that Henrique posted "smb: client:
preserve destination port when parsing server interfaces" a month ago at
https://lore.kernel.org/all/[email protected]/
which looks like a fix[1] for this regression, but unless I'm missing something (which very well might be the case) it still is waiting for review, as I can't see it in -next.

Ciao, Thorsten

[1] not totally sure, lacks a reported-by and link or closes tag pointing to the report. A stable tag would also be great to ensure the fix is backported.

#10 lore raw
Quoted 14 lines · Thorsten Leemhuis
Quoted 13 lines · Henrique Carvalho

Sure, I read the comment in the code and the MS-SMB2 protocol. The protocol states that "client MUST ignore [Port] on receipt". Since we are not using p->Port, I don'se see how this is a protocol violation.

We're using the port that was selected on mount and copied over to server->dstaddr, so that when server->dstaddr is overwridden, server->dstaddr keeps the user selected port.

Now, even if we only fix that for primary channels, the secondary channels will still get the wrong port when they are overwridden, no? So I don't see how that fixes the issue.

Quoted 6 lines
Quoted 1 line

Apologies if I'm missing something.

Lo! What happened to this? I saw that Henrique posted "smb: client:
preserve destination port when parsing server interfaces" a month ago at
https://lore.kernel.org/all/[email protected]/
which looks like a fix[1] for this regression, but unless I'm missing

That patch was updated. PATCH v3 was the one that made to the tree.

See commit d4c7210d2f3ea481a6481f03040a64d9077a6172 ("smb: client: fix iface port assignment in parse_server_interfaces").

Best,

Signature · 2 lines
Henrique
SUSE Labs