grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] tcp: Fix TCP port number reused on reboot
@ 2025-07-11  9:19 Michael Chang via Grub-devel
  0 siblings, 0 replies; 3+ messages in thread
From: Michael Chang via Grub-devel @ 2025-07-11  9:19 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Michael Chang, Enno Gotthold, Michal Suchanek, Avnish Chouhan

GRUB's TCP stack assigns source ports for outgoing connections starting
at 21550 and increments sequentially by 1 (e.g., 21550, 21551, ...).
While this generally works, it can lead to failures if the system
reboots rapidly and reuses the same source port too soon.

This issue was observed on powerpc-ieee1275 platforms using CAS (Client
Architecture Support) reboot. In such cases, loading the initrd over
HTTP may fail with connection timeouts. Packet captures show the failed
connections are flagged as "TCP Port Number Reused" by Wireshark.

The root cause is that GRUB reuses the same port shortly after reboot,
while the server may still be tracking the previous connection in
TIME_WAIT. This can result in the server rejecting the connection
attempt or responding with a stale ACK or RST, leading to handshake
failure.

This patch fixes the issue by introducing a time based source port
selection strategy. Instead of always starting from port 21550, GRUB now
computes an initial base port based on the current RTC time, divided
into 5 minute windows. The purpose of this time based strategy is to
ensure that GRUB avoids reusing the same source port within a 5 minute
window, thereby preventing collisions with stale server side connection
tracking that could interfere with a new TCP handshake.

A step size of 8 ensures that the same port will not be reused across
reboots unless GRUB opens more than 8 TCP connections per second on
average, something that is highly unlikely. In typical usage, a GRUB
boot cycle lasts about 15 seconds and may open fewer than 100
connections total, well below the reuse threshold. This makes the
approach robust against short reboot intervals while keeping the logic
simple and deterministic.

Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/net/tcp.c | 39 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
index 93dee0caa..d0cc602dc 100644
--- a/grub-core/net/tcp.c
+++ b/grub-core/net/tcp.c
@@ -22,6 +22,7 @@
 #include <grub/net/netbuff.h>
 #include <grub/time.h>
 #include <grub/priority_queue.h>
+#include <grub/datetime.h>
 
 #define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
 #define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
@@ -552,6 +553,36 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
   return GRUB_ERR_NONE;
 }
 
