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 <saloni.kasbekar@intel.com> Cc: Zachary Clark-williams <zachary.clark-williams@intel.com> Signed-off-by: Doug Flick [MSFT] <doug.edk2@gmail.com> Reviewed-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
This commit is contained in:
@@ -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,
|
||||
|
Reference in New Issue
Block a user