From 6f0cf9f14b1abefa62416c1611f01d6fb3353c44 Mon Sep 17 00:00:00 2001 From: Jon Maloy Date: Tue, 11 Jun 2024 15:20:29 -0400 Subject: [PATCH 2/8] NetworkPkg TcpDxe: SECURITY PATCH CVE-2023-45236 RH-Author: Jon Maloy RH-MergeRequest: 75: NetworkPkg: SECURITY PATCH CVE-2023-45236 and CVE-2023-45237 RH-Jira: RHEL-40270 RHEL-40272 RH-Acked-by: Gerd Hoffmann RH-Commit: [2/8] 18e88b5def6b058ecd4ffa565ef6f3bafe6f03ad JIRA: https://issues.redhat.com/browse/RHEL-40272 Upstream: Merged CVE: CVE-2023-45236 commit 1904a64bcc18199738e5be183d28887ac5d837d7 Author: Doug Flick Date: Wed May 8 22:56:29 2024 -0700 NetworkPkg TcpDxe: SECURITY PATCH CVE-2023-45236 REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4541 REF: https://www.rfc-editor.org/rfc/rfc1948.txt REF: https://www.rfc-editor.org/rfc/rfc6528.txt REF: https://www.rfc-editor.org/rfc/rfc9293.txt Bug Overview: PixieFail Bug #8 CVE-2023-45236 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N CWE-200 Exposure of Sensitive Information to an Unauthorized Actor Updates TCP ISN generation to use a cryptographic hash of the connection's identifying parameters and a secret key. This prevents an attacker from guessing the ISN used for some other connection. This is follows the guidance in RFC 1948, RFC 6528, and RFC 9293. RFC: 9293 Section 3.4.1. Initial Sequence Number Selection A TCP implementation MUST use the above type of "clock" for clock- driven selection of initial sequence numbers (MUST-8), and SHOULD generate its initial sequence numbers with the expression: ISN = M + F(localip, localport, remoteip, remoteport, secretkey) where M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the connection's identifying parameters ("localip, localport, remoteip, remoteport") and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the outside (MUST-9), or an attacker could still guess at sequence numbers from the ISN used for some other connection. The PRF could be implemented as a cryptographic hash of the concatenation of the TCP connection parameters and some secret data. For discussion of the selection of a specific hash algorithm and management of the secret key data, please see Section 3 of [42]. For each connection there is a send sequence number and a receive sequence number. The initial send sequence number (ISS) is chosen by the data sending TCP peer, and the initial receive sequence number (IRS) is learned during the connection-establishing procedure. For a connection to be established or initialized, the two TCP peers must synchronize on each other's initial sequence numbers. This is done in an exchange of connection-establishing segments carrying a control bit called "SYN" (for synchronize) and the initial sequence numbers. As a shorthand, segments carrying the SYN bit are also called "SYNs". Hence, the solution requires a suitable mechanism for picking an initial sequence number and a slightly involved handshake to exchange the ISNs. Cc: Saloni Kasbekar Cc: Zachary Clark-williams Signed-off-by: Doug Flick [MSFT] Reviewed-by: Saloni Kasbekar --- NetworkPkg/SecurityFixes.yaml | 22 +++ NetworkPkg/TcpDxe/TcpDriver.c | 92 ++++++++++++- NetworkPkg/TcpDxe/TcpDxe.inf | 8 +- NetworkPkg/TcpDxe/TcpFunc.h | 23 ++-- NetworkPkg/TcpDxe/TcpInput.c | 13 +- NetworkPkg/TcpDxe/TcpMain.h | 59 ++++++-- NetworkPkg/TcpDxe/TcpMisc.c | 244 ++++++++++++++++++++++++++++++++-- NetworkPkg/TcpDxe/TcpTimer.c | 3 +- 8 files changed, 415 insertions(+), 49 deletions(-) diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml index 20a4555019..4305328425 100644 --- a/NetworkPkg/SecurityFixes.yaml +++ b/NetworkPkg/SecurityFixes.yaml @@ -122,6 +122,28 @@ CVE_2023_45235: - http://www.openwall.com/lists/oss-security/2024/01/16/2 - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html +CVE_2023_45236: + commit_titles: + - "NetworkPkg: TcpDxe: SECURITY PATCH CVE-2023-45236 Patch" + cve: CVE-2023-45236 + date_reported: 2023-08-28 13:56 UTC + description: "Bug 08 - edk2/NetworkPkg: Predictable TCP Initial Sequence Numbers" + note: + files_impacted: + - NetworkPkg/Include/Library/NetLib.h + - NetworkPkg/TcpDxe/TcpDriver.c + - NetworkPkg/TcpDxe/TcpDxe.inf + - NetworkPkg/TcpDxe/TcpFunc.h + - NetworkPkg/TcpDxe/TcpInput.c + - NetworkPkg/TcpDxe/TcpMain.h + - NetworkPkg/TcpDxe/TcpMisc.c + - NetworkPkg/TcpDxe/TcpTimer.c + links: + - https://bugzilla.tianocore.org/show_bug.cgi?id=4541 + - https://nvd.nist.gov/vuln/detail/CVE-2023-45236 + - http://www.openwall.com/lists/oss-security/2024/01/16/2 + - http://packetstormsecurity.com/files/176574/PixieFail-Proof-Of-Concepts.html + - https://blog.quarkslab.com/pixiefail-nine-vulnerabilities-in-tianocores-edk-ii-ipv6-network-stack.html CVE_2023_45237: commit_titles: - "NetworkPkg:: SECURITY PATCH CVE 2023-45237" diff --git a/NetworkPkg/TcpDxe/TcpDriver.c b/NetworkPkg/TcpDxe/TcpDriver.c index 8fe6badd68..40bba4080c 100644 --- a/NetworkPkg/TcpDxe/TcpDriver.c +++ b/NetworkPkg/TcpDxe/TcpDriver.c @@ -83,6 +83,12 @@ EFI_SERVICE_BINDING_PROTOCOL gTcpServiceBinding = { TcpServiceBindingDestroyChild }; +// +// This is the handle for the Hash2ServiceBinding Protocol instance this driver produces +// if the platform does not provide one. +// +EFI_HANDLE mHash2ServiceHandle = NULL; + /** Create and start the heartbeat timer for the TCP driver. @@ -165,6 +171,23 @@ TcpDriverEntryPoint ( EFI_STATUS Status; UINT32 Random; + // + // Initialize the Secret used for hashing TCP sequence numbers + // + // Normally this should be regenerated periodically, but since + // this is only used for UEFI networking and not a general purpose + // operating system, it is not necessary to regenerate it. + // + Status = PseudoRandomU32 (&mTcpGlobalSecret); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); + return Status; + } + + // + // Get a random number used to generate a random port number + // Intentionally not linking this to mTcpGlobalSecret to avoid leaking information about the secret + // Status = PseudoRandomU32 (&Random); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "%a Failed to generate random number: %r\n", __func__, Status)); @@ -207,9 +230,8 @@ TcpDriverEntryPoint ( } // - // Initialize ISS and random port. + // Initialize the random port. // - mTcpGlobalIss = Random % mTcpGlobalIss; mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (Random % TCP_PORT_KNOWN)); mTcp6RandomPort = mTcp4RandomPort; @@ -224,6 +246,8 @@ TcpDriverEntryPoint ( @param[in] IpVersion IP_VERSION_4 or IP_VERSION_6. @retval EFI_OUT_OF_RESOURCES Failed to allocate some resources. + @retval EFI_UNSUPPORTED Service Binding Protocols are unavailable. + @retval EFI_ALREADY_STARTED The TCP driver is already started on the controller. @retval EFI_SUCCESS A new IP6 service binding private was created. **/ @@ -234,11 +258,13 @@ TcpCreateService ( IN UINT8 IpVersion ) { - EFI_STATUS Status; - EFI_GUID *IpServiceBindingGuid; - EFI_GUID *TcpServiceBindingGuid; - TCP_SERVICE_DATA *TcpServiceData; - IP_IO_OPEN_DATA OpenData; + EFI_STATUS Status; + EFI_GUID *IpServiceBindingGuid; + EFI_GUID *TcpServiceBindingGuid; + TCP_SERVICE_DATA *TcpServiceData; + IP_IO_OPEN_DATA OpenData; + EFI_SERVICE_BINDING_PROTOCOL *Hash2ServiceBinding; + EFI_HASH2_PROTOCOL *Hash2Protocol; if (IpVersion == IP_VERSION_4) { IpServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid; @@ -272,6 +298,33 @@ TcpCreateService ( return EFI_UNSUPPORTED; } + Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol); + if (EFI_ERROR (Status)) { + // + // If we can't find the Hashing protocol, then we need to create one. + // + + // + // Platform is expected to publish the hash service binding protocol to support TCP. + // + Status = gBS->LocateProtocol ( + &gEfiHash2ServiceBindingProtocolGuid, + NULL, + (VOID **)&Hash2ServiceBinding + ); + if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->CreateChild == NULL)) { + return EFI_UNSUPPORTED; + } + + // + // Create an instance of the hash protocol for this controller. + // + Status = Hash2ServiceBinding->CreateChild (Hash2ServiceBinding, &mHash2ServiceHandle); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + } + // // Create the TCP service data. // @@ -423,6 +476,7 @@ TcpDestroyService ( EFI_STATUS Status; LIST_ENTRY *List; TCP_DESTROY_CHILD_IN_HANDLE_BUF_CONTEXT Context; + EFI_SERVICE_BINDING_PROTOCOL *Hash2ServiceBinding; ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6)); @@ -439,6 +493,30 @@ TcpDestroyService ( return EFI_SUCCESS; } + // + // Destroy the Hash2ServiceBinding instance if it is created by Tcp driver. + // + if (mHash2ServiceHandle != NULL) { + Status = gBS->LocateProtocol ( + &gEfiHash2ServiceBindingProtocolGuid, + NULL, + (VOID **)&Hash2ServiceBinding + ); + if (EFI_ERROR (Status) || (Hash2ServiceBinding == NULL) || (Hash2ServiceBinding->DestroyChild == NULL)) { + return EFI_UNSUPPORTED; + } + + // + // Destroy the instance of the hashing protocol for this controller. + // + Status = Hash2ServiceBinding->DestroyChild (Hash2ServiceBinding, &mHash2ServiceHandle); + if (EFI_ERROR (Status)) { + return EFI_UNSUPPORTED; + } + + mHash2ServiceHandle = NULL; + } + Status = gBS->OpenProtocol ( NicHandle, ServiceBindingGuid, diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf index cf5423f4c5..76de4cf9ec 100644 --- a/NetworkPkg/TcpDxe/TcpDxe.inf +++ b/NetworkPkg/TcpDxe/TcpDxe.inf @@ -6,6 +6,7 @@ # stack has been loaded in system. This driver supports both IPv4 and IPv6 network stack. # # Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
+# Copyright (c) Microsoft Corporation # # SPDX-License-Identifier: BSD-2-Clause-Patent # @@ -68,7 +69,6 @@ NetLib IpIoLib - [Protocols] ## SOMETIMES_CONSUMES ## SOMETIMES_PRODUCES @@ -81,6 +81,12 @@ gEfiIp6ServiceBindingProtocolGuid ## TO_START gEfiTcp6ProtocolGuid ## BY_START gEfiTcp6ServiceBindingProtocolGuid ## BY_START + gEfiHash2ProtocolGuid ## BY_START + gEfiHash2ServiceBindingProtocolGuid ## BY_START + +[Guids] + gEfiHashAlgorithmMD5Guid ## CONSUMES + gEfiHashAlgorithmSha256Guid ## CONSUMES [Depex] gEfiHash2ServiceBindingProtocolGuid diff --git a/NetworkPkg/TcpDxe/TcpFunc.h b/NetworkPkg/TcpDxe/TcpFunc.h index a7af01fff2..c707bee3e5 100644 --- a/NetworkPkg/TcpDxe/TcpFunc.h +++ b/NetworkPkg/TcpDxe/TcpFunc.h @@ -2,7 +2,7 @@ Declaration of external functions shared in TCP driver. Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.
- + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -36,8 +36,11 @@ VOID @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + @retval EFI_SUCCESS The operation completed successfully + @retval others The underlying functions failed and could not complete the operation + **/ -VOID +EFI_STATUS TcpInitTcbLocal ( IN OUT TCP_CB *Tcb ); @@ -128,17 +131,6 @@ TcpCloneTcb ( IN TCP_CB *Tcb ); -/** - Compute an ISS to be used by a new connection. - - @return The result ISS. - -**/ -TCP_SEQNO -TcpGetIss ( - VOID - ); - /** Get the local mss. @@ -202,8 +194,11 @@ TcpFormatNetbuf ( @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a connection. + @retval EFI_SUCCESS The operation completed successfully + @retval others The underlying functions failed and could not complete the operation + **/ -VOID +EFI_STATUS TcpOnAppConnect ( IN OUT TCP_CB *Tcb ); diff --git a/NetworkPkg/TcpDxe/TcpInput.c b/NetworkPkg/TcpDxe/TcpInput.c index 7b329be64d..86dd7c4907 100644 --- a/NetworkPkg/TcpDxe/TcpInput.c +++ b/NetworkPkg/TcpDxe/TcpInput.c @@ -724,6 +724,7 @@ TcpInput ( TCP_SEQNO Urg; UINT16 Checksum; INT32 Usable; + EFI_STATUS Status; ASSERT ((Version == IP_VERSION_4) || (Version == IP_VERSION_6)); @@ -872,7 +873,17 @@ TcpInput ( Tcb->LocalEnd.Port = Head->DstPort; Tcb->RemoteEnd.Port = Head->SrcPort; - TcpInitTcbLocal (Tcb); + Status = TcpInitTcbLocal (Tcb); + if (EFI_ERROR (Status)) { + DEBUG ( + (DEBUG_ERROR, + "TcpInput: discard a segment because failed to init local end for TCB %p\n", + Tcb) + ); + + goto DISCARD; + } + TcpInitTcbPeer (Tcb, Seg, &Option); TcpSetState (Tcb, TCP_SYN_RCVD); diff --git a/NetworkPkg/TcpDxe/TcpMain.h b/NetworkPkg/TcpDxe/TcpMain.h index c0c9b7f46e..4d5566ab93 100644 --- a/NetworkPkg/TcpDxe/TcpMain.h +++ b/NetworkPkg/TcpDxe/TcpMain.h @@ -3,7 +3,7 @@ It is the common head file for all Tcp*.c in TCP driver. Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
- + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -31,7 +32,7 @@ extern EFI_UNICODE_STRING_TABLE *gTcpControllerNameTable; extern LIST_ENTRY mTcpRunQue; extern LIST_ENTRY mTcpListenQue; -extern TCP_SEQNO mTcpGlobalIss; +extern TCP_SEQNO mTcpGlobalSecret; extern UINT32 mTcpTick; /// @@ -45,14 +46,6 @@ extern UINT32 mTcpTick; #define TCP_EXPIRE_TIME 65535 -/// -/// The implementation selects the initial send sequence number and the unit to -/// be added when it is increased. -/// -#define TCP_BASE_ISS 0x4d7e980b -#define TCP_ISS_INCREMENT_1 2048 -#define TCP_ISS_INCREMENT_2 100 - typedef union { EFI_TCP4_CONFIG_DATA Tcp4CfgData; EFI_TCP6_CONFIG_DATA Tcp6CfgData; @@ -774,4 +767,50 @@ Tcp6Poll ( IN EFI_TCP6_PROTOCOL *This ); +/** + Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local + and remote IP addresses and ports. + + This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1 + Where the ISN is computed as follows: + ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret) + + Otherwise: + ISN = M + F(localip, localport, remoteip, remoteport, secretkey) + + "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the + connection's identifying parameters ("localip, localport, remoteip, remoteport") + and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the + outside (MUST-9), or an attacker could still guess at sequence numbers from the + ISN used for some other connection. The PRF could be implemented as a + cryptographic hash of the concatenation of the TCP connection parameters and some + secret data. For discussion of the selection of a specific hash algorithm and + management of the secret key data." + + @param[in] LocalIp A pointer to the local IP address of the TCP connection. + @param[in] LocalIpSize The size, in bytes, of the LocalIp buffer. + @param[in] LocalPort The local port number of the TCP connection. + @param[in] RemoteIp A pointer to the remote IP address of the TCP connection. + @param[in] RemoteIpSize The size, in bytes, of the RemoteIp buffer. + @param[in] RemotePort The remote port number of the TCP connection. + @param[out] Isn A pointer to the variable that will receive the Initial + Sequence Number (ISN). + + @retval EFI_SUCCESS The operation completed successfully, and the ISN was + retrieved. + @retval EFI_INVALID_PARAMETER One or more of the input parameters are invalid. + @retval EFI_UNSUPPORTED The operation is not supported. + +**/ +EFI_STATUS +TcpGetIsn ( + IN UINT8 *LocalIp, + IN UINTN LocalIpSize, + IN UINT16 LocalPort, + IN UINT8 *RemoteIp, + IN UINTN RemoteIpSize, + IN UINT16 RemotePort, + OUT TCP_SEQNO *Isn + ); + #endif diff --git a/NetworkPkg/TcpDxe/TcpMisc.c b/NetworkPkg/TcpDxe/TcpMisc.c index c93212d47d..3310306f63 100644 --- a/NetworkPkg/TcpDxe/TcpMisc.c +++ b/NetworkPkg/TcpDxe/TcpMisc.c @@ -3,7 +3,7 @@ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
- + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -20,7 +20,34 @@ LIST_ENTRY mTcpListenQue = { &mTcpListenQue }; -TCP_SEQNO mTcpGlobalIss = TCP_BASE_ISS; +// +// The Session secret +// This must be initialized to a random value at boot time +// +TCP_SEQNO mTcpGlobalSecret; + +// +// Union to hold either an IPv4 or IPv6 address +// This is used to simplify the ISN hash computation +// +typedef union { + UINT8 IPv4[4]; + UINT8 IPv6[16]; +} NETWORK_ADDRESS; + +// +// The ISN is computed by hashing this structure +// It is initialized with the local and remote IP addresses and ports +// and the secret +// +// +typedef struct { + UINT16 LocalPort; + UINT16 RemotePort; + NETWORK_ADDRESS LocalAddress; + NETWORK_ADDRESS RemoteAddress; + TCP_SEQNO Secret; +} ISN_HASH_CTX; CHAR16 *mTcpStateName[] = { L"TCP_CLOSED", @@ -41,12 +68,18 @@ CHAR16 *mTcpStateName[] = { @param[in, out] Tcb Pointer to the TCP_CB of this TCP instance. + @retval EFI_SUCCESS The operation completed successfully + @retval others The underlying functions failed and could not complete the operation + **/ -VOID +EFI_STATUS TcpInitTcbLocal ( IN OUT TCP_CB *Tcb ) { + TCP_SEQNO Isn; + EFI_STATUS Status; + // // Compute the checksum of the fixed parts of pseudo header // @@ -57,6 +90,16 @@ TcpInitTcbLocal ( 0x06, 0 ); + + Status = TcpGetIsn ( + Tcb->LocalEnd.Ip.v4.Addr, + sizeof (IPv4_ADDRESS), + Tcb->LocalEnd.Port, + Tcb->RemoteEnd.Ip.v4.Addr, + sizeof (IPv4_ADDRESS), + Tcb->RemoteEnd.Port, + &Isn + ); } else { Tcb->HeadSum = NetIp6PseudoHeadChecksum ( &Tcb->LocalEnd.Ip.v6, @@ -64,9 +107,25 @@ TcpInitTcbLocal ( 0x06, 0 ); + + Status = TcpGetIsn ( + Tcb->LocalEnd.Ip.v6.Addr, + sizeof (IPv6_ADDRESS), + Tcb->LocalEnd.Port, + Tcb->RemoteEnd.Ip.v6.Addr, + sizeof (IPv6_ADDRESS), + Tcb->RemoteEnd.Port, + &Isn + ); + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "TcpInitTcbLocal: failed to get isn\n")); + ASSERT (FALSE); + return Status; } - Tcb->Iss = TcpGetIss (); + Tcb->Iss = Isn; Tcb->SndUna = Tcb->Iss; Tcb->SndNxt = Tcb->Iss; @@ -82,6 +141,8 @@ TcpInitTcbLocal ( Tcb->RetxmitSeqMax = 0; Tcb->ProbeTimerOn = FALSE; + + return EFI_SUCCESS; } /** @@ -506,18 +567,162 @@ TcpCloneTcb ( } /** - Compute an ISS to be used by a new connection. - - @return The resulting ISS. + Retrieves the Initial Sequence Number (ISN) for a TCP connection identified by local + and remote IP addresses and ports. + + This method is based on https://datatracker.ietf.org/doc/html/rfc9293#section-3.4.1 + Where the ISN is computed as follows: + ISN = TimeStamp + MD5(LocalIP, LocalPort, RemoteIP, RemotePort, Secret) + + Otherwise: + ISN = M + F(localip, localport, remoteip, remoteport, secretkey) + + "Here M is the 4 microsecond timer, and F() is a pseudorandom function (PRF) of the + connection's identifying parameters ("localip, localport, remoteip, remoteport") + and a secret key ("secretkey") (SHLD-1). F() MUST NOT be computable from the + outside (MUST-9), or an attacker could still guess at sequence numbers from the + ISN used for some other connection. The PRF could be implemented as a + cryptographic hash of the concatenation of the TCP connection parameters and some + secret data. For discussion of the selection of a specific hash algorithm and + management of the secret key data." + + @param[in] LocalIp A pointer to the local IP address of the TCP connection. + @param[in] LocalIpSize The size, in bytes, of the LocalIp buffer. + @param[in] LocalPort The local port number of the TCP connection. + @param[in] RemoteIp A pointer to the remote IP address of the TCP connection. + @param[in] RemoteIpSize The size, in bytes, of the RemoteIp buffer. + @param[in] RemotePort The remote port number of the TCP connection. + @param[out] Isn A pointer to the variable that will receive the Initial + Sequence Number (ISN). + + @retval EFI_SUCCESS The operation completed successfully, and the ISN was + retrieved. + @retval EFI_INVALID_PARAMETER One or more of the input parameters are invalid. + @retval EFI_UNSUPPORTED The operation is not supported. **/ -TCP_SEQNO -TcpGetIss ( - VOID +EFI_STATUS +TcpGetIsn ( + IN UINT8 *LocalIp, + IN UINTN LocalIpSize, + IN UINT16 LocalPort, + IN UINT8 *RemoteIp, + IN UINTN RemoteIpSize, + IN UINT16 RemotePort, + OUT TCP_SEQNO *Isn ) { - mTcpGlobalIss += TCP_ISS_INCREMENT_1; - return mTcpGlobalIss; + EFI_STATUS Status; + EFI_HASH2_PROTOCOL *Hash2Protocol; + EFI_HASH2_OUTPUT HashResult; + ISN_HASH_CTX IsnHashCtx; + EFI_TIME TimeStamp; + + // + // Check that the ISN pointer is valid + // + if (Isn == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The local ip may be a v4 or v6 address and may not be NULL + // + if ((LocalIp == NULL) || (LocalIpSize == 0) || (RemoteIp == NULL) || (RemoteIpSize == 0)) { + return EFI_INVALID_PARAMETER; + } + + // + // the local ip may be a v4 or v6 address + // + if ((LocalIpSize != sizeof (EFI_IPv4_ADDRESS)) && (LocalIpSize != sizeof (EFI_IPv6_ADDRESS))) { + return EFI_INVALID_PARAMETER; + } + + // + // Locate the Hash Protocol + // + Status = gBS->LocateProtocol (&gEfiHash2ProtocolGuid, NULL, (VOID **)&Hash2Protocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_NET, "Failed to locate Hash Protocol: %r\n", Status)); + + // + // TcpCreateService(..) is expected to be called prior to this function + // + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // Initialize the hash algorithm + // + Status = Hash2Protocol->HashInit (Hash2Protocol, &gEfiHashAlgorithmSha256Guid); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_NET, "Failed to initialize sha256 hash algorithm: %r\n", Status)); + return Status; + } + + IsnHashCtx.LocalPort = LocalPort; + IsnHashCtx.RemotePort = RemotePort; + IsnHashCtx.Secret = mTcpGlobalSecret; + + // + // Check the IP address family and copy accordingly + // + if (LocalIpSize == sizeof (EFI_IPv4_ADDRESS)) { + CopyMem (&IsnHashCtx.LocalAddress.IPv4, LocalIp, LocalIpSize); + } else if (LocalIpSize == sizeof (EFI_IPv6_ADDRESS)) { + CopyMem (&IsnHashCtx.LocalAddress.IPv6, LocalIp, LocalIpSize); + } else { + return EFI_INVALID_PARAMETER; // Unsupported address size + } + + // + // Repeat the process for the remote IP address + // + if (RemoteIpSize == sizeof (EFI_IPv4_ADDRESS)) { + CopyMem (&IsnHashCtx.RemoteAddress.IPv4, RemoteIp, RemoteIpSize); + } else if (RemoteIpSize == sizeof (EFI_IPv6_ADDRESS)) { + CopyMem (&IsnHashCtx.RemoteAddress.IPv6, RemoteIp, RemoteIpSize); + } else { + return EFI_INVALID_PARAMETER; // Unsupported address size + } + + // + // Compute the hash + // Update the hash with the data + // + Status = Hash2Protocol->HashUpdate (Hash2Protocol, (UINT8 *)&IsnHashCtx, sizeof (IsnHashCtx)); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_NET, "Failed to update hash: %r\n", Status)); + return Status; + } + + // + // Finalize the hash and retrieve the result + // + Status = Hash2Protocol->HashFinal (Hash2Protocol, &HashResult); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_NET, "Failed to finalize hash: %r\n", Status)); + return Status; + } + + Status = gRT->GetTime (&TimeStamp, NULL); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // copy the first 4 bytes of the hash result into the ISN + // + CopyMem (Isn, HashResult.Md5Hash, sizeof (*Isn)); + + // + // now add the timestamp to the ISN as 4 microseconds units (1000 / 4 = 250) + // + *Isn += (TCP_SEQNO)TimeStamp.Nanosecond * 250; + + return Status; } /** @@ -721,17 +926,28 @@ TcpFormatNetbuf ( @param[in, out] Tcb Pointer to the TCP_CB that wants to initiate a connection. + @retval EFI_SUCCESS The operation completed successfully + @retval others The underlying functions failed and could not complete the operation + **/ -VOID +EFI_STATUS TcpOnAppConnect ( IN OUT TCP_CB *Tcb ) { - TcpInitTcbLocal (Tcb); + EFI_STATUS Status; + + Status = TcpInitTcbLocal (Tcb); + if (EFI_ERROR (Status)) { + return Status; + } + TcpSetState (Tcb, TCP_SYN_SENT); TcpSetTimer (Tcb, TCP_TIMER_CONNECT, Tcb->ConnectTimeout); TcpToSendData (Tcb, 1); + + return EFI_SUCCESS; } /** diff --git a/NetworkPkg/TcpDxe/TcpTimer.c b/NetworkPkg/TcpDxe/TcpTimer.c index 5d2e124977..065b1bdf5f 100644 --- a/NetworkPkg/TcpDxe/TcpTimer.c +++ b/NetworkPkg/TcpDxe/TcpTimer.c @@ -2,7 +2,7 @@ TCP timer related functions. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
- + Copyright (c) Microsoft Corporation SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -483,7 +483,6 @@ TcpTickingDpc ( INT16 Index; mTcpTick++; - mTcpGlobalIss += TCP_ISS_INCREMENT_2; // // Don't use LIST_FOR_EACH, which isn't delete safe. -- 2.39.3