+/*
+ * Derive a time-based source port to avoid reusing the same port across
+ * reboots. This helps prevent failures caused by server side TCP state (e.g.
+ * TIME_WAIT) from interfering with new connections using the same socket.
+ *
+ * The base port starts at 21550 and increments every second by 8 across a 5
+ * minute window (300 seconds), giving 2400 possible distinct base ports per
+ * window. In typical GRUB usage, the number of connections per boot is small,
+ * so reuse is effectively avoided.
+ */
+static grub_uint16_t
+get_initial_base_port (void)
+{
+  grub_err_t err;
+  struct grub_datetime date;
+  grub_int64_t t = 0;
+  grub_uint64_t r = 0;
+
+  err = grub_get_datetime (&date);
+  if (err != GRUB_ERR_NONE || !grub_datetime2unixtime (&date, &t))
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 21550;
+    }
+
+  grub_divmod64 (t, 300, &r);
+
+  return 21550 + (r << 3);
+}
+
 grub_net_tcp_socket_t
 grub_net_tcp_open (char *server,
 		   grub_uint16_t out_port,
@@ -569,13 +600,19 @@ grub_net_tcp_open (char *server,
   struct grub_net_network_level_interface *inf;
   grub_net_network_level_address_t gateway;
   grub_net_tcp_socket_t socket;
-  static grub_uint16_t in_port = 21550;
+  static grub_uint16_t in_port;
   struct grub_net_buff *nb;
   struct tcphdr *tcph;
   int i;
   grub_uint8_t *nbd;
   grub_net_link_level_address_t ll_target_addr;
 
+  if (!in_port)
+    {
+      in_port = get_initial_base_port ();
+      grub_dprintf ("net", "base port: %d\n", in_port);
+    }
+
   err = grub_net_resolve_address (server, &addr);
   if (err)
     return NULL;
-- 
2.50.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2] tcp: Fix TCP port number reused on reboot
@ 2025-09-02  6:58 Michael Chang via Grub-devel
  2025-09-04 17:17 ` Daniel Kiper
  0 siblings, 1 reply; 3+ messages in thread
From: Michael Chang via Grub-devel @ 2025-09-02  6:58 UTC (permalink / raw)
  To: The development of GNU GRUB
  Cc: Michael Chang, Enno Gotthold, Michal Suchanek, Avnish Chouhan,
	Sudhakar Kuppusamy

GRUB's TCP stack assigns source ports for outgoing connections starting
at 21550 and increments sequentially by 1 (e.g., 21550, 21551, ...).
While this generally works, it can lead to failures if the system
reboots rapidly and reuses the same source port too soon.

This issue was observed on powerpc-ieee1275 platforms using CAS (Client
Architecture Support) reboot. In such cases, loading the initrd over
HTTP may fail with connection timeouts. Packet captures show the failed
connections are flagged as "TCP Port Number Reused" by Wireshark.

The root cause is that GRUB reuses the same port shortly after reboot,
while the server may still be tracking the previous connection in
TIME_WAIT. This can result in the server rejecting the connection
attempt or responding with a stale ACK or RST, leading to handshake
failure.

This patch fixes the issue by introducing a time based source port
selection strategy. Instead of always starting from port 21550, GRUB now
computes an initial base port based on the current RTC time, divided
into 5 minute windows. The purpose of this time based strategy is to
ensure that GRUB avoids reusing the same source port within a 5 minute
window, thereby preventing collisions with stale server side connection
tracking that could interfere with a new TCP handshake.

A step size of 8 ensures that the same port will not be reused across
reboots unless GRUB opens more than 8 TCP connections per second on
average, something that is highly unlikely. In typical usage, a GRUB
boot cycle lasts about 15 seconds and may open fewer than 100
connections total, well below the reuse threshold. This makes the
approach robust against short reboot intervals while keeping the logic
simple and deterministic.

Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
 grub-core/net/tcp.c | 39 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 38 insertions(+), 1 deletion(-)

diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
index 93dee0caa..d0cc602dc 100644
--- a/grub-core/net/tcp.c
+++ b/grub-core/net/tcp.c
@@ -22,6 +22,7 @@
 #include <grub/net/netbuff.h>
 #include <grub/time.h>
 #include <grub/priority_queue.h>
+#include <grub/datetime.h>
 
 #define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
 #define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
@@ -552,6 +553,36 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
   return GRUB_ERR_NONE;
 }
 
+/*
+ * Derive a time-based source port to avoid reusing the same port across
+ * reboots. This helps prevent failures caused by server side TCP state (e.g.
+ * TIME_WAIT) from interfering with new connections using the same socket.
+ *
+ * The base port starts at 21550 and increments every second by 8 across a 5
+ * minute window (300 seconds), giving 2400 possible distinct base ports per
+ * window. In typical GRUB usage, the number of connections per boot is small,
+ * so reuse is effectively avoided.
+ */
+static grub_uint16_t
+get_initial_base_port (void)
+{
+  grub_err_t err;
+  struct grub_datetime date;
+  grub_int64_t t = 0;
+  grub_uint64_t r = 0;
+
+  err = grub_get_datetime (&date);
+  if (err != GRUB_ERR_NONE || !grub_datetime2unixtime (&date, &t))
+    {
+      grub_errno = GRUB_ERR_NONE;
+      return 21550;
+    }
+
+  grub_divmod64 (t, 300, &r);
+
+  return 21550 + (r << 3);
+}
+
 grub_net_tcp_socket_t
 grub_net_tcp_open (char *server,
 		   grub_uint16_t out_port,
@@ -569,13 +600,19 @@ grub_net_tcp_open (char *server,
   struct grub_net_network_level_interface *inf;
   grub_net_network_level_address_t gateway;
   grub_net_tcp_socket_t socket;
-  static grub_uint16_t in_port = 21550;
+  static grub_uint16_t in_port;
   struct grub_net_buff *nb;
   struct tcphdr *tcph;
   int i;
   grub_uint8_t *nbd;
   grub_net_link_level_address_t ll_target_addr;
 
+  if (!in_port)
+    {
+      in_port = get_initial_base_port ();
+      grub_dprintf ("net", "base port: %d\n", in_port);
+    }
+
   err = grub_net_resolve_address (server, &addr);
   if (err)
     return NULL;
-- 
2.50.1


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH v2] tcp: Fix TCP port number reused on reboot
  2025-09-02  6:58 [PATCH v2] tcp: Fix TCP port number reused on reboot Michael Chang via Grub-devel
@ 2025-09-04 17:17 ` Daniel Kiper
  0 siblings, 0 replies; 3+ messages in thread
From: Daniel Kiper @ 2025-09-04 17:17 UTC (permalink / raw)
  To: Michael Chang
  Cc: grub-devel, Enno Gotthold, Michal Suchanek, Avnish Chouhan,
	Sudhakar Kuppusamy

On Tue, Sep 02, 2025 at 02:58:50PM +0800, Michael Chang via Grub-devel wrote:
> GRUB's TCP stack assigns source ports for outgoing connections starting
> at 21550 and increments sequentially by 1 (e.g., 21550, 21551, ...).
> While this generally works, it can lead to failures if the system
> reboots rapidly and reuses the same source port too soon.
>
> This issue was observed on powerpc-ieee1275 platforms using CAS (Client
> Architecture Support) reboot. In such cases, loading the initrd over
> HTTP may fail with connection timeouts. Packet captures show the failed
> connections are flagged as "TCP Port Number Reused" by Wireshark.
>
> The root cause is that GRUB reuses the same port shortly after reboot,
> while the server may still be tracking the previous connection in
> TIME_WAIT. This can result in the server rejecting the connection
> attempt or responding with a stale ACK or RST, leading to handshake
> failure.
>
> This patch fixes the issue by introducing a time based source port
> selection strategy. Instead of always starting from port 21550, GRUB now
> computes an initial base port based on the current RTC time, divided
> into 5 minute windows. The purpose of this time based strategy is to
> ensure that GRUB avoids reusing the same source port within a 5 minute
> window, thereby preventing collisions with stale server side connection
> tracking that could interfere with a new TCP handshake.
>
> A step size of 8 ensures that the same port will not be reused across
> reboots unless GRUB opens more than 8 TCP connections per second on
> average, something that is highly unlikely. In typical usage, a GRUB
> boot cycle lasts about 15 seconds and may open fewer than 100
> connections total, well below the reuse threshold. This makes the
> approach robust against short reboot intervals while keeping the logic
> simple and deterministic.
>
> Signed-off-by: Michael Chang <mchang@suse.com>
> Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>

Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>

Daniel

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2025-09-04 17:18 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-02  6:58 [PATCH v2] tcp: Fix TCP port number reused on reboot Michael Chang via Grub-devel
2025-09-04 17:17 ` Daniel Kiper
  -- strict thread matches above, loose matches on Subject: below --
2025-07-11  9:19 Michael Chang via Grub-devel

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).