From 506636cbbd3aa22405c69f76ea4d4e0bac560b4a Mon Sep 17 00:00:00 2001 From: hy <12444214+dhjgty@user.noreply.gitee.com> Date: Sun, 23 Feb 2025 20:01:46 +0800 Subject: [PATCH 1/5] =?UTF-8?q?Fixes=20CVE-2024-13176=E3=80=81CVE-2024-474?= =?UTF-8?q?1=E3=80=81CVE-2023-5363?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...x-timing-side-channel-CVE-2024-13176.patch | 121 ++++++++++++++++++ ...-Free-the-read-buffers-CVE-2024-4741.patch | 70 ++++++++++ 0085-Process-key-length-CVE-2023-5363.patch | 79 ++++++++++++ edk2.spec | 10 +- 4 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 0083-Fix-timing-side-channel-CVE-2024-13176.patch create mode 100644 0084-Free-the-read-buffers-CVE-2024-4741.patch create mode 100644 0085-Process-key-length-CVE-2023-5363.patch diff --git a/0083-Fix-timing-side-channel-CVE-2024-13176.patch b/0083-Fix-timing-side-channel-CVE-2024-13176.patch new file mode 100644 index 0000000..ba4b482 --- /dev/null +++ b/0083-Fix-timing-side-channel-CVE-2024-13176.patch @@ -0,0 +1,121 @@ +From ccdf50988462e9889f3553cbefbe81bba3e41e1f Mon Sep 17 00:00:00 2001 +From: hy <12444214+dhjgty@user.noreply.gitee.com> +Date: Tue, 25 Feb 2025 23:29:26 +0800 +Subject: [PATCH] Fix timing side-channel in ECDSA signature computation +There is a timing signal of around 300 nanoseconds when the top word of +the inverted ECDSA nonce value is zero. This can happen with significant +probability only for some of the supported elliptic curves. In particular +the NIST P-521 curve is affected. To be able to measure this leak, the +attacker process must either be located in the same physical computer or +must have a very fast network connection with low latency. + +Attacks on ECDSA nonce are also known as Minerva attack. + +Fixes CVE-2024-13176 + +Reviewed-by: Tim Hudson +Reviewed-by: Neil Horman +Reviewed-by: Paul Dale + +--- + .../OpensslLib/openssl/crypto/bn/bn_exp.c | 21 +++++++++++++------ + .../OpensslLib/openssl/crypto/ec/ec_lib.c | 7 ++++--- + .../OpensslLib/openssl/include/crypto/bn.h | 3 +++ + 3 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c +index 4e169ae1..a161e580 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_exp.c +@@ -598,7 +598,7 @@ static int MOD_EXP_CTIME_COPY_FROM_PREBUF(BIGNUM *b, int top, + * out by Colin Percival, + * http://www.daemonology.net/hyperthreading-considered-harmful/) + */ +-int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, ++int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *in_mont) + { +@@ -615,10 +615,6 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + unsigned int t4 = 0; + #endif + +- bn_check_top(a); +- bn_check_top(p); +- bn_check_top(m); +- + if (!BN_is_odd(m)) { + ERR_raise(ERR_LIB_BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; +@@ -1138,7 +1134,7 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + goto err; + } else + #endif +- if (!BN_from_montgomery(rr, &tmp, mont, ctx)) ++ if (!bn_from_mont_fixed_top(rr, &tmp, mont, ctx)) + goto err; + ret = 1; + err: +@@ -1152,6 +1148,19 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + return ret; + } + ++int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, ++ const BIGNUM *m, BN_CTX *ctx, ++ BN_MONT_CTX *in_mont) ++{ ++ bn_check_top(a); ++ bn_check_top(p); ++ bn_check_top(m); ++ if (!bn_mod_exp_mont_fixed_top(rr, a, p, m, ctx, in_mont)) ++ return 0; ++ bn_correct_top(rr); ++ return 1; ++} ++ + int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) + { +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c +index b1696d93..1f0bf1ec 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/ec/ec_lib.c +@@ -20,6 +20,7 @@ + #include + #include + #include "crypto/ec.h" ++#include "crypto/bn.h" + #include "internal/nelem.h" + #include "ec_local.h" + +@@ -1262,10 +1263,10 @@ static int ec_field_inverse_mod_ord(const EC_GROUP *group, BIGNUM *r, + if (!BN_sub(e, group->order, e)) + goto err; + /*- +- * Exponent e is public. +- * No need for scatter-gather or BN_FLG_CONSTTIME. ++ * Although the exponent is public we want the result to be ++ * fixed top. + */ +- if (!BN_mod_exp_mont(r, x, e, group->order, ctx, group->mont_data)) ++ if (!bn_mod_exp_mont_fixed_top(r, x, e, group->order, ctx, group->mont_data)) + goto err; + + ret = 1; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/include/crypto/bn.h b/CryptoPkg/Library/OpensslLib/openssl/include/crypto/bn.h +index fd1c09d9..ba50bca2 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/include/crypto/bn.h ++++ b/CryptoPkg/Library/OpensslLib/openssl/include/crypto/bn.h +@@ -73,6 +73,9 @@ int bn_set_words(BIGNUM *a, const BN_ULONG *words, int num_words); + */ + int bn_mul_mont_fixed_top(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_MONT_CTX *mont, BN_CTX *ctx); ++int bn_mod_exp_mont_fixed_top(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, ++ const BIGNUM *m, BN_CTX *ctx, ++ BN_MONT_CTX *in_mont); + int bn_to_mont_fixed_top(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, + BN_CTX *ctx); + int bn_from_mont_fixed_top(BIGNUM *r, const BIGNUM *a, BN_MONT_CTX *mont, +-- +2.33.0 + diff --git a/0084-Free-the-read-buffers-CVE-2024-4741.patch b/0084-Free-the-read-buffers-CVE-2024-4741.patch new file mode 100644 index 0000000..93af318 --- /dev/null +++ b/0084-Free-the-read-buffers-CVE-2024-4741.patch @@ -0,0 +1,70 @@ +From 4487afc6c7ca5024ff8556ab76907449769b660d Mon Sep 17 00:00:00 2001 +From: hy <12444214+dhjgty@user.noreply.gitee.com> +Date: Mon, 24 Feb 2025 22:50:29 +0800 +Subject: [PATCH] fix CVE-2024-4741 + +Only free the read buffers if we're not using them +If we're part way through processing a record, or the application has +not released all the records then we should not free our buffer because +they are still needed. + +CVE-2024-4741 + +Reviewed-by: Tomas Mraz +Reviewed-by: Neil Horman +Reviewed-by: Matt Caswell +--- + .../Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c | 9 +++++++++ + CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h | 1 + + CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c b/CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c +index 3baf8207..99602b6b 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/ssl/record/rec_layer_s3.c +@@ -81,6 +81,15 @@ int RECORD_LAYER_read_pending(const RECORD_LAYER *rl) + return SSL3_BUFFER_get_left(&rl->rbuf) != 0; + } + ++int RECORD_LAYER_data_present(const RECORD_LAYER *rl) ++{ ++ if (rl->rstate == SSL_ST_READ_BODY) ++ return 1; ++ if (RECORD_LAYER_processed_read_pending(rl)) ++ return 1; ++ return 0; ++} ++ + /* Checks if we have decrypted unread record data pending */ + int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl) + { +diff --git a/CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h b/CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h +index 234656bf..b60f71c8 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h ++++ b/CryptoPkg/Library/OpensslLib/openssl/ssl/record/record.h +@@ -205,6 +205,7 @@ void RECORD_LAYER_release(RECORD_LAYER *rl); + int RECORD_LAYER_read_pending(const RECORD_LAYER *rl); + int RECORD_LAYER_processed_read_pending(const RECORD_LAYER *rl); + int RECORD_LAYER_write_pending(const RECORD_LAYER *rl); ++int RECORD_LAYER_data_present(const RECORD_LAYER *rl); + void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl); + void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl); + int RECORD_LAYER_is_sslv2_record(RECORD_LAYER *rl); +diff --git a/CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c b/CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c +index 5d57f5d2..ac4ae41e 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/ssl/ssl_lib.c +@@ -5489,6 +5489,9 @@ int SSL_free_buffers(SSL *ssl) + if (RECORD_LAYER_read_pending(rl) || RECORD_LAYER_write_pending(rl)) + return 0; + ++ if (RECORD_LAYER_data_present(rl)) ++ return 0; ++ + RECORD_LAYER_release(rl); + return 1; + } +-- +2.33.0 + diff --git a/0085-Process-key-length-CVE-2023-5363.patch b/0085-Process-key-length-CVE-2023-5363.patch new file mode 100644 index 0000000..0f0d014 --- /dev/null +++ b/0085-Process-key-length-CVE-2023-5363.patch @@ -0,0 +1,79 @@ +From d691ea7823f1a139ac7b859709be84c74ea6653f Mon Sep 17 00:00:00 2001 +From: hy <12444214+dhjgty@user.noreply.gitee.com> +Date: Mon, 24 Feb 2025 23:05:55 +0800 +Subject: [PATCH] evp: process key length and iv length early if present + evp_cipher_init_internal() takes a params array argument and this is + processed late in the initialisation process for some ciphers (AEAD ones). + +This means that changing the IV length as a parameter will either truncate the +IV (very bad if SP 800-38d section 8.2.1 is used) or grab extra uninitialised +bytes. + +Truncation is very bad if SP 800-38d section 8.2.1 is being used to +contruct a deterministic IV. This leads to an instant loss of confidentiality. + +Grabbing extra bytes isn't so serious, it will most likely result in a bad +decryption. + +Problem reported by Tony Battersby of Cybernetics.com but earlier discovered +and raised as issue #19822. + +Fixes CVE-2023-5363 +Fixes #19822 + +Reviewed-by: Hugo Landau +Reviewed-by: Matt Caswell +--- + .../OpensslLib/openssl/crypto/evp/evp_enc.c | 36 +++++++++++++++++++ + 1 file changed, 36 insertions(+) + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c +index b178d108..2dff3e66 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/evp/evp_enc.c +@@ -218,6 +218,42 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, + return 0; + } + ++#ifndef FIPS_MODULE ++ /* ++ * Fix for CVE-2023-5363 ++ * Passing in a size as part of the init call takes effect late ++ * so, force such to occur before the initialisation. ++ * ++ * The FIPS provider's internal library context is used in a manner ++ * such that this is not an issue. ++ */ ++ if (params != NULL) { ++ OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, ++ OSSL_PARAM_END }; ++ OSSL_PARAM *q = param_lens; ++ const OSSL_PARAM *p; ++ ++ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); ++ if (p != NULL) ++ memcpy(q++, p, sizeof(*q)); ++ ++ /* ++ * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for ++ * OSSL_CIPHER_PARAM_IVLEN so both are covered here. ++ */ ++ p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); ++ if (p != NULL) ++ memcpy(q++, p, sizeof(*q)); ++ ++ if (q != param_lens) { ++ if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { ++ ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); ++ return 0; ++ } ++ } ++ } ++#endif ++ + if (enc) { + if (ctx->cipher->einit == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); +-- +2.33.0 + diff --git a/edk2.spec b/edk2.spec index 0bb1bf3..3600d48 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 17 +Release: 18 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -132,6 +132,11 @@ patch80: 0080-Platform-Loongson-Remove-minimium-memory-size-limita.patch patch81: 0081-Platform-Loongson-Modify-loongarch-uefi-firmware-siz.patch patch82: 0082-fixup-fdt-parse-error.patch +# Fix CVE-2024-13176、CVE-2024-4741、CVE-2023-5363 +patch83: 0083-Fix-timing-side-channel-CVE-2024-13176.patch +patch84: 0084-Free-the-read-buffers-CVE-2024-4741.patch +patch85: 0085-Process-key-length-CVE-2023-5363.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -401,6 +406,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Sun Feb 23 2025 huyu - 202308-18 +- fix CVE-2024-13176、CVE-2024-4741、CVE-2023-5363 + * Tue Dec 17 2024 Xiaotian Wu - 202308-17 - Update LoongArch virtual machine - 0080-Platform-Loongson-Remove-minimium-memory-size-limita.patch -- Gitee From 59507c0953f382db6c515883adfc8488d0b90b78 Mon Sep 17 00:00:00 2001 From: ShenYage Date: Fri, 28 Feb 2025 22:29:15 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix=20some=20bugs=20for=20CVE-2023-45236?= =?UTF-8?q?=E3=80=81CVE-2023-45237?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: ShenYage --- ...orkPkg-SECURITY-PATCH-CVE-2023-45237.patch | 1304 ----------------- ...e-SECURITY-PATCH-CVE-2023-45236-Rela.patch | 87 ++ ...tLib-SECURITY-PATCH-CVE-2023-45237-R.patch | 67 + ...TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch | 823 ----------- edk2.spec | 9 +- 5 files changed, 160 insertions(+), 2130 deletions(-) delete mode 100644 0055-NetworkPkg-SECURITY-PATCH-CVE-2023-45237.patch create mode 100644 0055-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236-Rela.patch create mode 100644 0056-NetworkPkg-DxeNetLib-SECURITY-PATCH-CVE-2023-45237-R.patch delete mode 100644 0056-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch diff --git a/0055-NetworkPkg-SECURITY-PATCH-CVE-2023-45237.patch b/0055-NetworkPkg-SECURITY-PATCH-CVE-2023-45237.patch deleted file mode 100644 index 188f075..0000000 --- a/0055-NetworkPkg-SECURITY-PATCH-CVE-2023-45237.patch +++ /dev/null @@ -1,1304 +0,0 @@ -From f236cf12bddf769382c5960f92c83a154eae0539 Mon Sep 17 00:00:00 2001 -From: Doug Flick -Date: Wed, 8 May 2024 22:56:28 -0700 -Subject: [PATCH 1/2] NetworkPkg: SECURITY PATCH CVE-2023-45237 - -REF:https://bugzilla.tianocore.org/show_bug.cgi?id=4542 - -Bug Overview: -PixieFail Bug #9 -CVE-2023-45237 -CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N -CWE-338 Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG) - -Use of a Weak PseudoRandom Number Generator - -Change Overview: - -Updates all Instances of NET_RANDOM (NetRandomInitSeed ()) to either - -> -> EFI_STATUS -> EFIAPI -> PseudoRandomU32 ( -> OUT UINT32 *Output -> ); -> - -or (depending on the use case) - -> -> EFI_STATUS -> EFIAPI -> PseudoRandom ( -> OUT VOID *Output, -> IN UINTN OutputLength -> ); -> - -This is because the use of - -Example: - -The following code snippet PseudoRandomU32 () function is used: - -> -> UINT32 Random; -> -> Status = PseudoRandomU32 (&Random); -> if (EFI_ERROR (Status)) { -> DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", -__func__, Status)); -> return Status; -> } -> - -This also introduces a new PCD to enable/disable the use of the -secure implementation of algorithms for PseudoRandom () and -instead depend on the default implementation. This may be required for -some platforms where the UEFI Spec defined algorithms are not available. - -> -> PcdEnforceSecureRngAlgorithms -> - -If the platform does not have any one of the UEFI defined -secure RNG algorithms then the driver will assert. - -Cc: Saloni Kasbekar -Cc: Zachary Clark-williams - -Signed-off-by: Doug Flick [MSFT] -Reviewed-by: Saloni Kasbekar ---- - MdePkg/MdePkg.dec | 1 + - NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c | 10 +- - NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c | 11 +- - NetworkPkg/DnsDxe/DnsDhcp.c | 10 +- - NetworkPkg/DnsDxe/DnsImpl.c | 11 +- - NetworkPkg/HttpBootDxe/HttpBootDhcp6.c | 10 +- - NetworkPkg/IScsiDxe/IScsiCHAP.c | 19 ++- - NetworkPkg/IScsiDxe/IScsiMisc.c | 14 +-- - NetworkPkg/IScsiDxe/IScsiMisc.h | 6 +- - NetworkPkg/Include/Library/NetLib.h | 50 +++++--- - NetworkPkg/Ip4Dxe/Ip4Driver.c | 10 +- - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c | 9 +- - NetworkPkg/Ip6Dxe/Ip6Driver.c | 17 ++- - NetworkPkg/Ip6Dxe/Ip6If.c | 12 +- - NetworkPkg/Ip6Dxe/Ip6Mld.c | 12 +- - NetworkPkg/Ip6Dxe/Ip6Nd.c | 35 ++++-- - NetworkPkg/Ip6Dxe/Ip6Nd.h | 8 +- - NetworkPkg/Library/DxeNetLib/DxeNetLib.c | 136 +++++++++++++++++---- - NetworkPkg/Library/DxeNetLib/DxeNetLib.inf | 14 ++- - NetworkPkg/NetworkPkg.dec | 7 ++ - NetworkPkg/SecurityFixes.yaml | 39 ++++++ - NetworkPkg/TcpDxe/TcpDriver.c | 15 ++- - NetworkPkg/TcpDxe/TcpDxe.inf | 3 + - NetworkPkg/Udp4Dxe/Udp4Driver.c | 10 +- - NetworkPkg/Udp6Dxe/Udp6Driver.c | 11 +- - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c | 9 +- - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 11 +- - NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c | 12 +- - 28 files changed, 420 insertions(+), 92 deletions(-) - -diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec -index b8561499..a7589e9f 100644 ---- a/MdePkg/MdePkg.dec -+++ b/MdePkg/MdePkg.dec -@@ -643,6 +643,7 @@ - gEfiRngAlgorithmX9313DesGuid = { 0x63c4785a, 0xca34, 0x4012, {0xa3, 0xc8, 0x0b, 0x6a, 0x32, 0x4f, 0x55, 0x46 }} - gEfiRngAlgorithmX931AesGuid = { 0xacd03321, 0x777e, 0x4d3d, {0xb1, 0xc8, 0x20, 0xcf, 0xd8, 0x88, 0x20, 0xc9 }} - gEfiRngAlgorithmRaw = { 0xe43176d7, 0xb6e8, 0x4827, {0xb7, 0x84, 0x7f, 0xfd, 0xc4, 0xb6, 0x85, 0x61 }} -+ gEfiRngAlgorithmArmRndr = { 0x43d2fde3, 0x9d4e, 0x4d79, {0x02, 0x96, 0xa8, 0x9b, 0xca, 0x78, 0x08, 0x41 }} - - ## Include/Protocol/AdapterInformation.h - gEfiAdapterInfoMediaStateGuid = { 0xD7C74207, 0xA831, 0x4A26, {0xB1, 0xF5, 0xD1, 0x93, 0x06, 0x5C, 0xE8, 0xB6 }} -diff --git a/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c b/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c -index 8c37e93b..b4e93a53 100644 ---- a/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c -+++ b/NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c -@@ -1,6 +1,7 @@ - /** @file - - Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -189,6 +190,13 @@ Dhcp4CreateService ( - { - DHCP_SERVICE *DhcpSb; - EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - *Service = NULL; - DhcpSb = AllocateZeroPool (sizeof (DHCP_SERVICE)); -@@ -203,7 +211,7 @@ Dhcp4CreateService ( - DhcpSb->Image = ImageHandle; - InitializeListHead (&DhcpSb->Children); - DhcpSb->DhcpState = Dhcp4Stopped; -- DhcpSb->Xid = NET_RANDOM (NetRandomInitSeed ()); -+ DhcpSb->Xid = Random; - CopyMem ( - &DhcpSb->ServiceBinding, - &mDhcp4ServiceBindingTemplate, -diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c -index b591a460..f0a1e3b6 100644 ---- a/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c -+++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c -@@ -3,7 +3,7 @@ - implementation for Dhcp6 Driver. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -123,6 +123,13 @@ Dhcp6CreateService ( - { - DHCP6_SERVICE *Dhcp6Srv; - EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - *Service = NULL; - Dhcp6Srv = AllocateZeroPool (sizeof (DHCP6_SERVICE)); -@@ -147,7 +154,7 @@ Dhcp6CreateService ( - Dhcp6Srv->Signature = DHCP6_SERVICE_SIGNATURE; - Dhcp6Srv->Controller = Controller; - Dhcp6Srv->Image = ImageHandle; -- Dhcp6Srv->Xid = (0xffffff & NET_RANDOM (NetRandomInitSeed ())); -+ Dhcp6Srv->Xid = (0xffffff & Random); - - CopyMem ( - &Dhcp6Srv->ServiceBinding, -diff --git a/NetworkPkg/DnsDxe/DnsDhcp.c b/NetworkPkg/DnsDxe/DnsDhcp.c -index 933565a3..102c4be6 100644 ---- a/NetworkPkg/DnsDxe/DnsDhcp.c -+++ b/NetworkPkg/DnsDxe/DnsDhcp.c -@@ -2,6 +2,7 @@ - Functions implementation related with DHCPv4/v6 for DNS driver. - - Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -277,6 +278,7 @@ GetDns4ServerFromDhcp4 ( - EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token; - BOOLEAN IsDone; - UINTN Index; -+ UINT32 Random; - - Image = Instance->Service->ImageHandle; - Controller = Instance->Service->ControllerHandle; -@@ -292,6 +294,12 @@ GetDns4ServerFromDhcp4 ( - Data = NULL; - InterfaceInfo = NULL; - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - ZeroMem ((UINT8 *)ParaList, sizeof (ParaList)); - - ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA)); -@@ -467,7 +475,7 @@ GetDns4ServerFromDhcp4 ( - - Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet); - -- Token.Packet->Dhcp4.Header.Xid = HTONL (NET_RANDOM (NetRandomInitSeed ())); -+ Token.Packet->Dhcp4.Header.Xid = Random; - - Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000); - -diff --git a/NetworkPkg/DnsDxe/DnsImpl.c b/NetworkPkg/DnsDxe/DnsImpl.c -index d3118128..8e9d7222 100644 ---- a/NetworkPkg/DnsDxe/DnsImpl.c -+++ b/NetworkPkg/DnsDxe/DnsImpl.c -@@ -2,6 +2,7 @@ - DnsDxe support functions implementation. - - Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -1963,6 +1964,14 @@ ConstructDNSQuery ( - NET_FRAGMENT Frag; - DNS_HEADER *DnsHeader; - DNS_QUERY_SECTION *DnsQuery; -+ EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - // - // Messages carried by UDP are restricted to 512 bytes (not counting the IP -@@ -1977,7 +1986,7 @@ ConstructDNSQuery ( - // Fill header - // - DnsHeader = (DNS_HEADER *)Frag.Bulk; -- DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed ()); -+ DnsHeader->Identification = (UINT16)Random; - DnsHeader->Flags.Uint16 = 0x0000; - DnsHeader->Flags.Bits.RD = 1; - DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD; -diff --git a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c -index b22cef4f..5e8c7bed 100644 ---- a/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c -+++ b/NetworkPkg/HttpBootDxe/HttpBootDhcp6.c -@@ -2,6 +2,7 @@ - Functions implementation related with DHCPv6 for HTTP boot driver. - - Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -951,6 +952,7 @@ HttpBootDhcp6Sarr ( - UINT32 OptCount; - UINT8 Buffer[HTTP_BOOT_DHCP6_OPTION_MAX_SIZE]; - EFI_STATUS Status; -+ UINT32 Random; - - Dhcp6 = Private->Dhcp6; - ASSERT (Dhcp6 != NULL); -@@ -961,6 +963,12 @@ HttpBootDhcp6Sarr ( - OptCount = HttpBootBuildDhcp6Options (Private, OptList, Buffer); - ASSERT (OptCount > 0); - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - Retransmit = AllocateZeroPool (sizeof (EFI_DHCP6_RETRANSMISSION)); - if (Retransmit == NULL) { - return EFI_OUT_OF_RESOURCES; -@@ -976,7 +984,7 @@ HttpBootDhcp6Sarr ( - Config.IaInfoEvent = NULL; - Config.RapidCommit = FALSE; - Config.ReconfigureAccept = FALSE; -- Config.IaDescriptor.IaId = NET_RANDOM (NetRandomInitSeed ()); -+ Config.IaDescriptor.IaId = Random; - Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; - Config.SolicitRetransmission = Retransmit; - Retransmit->Irt = 4; -diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.c b/NetworkPkg/IScsiDxe/IScsiCHAP.c -index b507f11c..9af2727e 100644 ---- a/NetworkPkg/IScsiDxe/IScsiCHAP.c -+++ b/NetworkPkg/IScsiDxe/IScsiCHAP.c -@@ -3,6 +3,7 @@ - Configuration. - - Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -576,16 +577,24 @@ IScsiCHAPToSendReq ( - // - // CHAP_I= - // -- IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1); -+ Status = IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1); -+ if (EFI_ERROR (Status)) { -+ break; -+ } -+ - AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier); - IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr); - // - // CHAP_C= - // -- IScsiGenRandom ( -- (UINT8 *)AuthData->OutChallenge, -- AuthData->Hash->DigestSize -- ); -+ Status = IScsiGenRandom ( -+ (UINT8 *)AuthData->OutChallenge, -+ AuthData->Hash->DigestSize -+ ); -+ if (EFI_ERROR (Status)) { -+ break; -+ } -+ - BinToHexStatus = IScsiBinToHex ( - (UINT8 *)AuthData->OutChallenge, - AuthData->Hash->DigestSize, -diff --git a/NetworkPkg/IScsiDxe/IScsiMisc.c b/NetworkPkg/IScsiDxe/IScsiMisc.c -index 78dc5c73..1a1a99a0 100644 ---- a/NetworkPkg/IScsiDxe/IScsiMisc.c -+++ b/NetworkPkg/IScsiDxe/IScsiMisc.c -@@ -2,6 +2,7 @@ - Miscellaneous routines for iSCSI driver. - - Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -474,20 +475,17 @@ IScsiNetNtoi ( - @param[in, out] Rand The buffer to contain random numbers. - @param[in] RandLength The length of the Rand buffer. - -+ @retval EFI_SUCCESS on success -+ @retval others on error -+ - **/ --VOID -+EFI_STATUS - IScsiGenRandom ( - IN OUT UINT8 *Rand, - IN UINTN RandLength - ) - { -- UINT32 Random; -- -- while (RandLength > 0) { -- Random = NET_RANDOM (NetRandomInitSeed ()); -- *Rand++ = (UINT8)(Random); -- RandLength--; -- } -+ return PseudoRandom (Rand, RandLength); - } - - /** -diff --git a/NetworkPkg/IScsiDxe/IScsiMisc.h b/NetworkPkg/IScsiDxe/IScsiMisc.h -index a951eee7..16acd191 100644 ---- a/NetworkPkg/IScsiDxe/IScsiMisc.h -+++ b/NetworkPkg/IScsiDxe/IScsiMisc.h -@@ -2,6 +2,7 @@ - Miscellaneous definitions for iSCSI driver. - - Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -202,8 +203,11 @@ IScsiNetNtoi ( - @param[in, out] Rand The buffer to contain random numbers. - @param[in] RandLength The length of the Rand buffer. - -+ @retval EFI_SUCCESS on success -+ @retval others on error -+ - **/ --VOID -+EFI_STATUS - IScsiGenRandom ( - IN OUT UINT8 *Rand, - IN UINTN RandLength -diff --git a/NetworkPkg/Include/Library/NetLib.h b/NetworkPkg/Include/Library/NetLib.h -index 8c0e62b3..995a0b58 100644 ---- a/NetworkPkg/Include/Library/NetLib.h -+++ b/NetworkPkg/Include/Library/NetLib.h -@@ -3,6 +3,7 @@ - It provides basic functions for the UEFI network stack. - - Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -539,8 +540,6 @@ extern EFI_IPv4_ADDRESS mZeroIp4Addr; - #define TICKS_PER_MS 10000U - #define TICKS_PER_SECOND 10000000U - --#define NET_RANDOM(Seed) ((UINT32) ((UINT32) (Seed) * 1103515245UL + 12345) % 4294967295UL) -- - /** - Extract a UINT32 from a byte stream. - -@@ -580,19 +579,40 @@ NetPutUint32 ( - ); - - /** -- Initialize a random seed using current time and monotonic count. -- -- Get current time and monotonic count first. Then initialize a random seed -- based on some basic mathematics operation on the hour, day, minute, second, -- nanosecond and year of the current time and the monotonic count value. -- -- @return The random seed initialized with current time. -- --**/ --UINT32 --EFIAPI --NetRandomInitSeed ( -- VOID -+ Generate a Random output data given a length. -+ -+ @param[out] Output - The buffer to store the generated random data. -+ @param[in] OutputLength - The length of the output buffer. -+ -+ @retval EFI_SUCCESS On Success -+ @retval EFI_INVALID_PARAMETER Pointer is null or size is zero -+ @retval EFI_NOT_FOUND RNG protocol not found -+ @retval Others Error from RngProtocol->GetRNG() -+ -+ @return Status code -+**/ -+EFI_STATUS -+EFIAPI -+PseudoRandom ( -+ OUT VOID *Output, -+ IN UINTN OutputLength -+ ); -+ -+/** -+ Generate a 32-bit pseudo-random number. -+ -+ @param[out] Output - The buffer to store the generated random number. -+ -+ @retval EFI_SUCCESS On Success -+ @retval EFI_NOT_FOUND RNG protocol not found -+ @retval Others Error from RngProtocol->GetRNG() -+ -+ @return Status code -+**/ -+EFI_STATUS -+EFIAPI -+PseudoRandomU32 ( -+ OUT UINT32 *Output - ); - - #define NET_LIST_USER_STRUCT(Entry, Type, Field) \ -diff --git a/NetworkPkg/Ip4Dxe/Ip4Driver.c b/NetworkPkg/Ip4Dxe/Ip4Driver.c -index ec483ff0..c8a594ed 100644 ---- a/NetworkPkg/Ip4Dxe/Ip4Driver.c -+++ b/NetworkPkg/Ip4Dxe/Ip4Driver.c -@@ -2,6 +2,7 @@ - The driver binding and service binding protocol for IP4 driver. - - Copyright (c) 2005 - 2019, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
- - SPDX-License-Identifier: BSD-2-Clause-Patent -@@ -549,11 +550,18 @@ Ip4DriverBindingStart ( - EFI_IP4_CONFIG2_PROTOCOL *Ip4Cfg2; - UINTN Index; - IP4_CONFIG2_DATA_ITEM *DataItem; -+ UINT32 Random; - - IpSb = NULL; - Ip4Cfg2 = NULL; - DataItem = NULL; - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - // - // Test for the Ip4 service binding protocol - // -@@ -653,7 +661,7 @@ Ip4DriverBindingStart ( - // - // Initialize the IP4 ID - // -- mIp4Id = (UINT16)NET_RANDOM (NetRandomInitSeed ()); -+ mIp4Id = (UINT16)Random; - - return Status; - -diff --git a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c -index 70e232ce..79741609 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c -+++ b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c -@@ -2276,6 +2276,13 @@ Ip6ConfigInitInstance ( - UINTN Index; - UINT16 IfIndex; - IP6_CONFIG_DATA_ITEM *DataItem; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - IpSb = IP6_SERVICE_FROM_IP6_CONFIG_INSTANCE (Instance); - -@@ -2381,7 +2388,7 @@ Ip6ConfigInitInstance ( - // The NV variable is not set, so generate a random IAID, and write down the - // fresh new configuration as the NV variable now. - // -- Instance->IaId = NET_RANDOM (NetRandomInitSeed ()); -+ Instance->IaId = Random; - - for (Index = 0; Index < IpSb->SnpMode.HwAddressSize; Index++) { - Instance->IaId |= (IpSb->SnpMode.CurrentAddress.Addr[Index] << ((Index << 3) & 31)); -diff --git a/NetworkPkg/Ip6Dxe/Ip6Driver.c b/NetworkPkg/Ip6Dxe/Ip6Driver.c -index b483a7d1..c73da917 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6Driver.c -+++ b/NetworkPkg/Ip6Dxe/Ip6Driver.c -@@ -3,7 +3,7 @@ - - Copyright (c) 2009 - 2019, Intel Corporation. All rights reserved.
- (C) Copyright 2015 Hewlett-Packard Development Company, L.P.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -316,7 +316,11 @@ Ip6CreateService ( - IpSb->CurHopLimit = IP6_HOP_LIMIT; - IpSb->LinkMTU = IP6_MIN_LINK_MTU; - IpSb->BaseReachableTime = IP6_REACHABLE_TIME; -- Ip6UpdateReachableTime (IpSb); -+ Status = Ip6UpdateReachableTime (IpSb); -+ if (EFI_ERROR (Status)) { -+ goto ON_ERROR; -+ } -+ - // - // RFC4861 RETRANS_TIMER: 1,000 milliseconds - // -@@ -516,11 +520,18 @@ Ip6DriverBindingStart ( - EFI_STATUS Status; - EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; - IP6_CONFIG_DATA_ITEM *DataItem; -+ UINT32 Random; - - IpSb = NULL; - Ip6Cfg = NULL; - DataItem = NULL; - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - // - // Test for the Ip6 service binding protocol - // -@@ -656,7 +667,7 @@ Ip6DriverBindingStart ( - // - // Initialize the IP6 ID - // -- mIp6Id = NET_RANDOM (NetRandomInitSeed ()); -+ mIp6Id = Random; - - return EFI_SUCCESS; - -diff --git a/NetworkPkg/Ip6Dxe/Ip6If.c b/NetworkPkg/Ip6Dxe/Ip6If.c -index 4629c05f..06b01df1 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6If.c -+++ b/NetworkPkg/Ip6Dxe/Ip6If.c -@@ -2,7 +2,7 @@ - Implement IP6 pseudo interface. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -89,6 +89,14 @@ Ip6SetAddress ( - IP6_PREFIX_LIST_ENTRY *PrefixEntry; - UINT64 Delay; - IP6_DELAY_JOIN_LIST *DelayNode; -+ EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - NET_CHECK_SIGNATURE (Interface, IP6_INTERFACE_SIGNATURE); - -@@ -164,7 +172,7 @@ Ip6SetAddress ( - // Thus queue the address to be processed in Duplicate Address Detection module - // after the delay time (in milliseconds). - // -- Delay = (UINT64)NET_RANDOM (NetRandomInitSeed ()); -+ Delay = (UINT64)Random; - Delay = MultU64x32 (Delay, IP6_ONE_SECOND_IN_MS); - Delay = RShiftU64 (Delay, 32); - -diff --git a/NetworkPkg/Ip6Dxe/Ip6Mld.c b/NetworkPkg/Ip6Dxe/Ip6Mld.c -index e6b2b653..6b2f07fc 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6Mld.c -+++ b/NetworkPkg/Ip6Dxe/Ip6Mld.c -@@ -696,7 +696,15 @@ Ip6UpdateDelayTimer ( - IN OUT IP6_MLD_GROUP *Group - ) - { -- UINT32 Delay; -+ UINT32 Delay; -+ EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - // - // If the Query packet specifies a Maximum Response Delay of zero, perform timer -@@ -715,7 +723,7 @@ Ip6UpdateDelayTimer ( - // is less than the remaining value of the running timer. - // - if ((Group->DelayTimer == 0) || (Delay < Group->DelayTimer)) { -- Group->DelayTimer = Delay / 4294967295UL * NET_RANDOM (NetRandomInitSeed ()); -+ Group->DelayTimer = Delay / 4294967295UL * Random; - } - - return EFI_SUCCESS; -diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.c b/NetworkPkg/Ip6Dxe/Ip6Nd.c -index c10c7017..395cd991 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6Nd.c -+++ b/NetworkPkg/Ip6Dxe/Ip6Nd.c -@@ -2,7 +2,7 @@ - Implementation of Neighbor Discovery support routines. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -16,17 +16,28 @@ EFI_MAC_ADDRESS mZeroMacAddress; - - @param[in, out] IpSb Points to the IP6_SERVICE. - -+ @retval EFI_SUCCESS ReachableTime Updated -+ @retval others Failed to update ReachableTime - **/ --VOID -+EFI_STATUS - Ip6UpdateReachableTime ( - IN OUT IP6_SERVICE *IpSb - ) - { -- UINT32 Random; -- -- Random = (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE; -+ UINT32 Random; -+ EFI_STATUS Status; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ -+ Random = (Random / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE; - Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED; - IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE; -+ -+ return EFI_SUCCESS; - } - - /** -@@ -972,10 +983,17 @@ Ip6InitDADProcess ( - IP6_SERVICE *IpSb; - EFI_STATUS Status; - UINT32 MaxDelayTick; -+ UINT32 Random; - - NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE); - ASSERT (AddressInfo != NULL); - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - // - // Do nothing if we have already started DAD on the address. - // -@@ -1014,7 +1032,7 @@ Ip6InitDADProcess ( - Entry->Transmit = 0; - Entry->Receive = 0; - MaxDelayTick = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS; -- Entry->RetransTick = (MaxDelayTick * ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5; -+ Entry->RetransTick = (MaxDelayTick * ((Random % 5) + 1)) / 5; - Entry->AddressInfo = AddressInfo; - Entry->Callback = Callback; - Entry->Context = Context; -@@ -2078,7 +2096,10 @@ Ip6ProcessRouterAdvertise ( - // in BaseReachableTime and recompute a ReachableTime. - // - IpSb->BaseReachableTime = ReachableTime; -- Ip6UpdateReachableTime (IpSb); -+ Status = Ip6UpdateReachableTime (IpSb); -+ if (EFI_ERROR (Status)) { -+ goto Exit; -+ } - } - - if (RetransTimer != 0) { -diff --git a/NetworkPkg/Ip6Dxe/Ip6Nd.h b/NetworkPkg/Ip6Dxe/Ip6Nd.h -index 7d6577ad..899ef216 100644 ---- a/NetworkPkg/Ip6Dxe/Ip6Nd.h -+++ b/NetworkPkg/Ip6Dxe/Ip6Nd.h -@@ -2,7 +2,7 @@ - Definition of Neighbor Discovery support routines. - - Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -780,10 +780,10 @@ Ip6OnArpResolved ( - /** - Update the ReachableTime in IP6 service binding instance data, in milliseconds. - -- @param[in, out] IpSb Points to the IP6_SERVICE. -- -+ @retval EFI_SUCCESS ReachableTime Updated -+ @retval others Failed to update ReachableTime - **/ --VOID -+EFI_STATUS - Ip6UpdateReachableTime ( - IN OUT IP6_SERVICE *IpSb - ); -diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c -index fd4a9e15..e27406a0 100644 ---- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c -+++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c -@@ -3,6 +3,7 @@ - - Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.
- (C) Copyright 2015 Hewlett Packard Enterprise Development LP
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - **/ - -@@ -31,6 +32,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent - #include - #include - #include -+#include - - #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE) - #define DEFAULT_ZERO_START ((UINTN) ~0) -@@ -127,6 +129,25 @@ GLOBAL_REMOVE_IF_UNREFERENCED VLAN_DEVICE_PATH mNetVlanDevicePathTemplate = { - 0 - }; - -+// -+// These represent UEFI SPEC defined algorithms that should be supported by -+// the RNG protocol and are generally considered secure. -+// -+// The order of the algorithms in this array is important. This order is the order -+// in which the algorithms will be tried by the RNG protocol. -+// If your platform needs to use a specific algorithm for the random number generator, -+// then you should place that algorithm first in the array. -+// -+GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID *mSecureHashAlgorithms[] = { -+ &gEfiRngAlgorithmSp80090Ctr256Guid, // SP800-90A DRBG CTR using AES-256 -+ &gEfiRngAlgorithmSp80090Hmac256Guid, // SP800-90A DRBG HMAC using SHA-256 -+ &gEfiRngAlgorithmSp80090Hash256Guid, // SP800-90A DRBG Hash using SHA-256 -+ &gEfiRngAlgorithmArmRndr, // unspecified SP800-90A DRBG via ARM RNDR register -+ &gEfiRngAlgorithmRaw, // Raw data from NRBG (or TRNG) -+}; -+ -+#define SECURE_HASH_ALGORITHMS_SIZE (sizeof (mSecureHashAlgorithms) / sizeof (EFI_GUID *)) -+ - /** - Locate the handles that support SNP, then open one of them - to send the syslog packets. The caller isn't required to close -@@ -884,34 +905,107 @@ Ip6Swap128 ( - } - - /** -- Initialize a random seed using current time and monotonic count. -+ Generate a Random output data given a length. - -- Get current time and monotonic count first. Then initialize a random seed -- based on some basic mathematics operation on the hour, day, minute, second, -- nanosecond and year of the current time and the monotonic count value. -+ @param[out] Output - The buffer to store the generated random data. -+ @param[in] OutputLength - The length of the output buffer. - -- @return The random seed initialized with current time. -+ @retval EFI_SUCCESS On Success -+ @retval EFI_INVALID_PARAMETER Pointer is null or size is zero -+ @retval EFI_NOT_FOUND RNG protocol not found -+ @retval Others Error from RngProtocol->GetRNG() - -+ @return Status code - **/ --UINT32 -+EFI_STATUS - EFIAPI --NetRandomInitSeed ( -- VOID -+PseudoRandom ( -+ OUT VOID *Output, -+ IN UINTN OutputLength - ) - { -- EFI_TIME Time; -- UINT32 Seed; -- UINT64 MonotonicCount; -- -- gRT->GetTime (&Time, NULL); -- Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second); -- Seed ^= Time.Nanosecond; -- Seed ^= Time.Year << 7; -- -- gBS->GetNextMonotonicCount (&MonotonicCount); -- Seed += (UINT32)MonotonicCount; -- -- return Seed; -+ EFI_RNG_PROTOCOL *RngProtocol; -+ EFI_STATUS Status; -+ UINTN AlgorithmIndex; -+ -+ if ((Output == NULL) || (OutputLength == 0)) { -+ return EFI_INVALID_PARAMETER; -+ } -+ -+ Status = gBS->LocateProtocol (&gEfiRngProtocolGuid, NULL, (VOID **)&RngProtocol); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "Failed to locate EFI_RNG_PROTOCOL: %r\n", Status)); -+ ASSERT_EFI_ERROR (Status); -+ return Status; -+ } -+ -+ if (PcdGetBool (PcdEnforceSecureRngAlgorithms)) { -+ for (AlgorithmIndex = 0; AlgorithmIndex < SECURE_HASH_ALGORITHMS_SIZE; AlgorithmIndex++) { -+ Status = RngProtocol->GetRNG (RngProtocol, mSecureHashAlgorithms[AlgorithmIndex], OutputLength, (UINT8 *)Output); -+ if (!EFI_ERROR (Status)) { -+ // -+ // Secure Algorithm was supported on this platform -+ // -+ return EFI_SUCCESS; -+ } else if (Status == EFI_UNSUPPORTED) { -+ // -+ // Secure Algorithm was not supported on this platform -+ // -+ DEBUG ((DEBUG_ERROR, "Failed to generate random data using secure algorithm %d: %r\n", AlgorithmIndex, Status)); -+ -+ // -+ // Try the next secure algorithm -+ // -+ continue; -+ } else { -+ // -+ // Some other error occurred -+ // -+ DEBUG ((DEBUG_ERROR, "Failed to generate random data using secure algorithm %d: %r\n", AlgorithmIndex, Status)); -+ ASSERT_EFI_ERROR (Status); -+ return Status; -+ } -+ } -+ -+ // -+ // If we get here, we failed to generate random data using any secure algorithm -+ // Platform owner should ensure that at least one secure algorithm is supported -+ // -+ ASSERT_EFI_ERROR (Status); -+ return Status; -+ } -+ -+ // -+ // Lets try using the default algorithm (which may not be secure) -+ // -+ Status = RngProtocol->GetRNG (RngProtocol, NULL, OutputLength, (UINT8 *)Output); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random data: %r\n", __func__, Status)); -+ ASSERT_EFI_ERROR (Status); -+ return Status; -+ } -+ -+ return EFI_SUCCESS; -+} -+ -+/** -+ Generate a 32-bit pseudo-random number. -+ -+ @param[out] Output - The buffer to store the generated random number. -+ -+ @retval EFI_SUCCESS On Success -+ @retval EFI_NOT_FOUND RNG protocol not found -+ @retval Others Error from RngProtocol->GetRNG() -+ -+ @return Status code -+**/ -+EFI_STATUS -+EFIAPI -+PseudoRandomU32 ( -+ OUT UINT32 *Output -+ ) -+{ -+ return PseudoRandom (Output, sizeof (*Output)); - } - - /** -diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf -index 8145d256..ed5bb634 100644 ---- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf -+++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf -@@ -3,6 +3,7 @@ - # - # Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
- # (C) Copyright 2015 Hewlett Packard Enterprise Development LP
-+# Copyright (c) Microsoft Corporation - # SPDX-License-Identifier: BSD-2-Clause-Patent - # - ## -@@ -49,7 +50,11 @@ - gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ## SystemTable - gEfiSmbios3TableGuid ## SOMETIMES_CONSUMES ## SystemTable - gEfiAdapterInfoMediaStateGuid ## SOMETIMES_CONSUMES -- -+ gEfiRngAlgorithmRaw ## CONSUMES -+ gEfiRngAlgorithmSp80090Ctr256Guid ## CONSUMES -+ gEfiRngAlgorithmSp80090Hmac256Guid ## CONSUMES -+ gEfiRngAlgorithmSp80090Hash256Guid ## CONSUMES -+ gEfiRngAlgorithmArmRndr ## CONSUMES - - [Protocols] - gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES -@@ -59,3 +64,10 @@ - gEfiComponentNameProtocolGuid ## SOMETIMES_CONSUMES - gEfiComponentName2ProtocolGuid ## SOMETIMES_CONSUMES - gEfiAdapterInformationProtocolGuid ## SOMETIMES_CONSUMES -+ gEfiRngProtocolGuid ## CONSUMES -+ -+[FixedPcd] -+ gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms ## CONSUMES -+ -+[Depex] -+ gEfiRngProtocolGuid -diff --git a/NetworkPkg/NetworkPkg.dec b/NetworkPkg/NetworkPkg.dec -index e06f35e7..db7b1f27 100644 ---- a/NetworkPkg/NetworkPkg.dec -+++ b/NetworkPkg/NetworkPkg.dec -@@ -5,6 +5,7 @@ - # - # Copyright (c) 2009 - 2021, Intel Corporation. All rights reserved.
- # (C) Copyright 2015-2020 Hewlett Packard Enterprise Development LP
-+# Copyright (c) Microsoft Corporation - # - # SPDX-License-Identifier: BSD-2-Clause-Patent - # -@@ -130,6 +131,12 @@ - # @Prompt Indicates whether SnpDxe creates event for ExitBootServices() call. - gEfiNetworkPkgTokenSpaceGuid.PcdSnpCreateExitBootServicesEvent|TRUE|BOOLEAN|0x1000000C - -+ ## Enforces the use of Secure UEFI spec defined RNG algorithms for all network connections. -+ # TRUE - Enforce the use of Secure UEFI spec defined RNG algorithms. -+ # FALSE - Do not enforce and depend on the default implementation of RNG algorithm from the provider. -+ # @Prompt Enforce the use of Secure UEFI spec defined RNG algorithms. -+ gEfiNetworkPkgTokenSpaceGuid.PcdEnforceSecureRngAlgorithms|TRUE|BOOLEAN|0x1000000D -+ - [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx] - ## IPv6 DHCP Unique Identifier (DUID) Type configuration (From RFCs 3315 and 6355). - # 01 = DUID Based on Link-layer Address Plus Time [DUID-LLT] -diff --git a/NetworkPkg/SecurityFixes.yaml b/NetworkPkg/SecurityFixes.yaml -index 7d716ffc..a44cfc43 100644 ---- a/NetworkPkg/SecurityFixes.yaml -+++ b/NetworkPkg/SecurityFixes.yaml -@@ -122,3 +122,42 @@ 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_45237: -+ commit_titles: -+ - "NetworkPkg:: SECURITY PATCH CVE 2023-45237" -+ cve: CVE-2023-45237 -+ date_reported: 2023-08-28 13:56 UTC -+ description: "Bug 09 - Use of a Weak PseudoRandom Number Generator" -+ note: -+ files_impacted: -+ - NetworkPkg/Dhcp4Dxe/Dhcp4Driver.c -+ - NetworkPkg/Dhcp6Dxe/Dhcp6Driver.c -+ - NetworkPkg/DnsDxe/DnsDhcp.c -+ - NetworkPkg/DnsDxe/DnsImpl.c -+ - NetworkPkg/HttpBootDxe/HttpBootDhcp6.c -+ - NetworkPkg/IScsiDxe/IScsiCHAP.c -+ - NetworkPkg/IScsiDxe/IScsiMisc.c -+ - NetworkPkg/IScsiDxe/IScsiMisc.h -+ - NetworkPkg/Include/Library/NetLib.h -+ - NetworkPkg/Ip4Dxe/Ip4Driver.c -+ - NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c -+ - NetworkPkg/Ip6Dxe/Ip6Driver.c -+ - NetworkPkg/Ip6Dxe/Ip6If.c -+ - NetworkPkg/Ip6Dxe/Ip6Mld.c -+ - NetworkPkg/Ip6Dxe/Ip6Nd.c -+ - NetworkPkg/Ip6Dxe/Ip6Nd.h -+ - NetworkPkg/Library/DxeNetLib/DxeNetLib.c -+ - NetworkPkg/Library/DxeNetLib/DxeNetLib.inf -+ - NetworkPkg/NetworkPkg.dec -+ - NetworkPkg/TcpDxe/TcpDriver.c -+ - NetworkPkg/Udp4Dxe/Udp4Driver.c -+ - NetworkPkg/Udp6Dxe/Udp6Driver.c -+ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c -+ - NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c -+ - NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c -+ links: -+ - https://bugzilla.tianocore.org/show_bug.cgi?id=4542 -+ - https://nvd.nist.gov/vuln/detail/CVE-2023-45237 -+ - 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 -diff --git a/NetworkPkg/TcpDxe/TcpDriver.c b/NetworkPkg/TcpDxe/TcpDriver.c -index 98a90e02..f5d10c6e 100644 ---- a/NetworkPkg/TcpDxe/TcpDriver.c -+++ b/NetworkPkg/TcpDxe/TcpDriver.c -@@ -2,7 +2,7 @@ - The driver binding and service binding protocol for the TCP driver. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -163,7 +163,13 @@ TcpDriverEntryPoint ( - ) - { - EFI_STATUS Status; -- UINT32 Seed; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a Failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - // - // Install the TCP Driver Binding Protocol -@@ -203,9 +209,8 @@ TcpDriverEntryPoint ( - // - // Initialize ISS and random port. - // -- Seed = NetRandomInitSeed (); -- mTcpGlobalIss = NET_RANDOM (Seed) % mTcpGlobalIss; -- mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (NET_RANDOM (Seed) % TCP_PORT_KNOWN)); -+ mTcpGlobalIss = Random % mTcpGlobalIss; -+ mTcp4RandomPort = (UINT16)(TCP_PORT_KNOWN + (Random % TCP_PORT_KNOWN)); - mTcp6RandomPort = mTcp4RandomPort; - - return EFI_SUCCESS; -diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf -index c0acbdca..1b309801 100644 ---- a/NetworkPkg/TcpDxe/TcpDxe.inf -+++ b/NetworkPkg/TcpDxe/TcpDxe.inf -@@ -82,5 +82,8 @@ - gEfiTcp6ProtocolGuid ## BY_START - gEfiTcp6ServiceBindingProtocolGuid ## BY_START - -+[Depex] -+ gEfiHash2ServiceBindingProtocolGuid -+ - [UserExtensions.TianoCore."ExtraFiles"] - TcpDxeExtra.uni -diff --git a/NetworkPkg/Udp4Dxe/Udp4Driver.c b/NetworkPkg/Udp4Dxe/Udp4Driver.c -index cb917fcf..475ee13d 100644 ---- a/NetworkPkg/Udp4Dxe/Udp4Driver.c -+++ b/NetworkPkg/Udp4Dxe/Udp4Driver.c -@@ -1,6 +1,7 @@ - /** @file - - Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.
-+Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -555,6 +556,13 @@ Udp4DriverEntryPoint ( - ) - { - EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - // - // Install the Udp4DriverBinding and Udp4ComponentName protocols. -@@ -571,7 +579,7 @@ Udp4DriverEntryPoint ( - // - // Initialize the UDP random port. - // -- mUdp4RandomPort = (UINT16)(((UINT16)NetRandomInitSeed ()) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); -+ mUdp4RandomPort = (UINT16)(((UINT16)Random) % UDP4_PORT_KNOWN + UDP4_PORT_KNOWN); - } - - return Status; -diff --git a/NetworkPkg/Udp6Dxe/Udp6Driver.c b/NetworkPkg/Udp6Dxe/Udp6Driver.c -index ae96fb99..18b7f05b 100644 ---- a/NetworkPkg/Udp6Dxe/Udp6Driver.c -+++ b/NetworkPkg/Udp6Dxe/Udp6Driver.c -@@ -2,7 +2,7 @@ - Driver Binding functions and Service Binding functions for the Network driver module. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -596,6 +596,13 @@ Udp6DriverEntryPoint ( - ) - { - EFI_STATUS Status; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } - - // - // Install the Udp6DriverBinding and Udp6ComponentName protocols. -@@ -614,7 +621,7 @@ Udp6DriverEntryPoint ( - // Initialize the UDP random port. - // - mUdp6RandomPort = (UINT16)( -- ((UINT16)NetRandomInitSeed ()) % -+ ((UINT16)Random) % - UDP6_PORT_KNOWN + - UDP6_PORT_KNOWN - ); -diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c -index 91146b78..1adeda97 100644 ---- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c -+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c -@@ -2,7 +2,7 @@ - Functions implementation related with DHCPv4 for UefiPxeBc Driver. - - Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
-- -+ Copyright (c) Microsoft Corporation - SPDX-License-Identifier: BSD-2-Clause-Patent - - **/ -@@ -1381,6 +1381,12 @@ PxeBcDhcp4Discover ( - UINT8 VendorOptLen; - UINT32 Xid; - -+ Status = PseudoRandomU32 (&Xid); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - Mode = Private->PxeBc.Mode; - Dhcp4 = Private->Dhcp4; - Status = EFI_SUCCESS; -@@ -1471,7 +1477,6 @@ PxeBcDhcp4Discover ( - // - // Set fields of the token for the request packet. - // -- Xid = NET_RANDOM (NetRandomInitSeed ()); - Token.Packet->Dhcp4.Header.Xid = HTONL (Xid); - Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)((IsBCast) ? 0x8000 : 0x0)); - CopyMem (&Token.Packet->Dhcp4.Header.ClientAddr, &Private->StationIp, sizeof (EFI_IPv4_ADDRESS)); -diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c -index 1eb5987c..97de1e14 100644 ---- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c -+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c -@@ -2180,7 +2180,7 @@ PxeBcDhcp6Discover ( - UINTN ReadSize; - UINT16 OpCode; - UINT16 OpLen; -- UINT32 Xid; -+ UINT32 Random; - EFI_STATUS Status; - UINTN DiscoverLenNeeded; - -@@ -2198,6 +2198,12 @@ PxeBcDhcp6Discover ( - return EFI_DEVICE_ERROR; - } - -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "%a failed to generate random number: %r\n", __func__, Status)); -+ return Status; -+ } -+ - DiscoverLenNeeded = sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET); - Discover = AllocateZeroPool (DiscoverLenNeeded); - if (Discover == NULL) { -@@ -2207,8 +2213,7 @@ PxeBcDhcp6Discover ( - // - // Build the discover packet by the cached request packet before. - // -- Xid = NET_RANDOM (NetRandomInitSeed ()); -- Discover->TransactionId = HTONL (Xid); -+ Discover->TransactionId = HTONL (Random); - Discover->MessageType = Request->Dhcp6.Header.MessageType; - RequestOpt = Request->Dhcp6.Option; - DiscoverOpt = Discover->DhcpOptions; -diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c -index d84aca7e..8396ebf9 100644 ---- a/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c -+++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDriver.c -@@ -3,6 +3,7 @@ - - (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
- Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.
-+ Copyright (c) Microsoft Corporation - - SPDX-License-Identifier: BSD-2-Clause-Patent - -@@ -892,6 +893,13 @@ PxeBcCreateIp6Children ( - PXEBC_PRIVATE_PROTOCOL *Id; - EFI_SIMPLE_NETWORK_PROTOCOL *Snp; - UINTN Index; -+ UINT32 Random; -+ -+ Status = PseudoRandomU32 (&Random); -+ if (EFI_ERROR (Status)) { -+ DEBUG ((DEBUG_ERROR, "Failed to generate random number using EFI_RNG_PROTOCOL: %r\n", Status)); -+ return Status; -+ } - - if (Private->Ip6Nic != NULL) { - // -@@ -935,9 +943,9 @@ PxeBcCreateIp6Children ( - } - - // -- // Generate a random IAID for the Dhcp6 assigned address. -+ // Set a random IAID for the Dhcp6 assigned address. - // -- Private->IaId = NET_RANDOM (NetRandomInitSeed ()); -+ Private->IaId = Random; - if (Private->Snp != NULL) { - for (Index = 0; Index < Private->Snp->Mode->HwAddressSize; Index++) { - Private->IaId |= (Private->Snp->Mode->CurrentAddress.Addr[Index] << ((Index << 3) & 31)); --- -2.33.0 - diff --git a/0055-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236-Rela.patch b/0055-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236-Rela.patch new file mode 100644 index 0000000..a564c8a --- /dev/null +++ b/0055-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236-Rela.patch @@ -0,0 +1,87 @@ +From b95e87d6764eb59e0e0814da5f33c4900cab57d4 Mon Sep 17 00:00:00 2001 +From: ShenYage +Date: Fri, 28 Feb 2025 16:04:22 +0800 +Subject: [PATCH 1/2] NetworkPkg: TcpDxe: SECURITY PATCH CVE-2023-45236 Relared + Patch + +BUG: Tianocore's EDK2 TCP implementation generates ISNs using fixed +increments from a fixed base value and thus is uceptible to TCP session injection +and session hijack attacks. + +This commit is a patch for CVE-2023-45236. Generates ISNs using RngLib to get a high-quality random number. + +Signed-off-by: ShenYage +--- + NetworkPkg/TcpDxe/TcpDxe.inf | 1 + + NetworkPkg/TcpDxe/TcpMain.h | 1 + + NetworkPkg/TcpDxe/TcpMisc.c | 9 ++++++++- + NetworkPkg/TcpDxe/TcpTimer.c | 7 ++++++- + 4 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/NetworkPkg/TcpDxe/TcpDxe.inf b/NetworkPkg/TcpDxe/TcpDxe.inf +index c0acbdca..9281f908 100644 +--- a/NetworkPkg/TcpDxe/TcpDxe.inf ++++ b/NetworkPkg/TcpDxe/TcpDxe.inf +@@ -67,6 +67,7 @@ + DpcLib + NetLib + IpIoLib ++ RngLib + + + [Protocols] +diff --git a/NetworkPkg/TcpDxe/TcpMain.h b/NetworkPkg/TcpDxe/TcpMain.h +index c0c9b7f4..fc66c00e 100644 +--- a/NetworkPkg/TcpDxe/TcpMain.h ++++ b/NetworkPkg/TcpDxe/TcpMain.h +@@ -16,6 +16,7 @@ + #include + #include + #include ++#include + + #include "Socket.h" + #include "TcpProto.h" +diff --git a/NetworkPkg/TcpDxe/TcpMisc.c b/NetworkPkg/TcpDxe/TcpMisc.c +index c93212d4..b5e6120d 100644 +--- a/NetworkPkg/TcpDxe/TcpMisc.c ++++ b/NetworkPkg/TcpDxe/TcpMisc.c +@@ -516,7 +516,14 @@ TcpGetIss ( + VOID + ) + { +- mTcpGlobalIss += TCP_ISS_INCREMENT_1; ++ UINT32 RandomVal; ++ ++ if (GetRandomNumber32(&RandomVal)) { ++ mTcpGlobalIss += RandomVal; ++ } else { ++ mTcpGlobalIss += TCP_ISS_INCREMENT_1; ++ } ++ + return mTcpGlobalIss; + } + +diff --git a/NetworkPkg/TcpDxe/TcpTimer.c b/NetworkPkg/TcpDxe/TcpTimer.c +index 5d2e1249..5c2ba1a1 100644 +--- a/NetworkPkg/TcpDxe/TcpTimer.c ++++ b/NetworkPkg/TcpDxe/TcpTimer.c +@@ -481,9 +481,14 @@ TcpTickingDpc ( + LIST_ENTRY *Next; + TCP_CB *Tcb; + INT16 Index; ++ UINT32 RandomVal; + + mTcpTick++; +- mTcpGlobalIss += TCP_ISS_INCREMENT_2; ++ if (GetRandomNumber32(&RandomVal)) { ++ mTcpGlobalIss += RandomVal; ++ } else { ++ mTcpGlobalIss += TCP_ISS_INCREMENT_2; ++ } + + // + // Don't use LIST_FOR_EACH, which isn't delete safe. +-- +2.33.0 + diff --git a/0056-NetworkPkg-DxeNetLib-SECURITY-PATCH-CVE-2023-45237-R.patch b/0056-NetworkPkg-DxeNetLib-SECURITY-PATCH-CVE-2023-45237-R.patch new file mode 100644 index 0000000..feb9852 --- /dev/null +++ b/0056-NetworkPkg-DxeNetLib-SECURITY-PATCH-CVE-2023-45237-R.patch @@ -0,0 +1,67 @@ +From e0bdb75c67290d6851a4d2509fcfafaf9ef0e696 Mon Sep 17 00:00:00 2001 +From: ShenYage +Date: Fri, 28 Feb 2025 16:18:39 +0800 +Subject: [PATCH 2/2] NetworkPkg: DxeNetLib: SECURITY PATCH CVE-2023-45237 + Relared Patch + +This commit is a patch for CVE-2023-45237. Using RngLib to generate a stronger pseudoRandom number for NetRandomInitSeed(). + +Signed-off-by: ShenYage +--- + NetworkPkg/Library/DxeNetLib/DxeNetLib.c | 18 ++++++++++++------ + NetworkPkg/Library/DxeNetLib/DxeNetLib.inf | 1 + + 2 files changed, 13 insertions(+), 6 deletions(-) + +diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c +index fd4a9e15..d24038e8 100644 +--- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.c ++++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.c +@@ -31,6 +31,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + #include ++#include + + #define NIC_ITEM_CONFIG_SIZE (sizeof (NIC_IP4_CONFIG_INFO) + sizeof (EFI_IP4_ROUTE_TABLE) * MAX_IP4_CONFIG_IN_VARIABLE) + #define DEFAULT_ZERO_START ((UINTN) ~0) +@@ -902,14 +903,19 @@ NetRandomInitSeed ( + EFI_TIME Time; + UINT32 Seed; + UINT64 MonotonicCount; ++ UINT32 RandomVal; + +- gRT->GetTime (&Time, NULL); +- Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second); +- Seed ^= Time.Nanosecond; +- Seed ^= Time.Year << 7; ++ if (GetRandomNumber32(&RandomVal)) { ++ Seed = RandomVal; ++ } else { ++ gRT->GetTime (&Time, NULL); ++ Seed = (Time.Hour << 24 | Time.Day << 16 | Time.Minute << 8 | Time.Second); ++ Seed ^= Time.Nanosecond; ++ Seed ^= Time.Year << 7; + +- gBS->GetNextMonotonicCount (&MonotonicCount); +- Seed += (UINT32)MonotonicCount; ++ gBS->GetNextMonotonicCount (&MonotonicCount); ++ Seed += (UINT32)MonotonicCount; ++ } + + return Seed; + } +diff --git a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf +index 8145d256..ce90aa5e 100644 +--- a/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf ++++ b/NetworkPkg/Library/DxeNetLib/DxeNetLib.inf +@@ -43,6 +43,7 @@ + MemoryAllocationLib + DevicePathLib + PrintLib ++ RngLib + + + [Guids] +-- +2.33.0 + diff --git a/0056-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch b/0056-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch deleted file mode 100644 index 0579332..0000000 --- a/0056-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch +++ /dev/null @@ -1,823 +0,0 @@ -From bb6d7763998a29ac05144d382966fe9fd5b7ef78 Mon Sep 17 00:00:00 2001 -From: Doug Flick -Date: Wed, 8 May 2024 22:56:29 -0700 -Subject: [PATCH 2/2] 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 a44cfc4..00ebacb 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 f5d10c6..32cff88 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 1b30980..dc08f76 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 a7af01f..35ea55d 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 7b329be..63fd03a 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 c0c9b7f..dbc1da2 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 c93212d..753dec5 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 5d2e124..f45d4fb 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.33.0 - diff --git a/edk2.spec b/edk2.spec index 3600d48..d763ad3 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 18 +Release: 19 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -94,8 +94,8 @@ patch53: 0053-relax_edk2_gcc14.patch patch54: 0054-MdePkg-Fix-overflow-issue-in-BasePeCoffLib.patch # Fix CVE-2023-45236、CVE-2023-45237 -patch55: 0055-NetworkPkg-SECURITY-PATCH-CVE-2023-45237.patch -patch56: 0056-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236.patch +patch55: 0055-NetworkPkg-TcpDxe-SECURITY-PATCH-CVE-2023-45236-Rela.patch +patch56: 0056-NetworkPkg-DxeNetLib-SECURITY-PATCH-CVE-2023-45237-R.patch # Support Hygon CSV3 patch57: 0057-MdePkg-Add-StandardSignatureIsHygonGenuine-in-BaseCp.patch @@ -406,6 +406,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Sun Mar 9 2025 shenyage - 202308-19 +- fix bugs for CVE-2023-45236、CVE-2023-45237 + * Sun Feb 23 2025 huyu - 202308-18 - fix CVE-2024-13176、CVE-2024-4741、CVE-2023-5363 -- Gitee From b78a0b7ffcb491b3d34595a9532bdd975a4128b2 Mon Sep 17 00:00:00 2001 From: hy <941973499@qq.com> Date: Sun, 16 Mar 2025 17:44:16 +0800 Subject: [PATCH 3/5] Fix CVE-2024-4603 --- 0086-Check-DSA-parameters.patch | 198 ++++++++++++++++++++++++++++++++ edk2.spec | 8 +- 2 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 0086-Check-DSA-parameters.patch diff --git a/0086-Check-DSA-parameters.patch b/0086-Check-DSA-parameters.patch new file mode 100644 index 0000000..45eebbc --- /dev/null +++ b/0086-Check-DSA-parameters.patch @@ -0,0 +1,198 @@ +From 164f617509519076015b4ec63fb3e11cbcad3028 Mon Sep 17 00:00:00 2001 +From: hy <12444214+dhjgty@user.noreply.gitee.com> +Date: Sun, 16 Mar 2025 16:30:29 +0800 +Subject: [PATCH] Check DSA parameters for excessive sizes before validating + This avoids overly long computation of various validation checks. + +Fixes CVE-2024-4603 + +Reviewed-by: Paul Dale +Reviewed-by: Matt Caswell +Reviewed-by: Neil Horman +Reviewed-by: Shane Lontis +--- + .../Library/OpensslLib/openssl/CHANGES.md | 17 ++++++ + .../OpensslLib/openssl/crypto/dsa/dsa_check.c | 44 ++++++++++++-- + .../invalid/p10240_q256_too_big.pem | 57 +++++++++++++++++++ + 3 files changed, 114 insertions(+), 4 deletions(-) + create mode 100644 CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dsaparam_data/invalid/p10240_q256_too_big.pem + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/CHANGES.md b/CryptoPkg/Library/OpensslLib/openssl/CHANGES.md +index 0fb1eb1f..2209e0ce 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/CHANGES.md ++++ b/CryptoPkg/Library/OpensslLib/openssl/CHANGES.md +@@ -30,6 +30,23 @@ breaking changes, and mappings for the large list of deprecated functions. + + ### Changes between 3.0.8 and 3.0.9 [30 May 2023] + ++ * Fixed an issue where checking excessively long DSA keys or parameters may ++ be very slow. ++ ++ Applications that use the functions EVP_PKEY_param_check() or ++ EVP_PKEY_public_check() to check a DSA public key or DSA parameters may ++ experience long delays. Where the key or parameters that are being checked ++ have been obtained from an untrusted source this may lead to a Denial of ++ Service. ++ ++ To resolve this issue DSA keys larger than OPENSSL_DSA_MAX_MODULUS_BITS ++ will now fail the check immediately with a DSA_R_MODULUS_TOO_LARGE error ++ reason. ++ ++ ([CVE-2024-4603]) ++ ++ *Tomáš Mráz* ++ + * Mitigate for the time it takes for `OBJ_obj2txt` to translate gigantic + OBJECT IDENTIFIER sub-identifiers to canonical numeric text form. + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_check.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_check.c +index 7ee914a4..ed01ea8f 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_check.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/dsa/dsa_check.c +@@ -19,8 +19,34 @@ + #include "dsa_local.h" + #include "crypto/dsa.h" + ++static int dsa_precheck_params(const DSA *dsa, int *ret) ++ { ++ if (dsa->params.p == NULL || dsa->params.q == NULL) { ++ ERR_raise(ERR_LIB_DSA, DSA_R_BAD_FFC_PARAMETERS); ++ *ret = FFC_CHECK_INVALID_PQ; ++ return 0; ++ } ++ ++ if (BN_num_bits(dsa->params.p) > OPENSSL_DSA_MAX_MODULUS_BITS) { ++ ERR_raise(ERR_LIB_DSA, DSA_R_MODULUS_TOO_LARGE); ++ *ret = FFC_CHECK_INVALID_PQ; ++ return 0; ++ } ++ ++ if (BN_num_bits(dsa->params.q) >= BN_num_bits(dsa->params.p)) { ++ ERR_raise(ERR_LIB_DSA, DSA_R_BAD_Q_VALUE); ++ *ret = FFC_CHECK_INVALID_PQ; ++ return 0; ++ } ++ ++ return 1; ++ } ++ + int ossl_dsa_check_params(const DSA *dsa, int checktype, int *ret) + { ++ if (!dsa_precheck_params(dsa, ret)) ++ return 0; ++ + if (checktype == OSSL_KEYMGMT_VALIDATE_QUICK_CHECK) + return ossl_ffc_params_simple_validate(dsa->libctx, &dsa->params, + FFC_PARAM_TYPE_DSA, ret); +@@ -39,6 +65,9 @@ int ossl_dsa_check_params(const DSA *dsa, int checktype, int *ret) + */ + int ossl_dsa_check_pub_key(const DSA *dsa, const BIGNUM *pub_key, int *ret) + { ++ if (!dsa_precheck_params(dsa, ret)) ++ return 0; ++ + return ossl_ffc_validate_public_key(&dsa->params, pub_key, ret); + } + +@@ -49,6 +78,9 @@ int ossl_dsa_check_pub_key(const DSA *dsa, const BIGNUM *pub_key, int *ret) + */ + int ossl_dsa_check_pub_key_partial(const DSA *dsa, const BIGNUM *pub_key, int *ret) + { ++ if (!dsa_precheck_params(dsa, ret)) ++ return 0; ++ + return ossl_ffc_validate_public_key_partial(&dsa->params, pub_key, ret); + } + +@@ -56,8 +88,10 @@ int ossl_dsa_check_priv_key(const DSA *dsa, const BIGNUM *priv_key, int *ret) + { + *ret = 0; + +- return (dsa->params.q != NULL +- && ossl_ffc_validate_private_key(dsa->params.q, priv_key, ret)); ++ if (!dsa_precheck_params(dsa, ret)) ++ return 0; ++ ++ return ossl_ffc_validate_private_key(dsa->params.q, priv_key, ret); + } + + /* +@@ -70,8 +104,10 @@ int ossl_dsa_check_pairwise(const DSA *dsa) + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL; + +- if (dsa->params.p == NULL +- || dsa->params.g == NULL ++ if (!dsa_precheck_params(dsa, &ret)) ++ return 0; ++ ++ if (dsa->params.g == NULL + || dsa->priv_key == NULL + || dsa->pub_key == NULL) + return 0; +diff --git a/CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dsaparam_data/invalid/p10240_q256_too_big.pem b/CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dsaparam_data/invalid/p10240_q256_too_big.pem +new file mode 100644 +index 00000000..162be8a8 +--- /dev/null ++++ b/CryptoPkg/Library/OpensslLib/openssl/test/recipes/15-test_dsaparam_data/invalid/p10240_q256_too_big.pem +@@ -0,0 +1,57 @@ ++-----BEGIN DSA PARAMETERS----- ++ MIIKLAKCBQEAym47LzPFZdbz16WvjczLKuzLtsP8yRk/exxL4bBthJhP1qOwctja ++ p1586SF7gDxCMn7yWVEYdfRbFefGoq0gj1XOE917XqlbnkmZhMgxut2KbNJo/xil ++ XNFUjGvKs3F413U9rAodC8f07cWHP1iTcWL+vPe6u2yilKWYYfnLWHQH+Z6aPrrF ++ x/R08LI6DZ6nEsIo+hxaQnEtx+iqNTJC6Q1RIjWDqxQkFVTkJ0Y7miRDXmRdneWk ++ oLrMZRpaXr5l5tSjEghh1pBgJcdyOv0lh4dlDy/alAiqE2Qlb667yHl6A9dDPlpW ++ dAntpffy4LwOxfbuEhISvKjjQoBwIvYE4TBPqL0Q6bC6HgQ4+tqd9b44pQjdIQjb ++ Xcjc6azheITSnPEex3OdKtKoQeRq01qCeLBpMXu1c+CTf4ApKArZvT3vZSg0hM1O ++ pR71bRZrEEegDj0LH2HCgI5W6H3blOS9A0kUTddCoQXr2lsVdiPtRbPKH1gcd9FQ ++ P8cGrvbakpTiC0dCczOMDaCteM1QNILlkM7ZoV6VghsKvDnFPxFsiIr5GgjasXP5 ++ hhbn3g7sDoq1LiTEo+IKQY28pBWx7etSOSRuXW/spnvCkivZla7lSEGljoy9QlQ2 ++ UZmsEQI9G3YyzgpxHvKZBK1CiZVTywdYKTZ4TYCxvqzhYhjv2bqbpjI12HRFLojB ++ koyEmMSp53lldCzp158PrIanqSp2rksMR8SmmCL3FwfAp2OjqFMEglG9DT8x0WaN ++ TLSkjGC6t2csMte7WyU1ekNoFDKfMjDSAz0+xIx21DEmZtYqFOg1DNPK1xYLS0pl ++ RSMRRkJVN2mk/G7/1oxlB8Wb9wgi3GKUqqCYT11SnBjzq0NdoJ3E4GMedp5Lx3AZ ++ 4mFuRPUd4iV86tE0XDSHSFE7Y3ZkrOjD7Q/26/L53L/UH5z4HW6CHP5os7QERJjg ++ c1S3x87wXWo9QXbB9b2xmf+c+aWwAAr1cviw38tru58jF3/IGyduj9H8claKQqBG ++ cIOUF4aNe1hK2K3ArAOApUxr4KE+tCvrltRfiTmVFip0g9Jt1CPY3Zu7Bd4Z2ZkE ++ DtSztpwa49HrWF5E9xpquvBL2U8jQ68E7Xd8Wp4orI/TIChriamBmdkgRz3H2LvN ++ Ozb6+hsnEGrz3sp2RVAToSqA9ysa6nHZdfufPNtMEbQdO/k1ehmGRb0ljBRsO6b2 ++ rsG2eYuC8tg8eCrIkua0TGRI7g6a4K32AJdzaX6NsISaaIW+OYJuoDSscvD3oOg8 ++ PPEhU+zM7xJskTA+jxvPlikKx8V7MNHOCQECldJlUBwzJvqp40JvwfnDsF+8VYwd ++ UaiieR3pzMzyTjpReXRmZbnRPusRcsVzxb2OhB79wmuy4UPjjQBX+7eD0rs8xxvW ++ 5a5q1Cjq4AvbwmmcA/wDrHDOjcbD/zodad2O1QtBWa/R4xyWea4zKsflgACE1zY9 ++ wW2br7+YQFekcrXkkkEzgxd6zxv8KVEDpXRZjmAM1cI5LvkoN64To4GedN8Qe/G7 ++ R9SZh9gnS17PTP64hK+aYqhFafMdu87q/+qLfxaSux727qE5hiW01u4nnWhACf9s ++ xuOozowKqxZxkolMIyZv6Lddwy1Zv5qjCyd0DvM/1skpXWkb9kfabYC+OhjsjVhs ++ 0Ktfs6a5B3eixiw5x94hhIcTEcS4hmvhGUL72FiTca6ZeSERTKmNBy8CIQC9/ZUN ++ uU/V5JTcnYyUGHzm7+XcZBjyGBagBj9rCmW3SQKCBQAJ/k9rb39f1cO+/3XDEMjy ++ 9bIEXSuS48g5RAc1UGd5nrrBQwuDxGWFyz0yvAY7LgyidZuJS21+MAp9EY7AOMmx ++ TDttifNaBJYt4GZ8of166PcqTKkHQwq5uBpxeSDv/ZE8YbYfaCtLTcUC8KlO+l36 ++ gjJHSkdkflSsGy1yObSNDQDfVAAwQs//TjDMnuEtvlNXZllsTvFFBceXVETn10K2 ++ ZMmdSIJNfLnjReUKEN6PfeGqv7F4xoyGwUybEfRE4u5RmXrqCODaIjY3SNMrOq8B ++ R3Ata/cCozsM1jIdIW2z+OybDJH+BYsYm2nkSZQjZS6javTYClLrntEKG/hAQwL8 ++ F16YLOQXpHhgiAaWnTZzANtLppB2+5qCVy5ElzKongOwT8JTjTFXOaRnqe/ngm9W ++ SSbrxfDaoWUOyK9XD8Cydzpv3n4Y8nWNGayi7/yAFCU36Ri040ufgv/TZLuKacnl ++ +3ga3ZUpRlSigzx0kb1+KjTSWeQ8vE/psdWjvBukVEbzdUauMLyRLo/6znSVvvPX ++ UGhviThE5uhrsUg+wEPFINriSHfF7JDKVhDcJnLBdaXvfN52pkF/naLBF5Rt3Gvq ++ fjCxjx0Sy9Lag1hDN4dor7dzuO7wmwOS01DJW1PtNLuuH0Bbqh1kYSaQkmyXBZWX ++ qo8K3nkoDM0niOtJJubOhTNrGmSaZpNXkK3Mcy9rBbdvEs5O0Jmqaax/eOdU0Yot ++ B3lX+3ddOseT2ZEFjzObqTtkWuFBeBxuYNcRTsu3qMdIBsEb8URQdsTtjoIja2fK ++ hreVgjK36GW70KXEl8V/vq5qjQulmqkBEjmilcDuiREKqQuyeagUOnhQaBplqVco ++ 4xznh5DMBMRbpGb5lHxKv4cPNi+uNAJ5i98zWUM1JRt6aXnRCuWcll1z8fRZ+5kD ++ vK9FaZU3VRMK/eknEG49cGr8OuJ6ZRSaC+tKwV1y+amkSZpKPWnk2bUnQI3ApJv3 ++ k1e1EToeECpMUkLMDgNbpKBoz4nqMEvAAlYgw9xKNbLlQlahqTVEAmaJHh4yDMDy ++ i7IZ9Wrn47IGoR7s3cvhDHUpRPeW4nsmgzj+tf5EAxemI61STZJTTWo0iaPGJxct ++ 9nhOOhw1I38Mvm4vkAbFH7YJ0B6QrjjYL2MbOTp5JiIh4vdOeWwNo9/y4ffyaN5+ ++ ADpxuuIAmcbdr6GPOhkOFFixRJa0B2eP1i032HESlLs8RB9oYtdTXdXQotnIgJGd ++ Y8tSKOa1zjzeLHn3AVpRZTUW++/BxmApV3GKIeG8fsUjg/df0QRrBcdC/1uccdaG ++ KKlAOwlywVn5jUlwHkTmDiTM9w5AqVVGHZ2b+4ZgQW8jnPKN0SrKf6U555D+zp7E ++ x4uXoE8ojN9y8m8UKf0cTLnujH2XgZorjPfuMOt5VZEhQFMS2QaljSeni5CJJ8gk ++ XtztNqfBlAtWR4V5iAHeQOfIB2YaOy8GESda89tyKraKeaez41VblpTVHTeq9IIF ++ YB4cQA2PfuNaGVRGLMAgT3Dvl+mxxxeJyxnGAiUcETU/jJJt9QombiuszBlYGQ5d ++ ELOSm/eQSRARV9zNSt5jaQlMSjMBqenIEM09BzYqa7jDwqoztFxNdO8bcuQPuKwa ++ 4z3bBZ1yYm63WFdNbQqqGEwc0OYmqg1raJ0zltgHyjFyw8IGu4g/wETs+nVQcH7D ++ vKuje86bePD6kD/LH3wmkA== ++ -----END DSA PARAMETERS----- +-- +2.33.0 + diff --git a/edk2.spec b/edk2.spec index d763ad3..bd6b69a 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 19 +Release: 20 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -137,6 +137,9 @@ patch83: 0083-Fix-timing-side-channel-CVE-2024-13176.patch patch84: 0084-Free-the-read-buffers-CVE-2024-4741.patch patch85: 0085-Process-key-length-CVE-2023-5363.patch +# Fix CVE-2024-4603 +patch86: 0086-Check-DSA-parameters.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -406,6 +409,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Sun Mar 16 2025 huyu - 202308-20 +- fix CVE-2024-4603 + * Sun Mar 9 2025 shenyage - 202308-19 - fix bugs for CVE-2023-45236、CVE-2023-45237 -- Gitee From 8a57ffe89f881f0fd86324da23fdb0a98472d3be Mon Sep 17 00:00:00 2001 From: hy <941973499@qq.com> Date: Fri, 28 Mar 2025 23:21:22 +0800 Subject: [PATCH 4/5] Fix CVE-2024-9143 --- ...rden-BN_GF2m_poly2arr-against-misuse.patch | 187 ++++++++++++++++++ edk2.spec | 8 +- 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 0087-Harden-BN_GF2m_poly2arr-against-misuse.patch diff --git a/0087-Harden-BN_GF2m_poly2arr-against-misuse.patch b/0087-Harden-BN_GF2m_poly2arr-against-misuse.patch new file mode 100644 index 0000000..037d692 --- /dev/null +++ b/0087-Harden-BN_GF2m_poly2arr-against-misuse.patch @@ -0,0 +1,187 @@ +From 2a0fa58af18f2ab5435ee2cefa6a02cacfb18818 Mon Sep 17 00:00:00 2001 +From: hy <941973499@qq.com> +Date: Fri, 28 Mar 2025 22:48:57 +0800 +Subject: [PATCH] Harden BN_GF2m_poly2arr against misuse. The + BN_GF2m_poly2arr() function converts characteristic-2 field (GF_{2^m}) Galois + polynomials from a representation as a BIGNUM bitmask, to a compact array + with just the exponents of the non-zero terms. + +These polynomials are then used in BN_GF2m_mod_arr() to perform modular +reduction. A precondition of calling BN_GF2m_mod_arr() is that the +polynomial must have a non-zero constant term (i.e. the array has `0` as +its final element). + +Internally, callers of BN_GF2m_poly2arr() did not verify that +precondition, and binary EC curve parameters with an invalid polynomial +could lead to out of bounds memory reads and writes in BN_GF2m_mod_arr(). + +The precondition is always true for polynomials that arise from the +standard form of EC parameters for characteristic-two fields (X9.62). +See the "Finite Field Identification" section of: + + https://www.itu.int/ITU-T/formal-language/itu-t/x/x894/2018-cor1/ANSI-X9-62.html + +The OpenSSL GF(2^m) code supports only the trinomial and pentanomial +basis X9.62 forms. + +This commit updates BN_GF2m_poly2arr() to return `0` (failure) when +the constant term is zero (i.e. the input bitmask BIGNUM is not odd). + +Additionally, the return value is made unambiguous when there is not +enough space to also pad the array with a final `-1` sentinel value. +The return value is now always the number of elements (including the +final `-1`) that would be filled when the output array is sufficiently +large. Previously the same count was returned both when the array has +just enough room for the final `-1` and when it had only enough space +for non-sentinel values. + +Finally, BN_GF2m_poly2arr() is updated to reject polynomials whose +degree exceeds `OPENSSL_ECC_MAX_FIELD_BITS`, this guards against +CPU exhausition attacks via excessively large inputs. + +The above issues do not arise in processing X.509 certificates. These +generally have EC keys from "named curves", and RFC5840 (Section 2.1.1) +disallows explicit EC parameters. The TLS code in OpenSSL enforces this +constraint only after the certificate is decoded, but, even if explicit +parameters are specified, they are in X9.62 form, which cannot represent +problem values as noted above. + +Initially reported as oss-fuzz issue 71623. +--- + .../OpensslLib/openssl/crypto/bn/bn_gf2m.c | 28 +++++++--- + .../openssl/test/ec_internal_test.c | 51 +++++++++++++++++++ + 2 files changed, 71 insertions(+), 8 deletions(-) + +diff --git a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c +index 304c2ea0..65e9958c 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/crypto/bn/bn_gf2m.c +@@ -15,6 +15,7 @@ + #include "bn_local.h" + + #ifndef OPENSSL_NO_EC2M ++# include + + /* + * Maximum number of iterations before BN_GF2m_mod_solve_quad_arr should +@@ -1134,16 +1135,26 @@ int BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + /* + * Convert the bit-string representation of a polynomial ( \sum_{i=0}^n a_i * + * x^i) into an array of integers corresponding to the bits with non-zero +- * coefficient. Array is terminated with -1. Up to max elements of the array +- * will be filled. Return value is total number of array elements that would +- * be filled if array was large enough. ++ * coefficient. The array is intended to be suitable for use with ++ * `BN_GF2m_mod_arr()`, and so the constant term of the polynomial must not be ++ * zero. This translates to a requirement that the input BIGNUM `a` is odd. ++ * ++ * Given sufficient room, the array is terminated with -1. Up to max elements ++ * of the array will be filled. ++ * ++ * The return value is total number of array elements that would be filled if ++ * array was large enough, including the terminating `-1`. It is `0` when `a` ++ * is not odd or the constant term is zero contrary to requirement. ++ * ++ * The return value is also `0` when the leading exponent exceeds ++ * `OPENSSL_ECC_MAX_FIELD_BITS`, this guards against CPU exhaustion attacks, + */ + int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max) + { + int i, j, k = 0; + BN_ULONG mask; + +- if (BN_is_zero(a)) ++ if (!BN_is_odd(a)) + return 0; + + for (i = a->top - 1; i >= 0; i--) { +@@ -1161,12 +1172,13 @@ int BN_GF2m_poly2arr(const BIGNUM *a, int p[], int max) + } + } + +- if (k < max) { ++ if (k > 0 && p[0] > OPENSSL_ECC_MAX_FIELD_BITS) ++ return 0; ++ ++ if (k < max) + p[k] = -1; +- k++; +- } + +- return k; ++ return k + 1; + } + + /* +diff --git a/CryptoPkg/Library/OpensslLib/openssl/test/ec_internal_test.c b/CryptoPkg/Library/OpensslLib/openssl/test/ec_internal_test.c +index 8c2cd056..484cbb2a 100644 +--- a/CryptoPkg/Library/OpensslLib/openssl/test/ec_internal_test.c ++++ b/CryptoPkg/Library/OpensslLib/openssl/test/ec_internal_test.c +@@ -155,6 +155,56 @@ static int field_tests_ecp_mont(void) + } + + #ifndef OPENSSL_NO_EC2M ++/* Test that decoding of invalid GF2m field parameters fails. */ ++ static int ec2m_field_sanity(void) ++ { ++ int ret = 0; ++ BN_CTX *ctx = BN_CTX_new(); ++ BIGNUM *p, *a, *b; ++ EC_GROUP *group1 = NULL, *group2 = NULL, *group3 = NULL; ++ ++ TEST_info("Testing GF2m hardening\n"); ++ ++ BN_CTX_start(ctx); ++ p = BN_CTX_get(ctx); ++ a = BN_CTX_get(ctx); ++ if (!TEST_ptr(b = BN_CTX_get(ctx)) ++ || !TEST_true(BN_one(a)) ++ || !TEST_true(BN_one(b))) ++ goto out; ++ ++ /* Even pentanomial value should be rejected */ ++ if (!TEST_true(BN_set_word(p, 0xf2))) ++ goto out; ++ if (!TEST_ptr_null(group1 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("Zero constant term accepted in GF2m polynomial"); ++ ++ /* Odd hexanomial should also be rejected */ ++ if (!TEST_true(BN_set_word(p, 0xf3))) ++ goto out; ++ if (!TEST_ptr_null(group2 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("Hexanomial accepted as GF2m polynomial"); ++ ++ /* Excessive polynomial degree should also be rejected */ ++ if (!TEST_true(BN_set_word(p, 0x71)) ++ || !TEST_true(BN_set_bit(p, OPENSSL_ECC_MAX_FIELD_BITS + 1))) ++ goto out; ++ if (!TEST_ptr_null(group3 = EC_GROUP_new_curve_GF2m(p, a, b, ctx))) ++ TEST_error("GF2m polynomial degree > %d accepted", ++ OPENSSL_ECC_MAX_FIELD_BITS); ++ ++ ret = group1 == NULL && group2 == NULL && group3 == NULL; ++ ++ out: ++ EC_GROUP_free(group1); ++ EC_GROUP_free(group2); ++ EC_GROUP_free(group3); ++ BN_CTX_end(ctx); ++ BN_CTX_free(ctx); ++ ++ return ret; ++ } ++ + /* test EC_GF2m_simple_method directly */ + static int field_tests_ec2_simple(void) + { +@@ -443,6 +493,7 @@ int setup_tests(void) + ADD_TEST(field_tests_ecp_simple); + ADD_TEST(field_tests_ecp_mont); + #ifndef OPENSSL_NO_EC2M ++ ADD_TEST(ec2m_field_sanity); + ADD_TEST(field_tests_ec2_simple); + #endif + ADD_ALL_TESTS(field_tests_default, crv_len); +-- +2.33.0 + diff --git a/edk2.spec b/edk2.spec index bd6b69a..a5eb491 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 20 +Release: 21 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -140,6 +140,9 @@ patch85: 0085-Process-key-length-CVE-2023-5363.patch # Fix CVE-2024-4603 patch86: 0086-Check-DSA-parameters.patch +# Fix CVE-2024-9143 +patch87: 0087-Harden-BN_GF2m_poly2arr-against-misuse.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -409,6 +412,9 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Fri Mar 28 2025 huyu - 202308-21 +- fix CVE-2024-9143 + * Sun Mar 16 2025 huyu - 202308-20 - fix CVE-2024-4603 -- Gitee From 3d9e4a3a57a875a30ffd056764590f3f7b221a4f Mon Sep 17 00:00:00 2001 From: gongchangsui Date: Sat, 29 Mar 2025 00:49:00 -0400 Subject: [PATCH 5/5] Support UEFI boot for CVM with measured boot capabilities Signed-off-by: gongchangsui --- ...tPkg-IoMMU-driver-to-DMA-from-Realms.patch | 1061 +++++++++++++++++ ...ibrary-for-Arm-CCA-initialisation-in.patch | 256 ++++ ...library-for-Arm-CCA-helper-functions.patch | 369 ++++++ ...e-an-interface-to-configure-MMIO-reg.patch | 59 + ...duce-Realm-Aperture-Management-Proto.patch | 821 +++++++++++++ ...rtQemu-Implement-ArmMonitorLib-for-Q.patch | 202 ++++ ...Add-a-NULL-implementation-of-ArmCcaC.patch | 71 ++ ...rm-Arm-CCA-initialisation-in-the-Pei.patch | 41 + ...rtQemu-Dispatch-variable-store-emula.patch | 187 +++ ...-SetMemoryProtectionAttribute-for-Re.patch | 84 ++ ...ashQemuLib-Parse-device-tree-earlier.patch | 218 ++++ 0099-OvmfPkg-Enforce-to-use-MMIO.patch | 183 +++ 0100-clean-code-for-virtCCA-support.patch | 266 +++++ ...pdate-ArmCcaLib-to-support-RSI-calls.patch | 456 +++++++ ...-for-Arm-CCA-and-SHA256-is-supported.patch | 285 +++++ ...o-produce-EFI_CC_MEASUREMENT_PROTOCO.patch | 430 +++++++ ...hLogExtendEvent-and-CcaMapPcrToMrInd.patch | 726 +++++++++++ ...EventLog-of-EFI_CC_MEASUREMENT_PROTO.patch | 381 ++++++ ...-eventlog-and-install-its-ACPI-table.patch | 342 ++++++ ...C-measurement-for-EFI-boot-variables.patch | 612 ++++++++++ ...measurement-for-EFI-secure-variables.patch | 244 ++++ ...ble-CC-measurement-for-PE-COFF-image.patch | 530 ++++++++ edk2.spec | 34 +- 23 files changed, 7857 insertions(+), 1 deletion(-) create mode 100644 0088-ArmVirtPkg-IoMMU-driver-to-DMA-from-Realms.patch create mode 100644 0089-ArmVirtPkg-Add-library-for-Arm-CCA-initialisation-in.patch create mode 100644 0090-ArmVirtPkg-Add-library-for-Arm-CCA-helper-functions.patch create mode 100644 0091-ArmVirtPkg-Define-an-interface-to-configure-MMIO-reg.patch create mode 100644 0092-ArmVirtPkg-Introduce-Realm-Aperture-Management-Proto.patch create mode 100644 0093-ArmVirtPkg-ArmVirtQemu-Implement-ArmMonitorLib-for-Q.patch create mode 100644 0094-ArmVirtPkg-Qemu-Add-a-NULL-implementation-of-ArmCcaC.patch create mode 100644 0095-ArmVirtPkg-Perform-Arm-CCA-initialisation-in-the-Pei.patch create mode 100644 0096-ArmVirtPkg-ArmVirtQemu-Dispatch-variable-store-emula.patch create mode 100644 0097-ArmPkg-Introduce-SetMemoryProtectionAttribute-for-Re.patch create mode 100644 0098-OvmfPkg-FdtNorFlashQemuLib-Parse-device-tree-earlier.patch create mode 100644 0099-OvmfPkg-Enforce-to-use-MMIO.patch create mode 100644 0100-clean-code-for-virtCCA-support.patch create mode 100644 0101-update-ArmCcaLib-to-support-RSI-calls.patch create mode 100644 0102-add-HashLib-for-Arm-CCA-and-SHA256-is-supported.patch create mode 100644 0103-add-CcaTcg2Dxe-to-produce-EFI_CC_MEASUREMENT_PROTOCO.patch create mode 100644 0104-implement-CcaHashLogExtendEvent-and-CcaMapPcrToMrInd.patch create mode 100644 0105-implement-CcaGetEventLog-of-EFI_CC_MEASUREMENT_PROTO.patch create mode 100644 0106-setup-CC-eventlog-and-install-its-ACPI-table.patch create mode 100644 0107-enable-CC-measurement-for-EFI-boot-variables.patch create mode 100644 0108-enable-CC-measurement-for-EFI-secure-variables.patch create mode 100644 0109-enable-CC-measurement-for-PE-COFF-image.patch diff --git a/0088-ArmVirtPkg-IoMMU-driver-to-DMA-from-Realms.patch b/0088-ArmVirtPkg-IoMMU-driver-to-DMA-from-Realms.patch new file mode 100644 index 0000000..82176d0 --- /dev/null +++ b/0088-ArmVirtPkg-IoMMU-driver-to-DMA-from-Realms.patch @@ -0,0 +1,1061 @@ +From 0307d871c146b4b8f04f08beeefcd0164fac9dca Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:37:42 +0800 +Subject: [PATCH 01/22] ArmVirtPkg: IoMMU driver to DMA from Realms + +On Arm CCA systems the access to pages inside the Realm is protected. + +However, software executing in a Realm needs to interact with the +external world. This may be done using para virtualisation of the +disk, network interfaces, etc. For this to work the buffers in the +Realm need to be shared with the Host. The sharing and management +of the Realm buffers is done by the Realm Aperture Management +Protocol, which invokes the necessary Realm Service Interfaces +to transition the buffers from Protected IPA to Unprotected IPA. + +The ArmCcaIoMmu driver provides the necessary hooks so that DMA +operations can be performed by bouncing buffers using pages shared +with the Host. It uses the Realm Aperture Management protocol to +share the buffers with the Host. + +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/9faad0381b93084db12d23adff26781170b99843 +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c | 813 +++++++++++++++++++++++++++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h | 66 +++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c | 60 ++ + ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf | 45 ++ + ArmVirtPkg/ArmVirtQemu.fdf | 5 + + 5 files changed, 989 insertions(+) + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c + create mode 100644 ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c +new file mode 100644 +index 0000000..9b664b1 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.c +@@ -0,0 +1,813 @@ ++/** @file ++ The protocol provides support to allocate, free, map and umap a DMA buffer ++ for bus master (e.g PciHostBridge). When the execution context is a Realm, ++ the DMA operations must be performed on buffers that are shared with the Host. ++ Hence the RAMP protocol is used to manage the sharing of the DMA buffers or ++ in some cases to bounce the buffers. ++ ++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ Copyright (c) 2017, Intel Corporation. All rights reserved.
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include "ArmCcaIoMmu.h" ++ ++/** List of the MAP_INFO structures that have been set up by IoMmuMap() and not ++ yet torn down by IoMmuUnmap(). The list represents the full set of mappings ++ currently in effect. ++*/ ++STATIC LIST_ENTRY mMapInfos = INITIALIZE_LIST_HEAD_VARIABLE (mMapInfos); ++ ++#if !defined (MDEPKG_NDEBUG) ++ ++/** ASCII names for EDKII_IOMMU_OPERATION constants, for debug logging. ++*/ ++STATIC CONST CHAR8 *CONST ++mBusMasterOperationName[EdkiiIoMmuOperationMaximum] = { ++ "Read", ++ "Write", ++ "CommonBuffer", ++ "Read64", ++ "Write64", ++ "CommonBuffer64" ++}; ++#endif ++ ++/** Pointer to the Realm Aperture Management Protocol ++*/ ++extern EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL *mRamp; ++ ++/** ++ Given the host address find a mapping node in the linked list. ++ ++ @param [in] HostAddress Host address. ++ ++ @return Pointer to the MapInfo node if found, otherwise NULL. ++**/ ++STATIC ++MAP_INFO * ++EFIAPI ++FindMappingByHostAddress ( ++ IN VOID *HostAddress ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ MAP_INFO *MapInfo; ++ ++ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) { ++ NextNode = GetNextNode (&mMapInfos, Node); ++ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG); ++ if (MapInfo->HostAddress == HostAddress) { ++ return MapInfo; ++ } ++ } ++ ++ return NULL; ++} ++ ++/** ++ Map a shared buffer ++ ++ @param [in] Operation IoMMU operation to perform. ++ @param [in] HostAddress Pointer to the Host buffer. ++ @param [in] NumberOfBytes Number of bytes to map. ++ @param [in] BbAddress Bounce buffer address. ++ @param [in] BbPages Number of pages covering the bounce buffer. ++ @param [out] Mapping Pointer to the MapInfo node. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. ++**/ ++STATIC ++EFI_STATUS ++MapSharedBuffer ( ++ IN EDKII_IOMMU_OPERATION Operation, ++ IN VOID *HostAddress, ++ IN UINTN NumberOfBytes, ++ IN EFI_PHYSICAL_ADDRESS BbAddress, ++ IN UINTN BbPages, ++ OUT MAP_INFO **Mapping ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ ++ if (BbPages != EFI_SIZE_TO_PAGES (NumberOfBytes)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is ++ // called later. ++ MapInfo = AllocateZeroPool (sizeof (MAP_INFO)); ++ if (MapInfo == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ InitializeListHead (&MapInfo->Link); ++ ++ // Initialize the MAP_INFO structure, except the NonParAddress field ++ MapInfo->Signature = MAP_INFO_SIG; ++ MapInfo->Operation = Operation; ++ MapInfo->NumberOfBytes = NumberOfBytes; ++ MapInfo->NumberOfPages = BbPages; ++ MapInfo->HostAddress = HostAddress; ++ MapInfo->BbAddress = BbAddress; ++ ++ // Open aperture here ++ Status = mRamp->OpenAperture ( ++ BbAddress, ++ BbPages, ++ &MapInfo->ApertureRef ++ ); ++ ++ if (EFI_ERROR (Status)) { ++ goto FreeMapInfo; ++ } ++ ++ // Track all MAP_INFO structures. ++ InsertHeadList (&mMapInfos, &MapInfo->Link); ++ *Mapping = MapInfo; ++ return Status; ++ ++FreeMapInfo: ++ FreePool (MapInfo); ++ return Status; ++} ++ ++/** ++ Unmap a shared buffer. ++ ++ @param [in] MapInfo Pointer to the MapInfo node. ++ @param [in] MemoryMapLocked The function is executing on the stack of ++ gBS->ExitBootServices(); changes to the UEFI ++ memory map are forbidden. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++UnMapSharedBuffer ( ++ IN MAP_INFO *MapInfo, ++ IN BOOLEAN MemoryMapLocked ++ ) ++{ ++ EFI_STATUS Status; ++ ++ if (MapInfo == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: HostAddress = 0x%p, BbAddress = 0x%p\n", ++ __func__, ++ MapInfo->HostAddress, ++ MapInfo->BbAddress ++ )); ++ Status = mRamp->CloseAperture (MapInfo->ApertureRef); ++ if (EFI_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "Failed to close aperture. Status = %r\n", ++ Status ++ )); ++ } ++ ++ RemoveEntryList (&MapInfo->Link); ++ ++ if (!MemoryMapLocked) { ++ FreePool (MapInfo); ++ } ++ ++ return Status; ++} ++ ++/** ++ Provides the controller-specific addresses required to access system memory ++ from a DMA bus master. On guest Realms, the DMA operations must be performed ++ on shared buffer hence we allocate a bounce buffer to map the HostAddress to ++ a DeviceAddress. The Realm Aperture Management protocol is then involved to ++ open the aperture for sharing the buffer pages with the Host OS. ++ ++ @param This The protocol instance pointer. ++ @param Operation Indicates if the bus master is going to read or ++ write to system memory. ++ @param HostAddress The system memory address to map to the PCI ++ controller. ++ @param NumberOfBytes On input the number of bytes to map. On output ++ the number of bytes that were mapped. ++ @param DeviceAddress The resulting map address for the bus master ++ PCI controller to use to access the hosts ++ HostAddress. ++ @param Mapping A resulting value to pass to Unmap(). ++ ++ @retval EFI_SUCCESS The range was mapped for the returned ++ NumberOfBytes. ++ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common ++ buffer. ++ @retval EFI_INVALID_PARAMETER One or more parameters are invalid. ++ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a ++ lack of resources. ++ @retval EFI_DEVICE_ERROR The system hardware could not map the requested ++ address. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuMap ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EDKII_IOMMU_OPERATION Operation, ++ IN VOID *HostAddress, ++ IN OUT UINTN *NumberOfBytes, ++ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress, ++ OUT VOID **Mapping ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ UINTN Pages; ++ EFI_ALLOCATE_TYPE AllocateType; ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: Operation=%a Host=0x%p Bytes=0x%lx\n", ++ __func__, ++ ((Operation >= 0 && ++ Operation < ARRAY_SIZE (mBusMasterOperationName)) ? ++ mBusMasterOperationName[Operation] : ++ "Invalid"), ++ HostAddress, ++ (UINT64)((NumberOfBytes == NULL) ? 0 : *NumberOfBytes) ++ )); ++ ++ if ((HostAddress == NULL) || ++ (NumberOfBytes == NULL) || ++ (DeviceAddress == NULL) || ++ (Mapping == NULL) || ++ (Operation >= EdkiiIoMmuOperationMaximum) || ++ (Operation < EdkiiIoMmuOperationBusMasterRead)) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = MAX_ADDRESS; ++ Pages = EFI_SIZE_TO_PAGES (*NumberOfBytes); ++ AllocateType = AllocateAnyPages; ++ switch (Operation) { ++ // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer ++ // is necessary as the original buffer may not meet the page start/end and ++ // page size alignment requirements. Also we need to consider the case where ++ // the original buffer crosses the 4GB limit. ++ case EdkiiIoMmuOperationBusMasterRead: ++ case EdkiiIoMmuOperationBusMasterWrite: ++ BbAddress = BASE_4GB - 1; ++ AllocateType = AllocateMaxAddress; ++ // fall through ++ case EdkiiIoMmuOperationBusMasterRead64: ++ case EdkiiIoMmuOperationBusMasterWrite64: ++ // Allocate a bounce buffer. ++ Status = gBS->AllocatePages ( ++ AllocateType, ++ EfiBootServicesData, ++ Pages, ++ &BbAddress ++ ); ++ if (EFI_ERROR (Status)) { ++ goto Failed; ++ } ++ ++ // Open aperture here ++ Status = MapSharedBuffer ( ++ Operation, ++ HostAddress, ++ *NumberOfBytes, ++ BbAddress, ++ Pages, ++ &MapInfo ++ ); ++ if (EFI_ERROR (Status)) { ++ goto FreeBounceBuffer; ++ } ++ ++ break; ++ ++ // For BusMasterCommonBuffer[64] operations, the buffer is already allocated ++ // and mapped in a call to AllocateBuffer(). So, we only need to return the ++ // device address and the mapping info ++ case EdkiiIoMmuOperationBusMasterCommonBuffer: ++ // fall through ++ case EdkiiIoMmuOperationBusMasterCommonBuffer64: ++ MapInfo = FindMappingByHostAddress (HostAddress); ++ if (MapInfo == NULL) { ++ ASSERT (MapInfo == NULL); ++ goto Failed; ++ } ++ ++ BbAddress = MapInfo->BbAddress; ++ break; ++ ++ default: ++ // Operation is invalid ++ Status = EFI_INVALID_PARAMETER; ++ goto Failed; ++ } // switch ++ ++ // If this is a read operation from the Bus Master's point of view, ++ // then copy the contents of the real buffer into the mapped buffer ++ // so the Bus Master can read the contents of the real buffer. ++ // No special action is needed for BusMasterCommonBuffer[64] operations. ++ if ((Operation == EdkiiIoMmuOperationBusMasterRead) || ++ (Operation == EdkiiIoMmuOperationBusMasterRead64)) ++ { ++ CopyMem ( ++ (VOID *)(UINTN)BbAddress, ++ (VOID *)(UINTN)HostAddress, ++ MapInfo->NumberOfBytes ++ ); ++ } ++ ++ // Populate output parameters. ++ *DeviceAddress = BbAddress; ++ *Mapping = MapInfo; ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: Mapping=0x%p HostAddress = 0x%p BBAddress = 0x%Lx Pages=0x%Lx\n", ++ __func__, ++ MapInfo, ++ HostAddress, ++ MapInfo->BbAddress, ++ MapInfo->NumberOfPages ++ )); ++ ++ return EFI_SUCCESS; ++ ++FreeBounceBuffer: ++ gBS->FreePages (BbAddress, Pages); ++ ++Failed: ++ *NumberOfBytes = 0; ++ return Status; ++} ++ ++/** ++ Completes the Map() operation and releases any corresponding resources. ++ ++ This is an internal worker function that only extends the Map() API with ++ the MemoryMapLocked parameter. ++ ++ @param This The protocol instance pointer. ++ @param MapInfo The mapping value returned from Map(). ++ @param MemoryMapLocked The function is executing on the stack of ++ gBS->ExitBootServices(); changes to the UEFI ++ memory map are forbidden. ++ ++ @retval EFI_SUCCESS The range was unmapped. ++ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by ++ Map(). ++ @retval EFI_DEVICE_ERROR The data was not committed to the target system ++ memory. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++IoMmuUnmapWorker ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN MAP_INFO *MapInfo, ++ IN BOOLEAN MemoryMapLocked ++ ) ++{ ++ EFI_STATUS Status; ++ PHYSICAL_ADDRESS BbAddress; ++ UINTN Pages; ++ ++ DEBUG (( ++ DEBUG_VERBOSE, ++ "%a: MapInfo=0x%p MemoryMapLocked=%d\n", ++ __func__, ++ MapInfo, ++ MemoryMapLocked ++ )); ++ ++ if (MapInfo == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = MapInfo->BbAddress; ++ Pages = MapInfo->NumberOfPages; ++ ++ // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations ++ // we have to copy the results, ultimately to the original place (i.e., ++ // "MapInfo->HostAddress"). ++ // No special operaton is needed for BusMasterCommonBuffer[64] operations. ++ switch (MapInfo->Operation) { ++ case EdkiiIoMmuOperationBusMasterCommonBuffer: ++ case EdkiiIoMmuOperationBusMasterCommonBuffer64: ++ ASSERT (BbAddress == (PHYSICAL_ADDRESS)MapInfo->HostAddress); ++ break; ++ case EdkiiIoMmuOperationBusMasterWrite: ++ case EdkiiIoMmuOperationBusMasterWrite64: ++ CopyMem ( ++ (VOID *)(UINTN)MapInfo->HostAddress, ++ (VOID *)(UINTN)BbAddress, ++ MapInfo->NumberOfBytes ++ ); ++ break; ++ ++ default: ++ // nothing to do for BusMasterRead[64] operations ++ break; ++ } ++ ++ // For all other operations, fill the late bounce buffer with zeros, and ++ // then release it (unless the UEFI memory map is locked). ++ if ((MapInfo->Operation != EdkiiIoMmuOperationBusMasterCommonBuffer) && ++ (MapInfo->Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) ++ { ++ ZeroMem ( ++ (VOID *)(UINTN)BbAddress, ++ EFI_PAGES_TO_SIZE (Pages) ++ ); ++ ++ // UnMapSharedPages ++ Status = UnMapSharedBuffer (MapInfo, MemoryMapLocked); ++ ASSERT_EFI_ERROR (Status); ++ ++ if (!MemoryMapLocked) { ++ gBS->FreePages (BbAddress, Pages); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Completes the Map() operation and releases any corresponding resources. ++ ++ @param This The protocol instance pointer. ++ @param Mapping The mapping value returned from Map(). ++ ++ @retval EFI_SUCCESS The range was unmapped. ++ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by ++ Map(). ++ @retval EFI_DEVICE_ERROR The data was not committed to the target system ++ memory. ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuUnmap ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN VOID *Mapping ++ ) ++{ ++ return IoMmuUnmapWorker ( ++ This, ++ (MAP_INFO *)Mapping, ++ FALSE // MemoryMapLocked ++ ); ++} ++ ++/** ++ Allocates pages that are suitable for an OperationBusMasterCommonBuffer or ++ OperationBusMasterCommonBuffer64 mapping. ++ ++ @param This The protocol instance pointer. ++ @param Type This parameter is not used and must be ignored. ++ @param MemoryType The type of memory to allocate, ++ EfiBootServicesData or EfiRuntimeServicesData. ++ @param Pages The number of pages to allocate. ++ @param HostAddress A pointer to store the base system memory ++ address of the allocated range. ++ @param Attributes The requested bit mask of attributes for the ++ allocated range. ++ ++ @retval EFI_SUCCESS The requested memory pages were allocated. ++ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal ++ attribute bits are MEMORY_WRITE_COMBINE and ++ MEMORY_CACHED. ++ @retval EFI_INVALID_PARAMETER One or more parameters are invalid. ++ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuAllocateBuffer ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EFI_ALLOCATE_TYPE Type, ++ IN EFI_MEMORY_TYPE MemoryType, ++ IN UINTN Pages, ++ IN OUT VOID **HostAddress, ++ IN UINT64 Attributes ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ MAP_INFO *MapInfo; ++ ++ // Validate Attributes ++ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // Check for invalid inputs ++ if (HostAddress == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The only valid memory types are EfiBootServicesData ++ if (MemoryType != EfiBootServicesData) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (Pages >= MAX_UINTN) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ BbAddress = (UINTN)-1; ++ if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) { ++ // Limit allocations to memory below 4GB ++ BbAddress = SIZE_4GB - 1; ++ } ++ ++ Status = gBS->AllocatePages ( ++ AllocateMaxAddress, ++ MemoryType, ++ Pages, ++ &BbAddress ++ ); ++ if (EFI_ERROR (Status)) { ++ // Set the host address to NULL in case of error ++ *HostAddress = NULL; ++ } else { ++ *HostAddress = (VOID *)(UINTN)BbAddress; ++ Status = MapSharedBuffer ( ++ EdkiiIoMmuOperationBusMasterCommonBuffer, ++ *HostAddress, ++ EFI_PAGES_TO_SIZE (Pages), ++ BbAddress, ++ Pages, ++ &MapInfo ++ ); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return Status; ++} ++ ++/** ++ Frees memory that was allocated with AllocateBuffer(). ++ ++ @param This The protocol instance pointer. ++ @param Pages The number of pages to free. ++ @param HostAddress The base system memory address of the allocated ++ range. ++ ++ @retval EFI_SUCCESS The requested memory pages were freed. ++ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and ++ Pages was not allocated with AllocateBuffer(). ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuFreeBuffer ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN UINTN Pages, ++ IN VOID *HostAddress ++ ) ++{ ++ EFI_STATUS Status; ++ MAP_INFO *MapInfo; ++ ++ // Release the common buffer itself. Unmap() has re-encrypted it in-place, so ++ // no need to zero it. ++ MapInfo = FindMappingByHostAddress (HostAddress); ++ if (MapInfo == NULL) { ++ ASSERT (0); ++ return EFI_NOT_FOUND; ++ } else { ++ // UnMapSharedPages ++ Status = UnMapSharedBuffer (MapInfo, FALSE); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return gBS->FreePages ((UINTN)HostAddress, Pages); ++} ++ ++/** ++ Set IOMMU attribute for a system memory. ++ ++ If the IOMMU protocol exists, the system memory cannot be used ++ for DMA by default. ++ ++ When a device requests a DMA access to system memory, ++ the device driver need use SetAttribute() to update the IOMMU ++ attribute to request DMA access (read and/or write). ++ ++ The DeviceHandle is used to identify which device submits the request. ++ The IOMMU implementation need to translate the device path to an IOMMU device ++ ID, and set the IOMMU hardware register accordingly. ++ 1) DeviceHandle can be a standard PCI device. ++ The memory for BusMasterRead needs EDKII_IOMMU_ACCESS_READ set. ++ The memory for BusMasterWrite needs EDKII_IOMMU_ACCESS_WRITE set. ++ The memory for BusMasterCommonBuffer needs ++ EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE set. ++ After the memory is used, the memory need set 0 to keep it being ++ protected. ++ 2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc). ++ The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or ++ EDKII_IOMMU_ACCESS_WRITE. ++ ++ @param[in] This The protocol instance pointer. ++ @param[in] DeviceHandle The device initiating the DMA access ++ request. ++ @param[in] Mapping The mapping value returned from Map(). ++ @param[in] IoMmuAccess The IOMMU access. ++ ++ @retval EFI_UNSUPPORTED Operation not supported by IOMMU. ++ ++**/ ++EFI_STATUS ++EFIAPI ++IoMmuSetAttribute ( ++ IN EDKII_IOMMU_PROTOCOL *This, ++ IN EFI_HANDLE DeviceHandle, ++ IN VOID *Mapping, ++ IN UINT64 IoMmuAccess ++ ) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++/** Arm CCA IoMMU protocol ++*/ ++EDKII_IOMMU_PROTOCOL mArmCcaIoMmu = { ++ EDKII_IOMMU_PROTOCOL_REVISION, ++ IoMmuSetAttribute, ++ IoMmuMap, ++ IoMmuUnmap, ++ IoMmuAllocateBuffer, ++ IoMmuFreeBuffer, ++}; ++ ++/** ++ Notification function that is queued when gBS->ExitBootServices() signals the ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another ++ event, received as Context, and returns. ++ ++ Signaling an event in this context is safe. The UEFI spec allows ++ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not ++ listed, hence memory is not allocated. The edk2 implementation also does not ++ release memory (and we only have to care about the edk2 implementation ++ because EDKII_IOMMU_PROTOCOL is edk2-specific anyway). ++ ++ @param[in] Event Event whose notification function is being invoked. ++ Event is permitted to request the queueing of this ++ function at TPL_CALLBACK or TPL_NOTIFY task ++ priority level. ++ ++ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal ++ is permitted to request the queueing of its ++ notification function only at TPL_CALLBACK level. ++**/ ++STATIC ++VOID ++EFIAPI ++ArmCcaIoMmuExitBoot ( ++ IN EFI_EVENT Event, ++ IN VOID *EventToSignal ++ ) ++{ ++ // (1) The NotifyFunctions of all the events in ++ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before ++ // ArmCcaIoMmuExitBoot() is entered. ++ // ++ // (2) ArmCcaIoMmuExitBoot() is executing minimally at TPL_CALLBACK. ++ // ++ // (3) ArmCcaIoMmuExitBoot() has been queued in unspecified order relative ++ // to the NotifyFunctions of all the other events in ++ // EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as ++ // Event's. ++ // ++ // Consequences: ++ // ++ // - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions ++ // queued at TPL_CALLBACK may be invoked after ArmCcaIoMmuExitBoot() ++ // returns. ++ // ++ // - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions ++ // queued at TPL_NOTIFY may be invoked after ArmCcaIoMmuExitBoot() returns; ++ // plus *all* NotifyFunctions queued at TPL_CALLBACK will be invoked ++ // strictly after all NotifyFunctions queued at TPL_NOTIFY, including ++ // ArmCcaIoMmuExitBoot(), have been invoked. ++ // ++ // - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we ++ // queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* ++ // events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. ++ gBS->SignalEvent (EventToSignal); ++} ++ ++/** ++ Notification function that is queued after the notification functions of all ++ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. The same memory ++ map restrictions apply. ++ ++ This function unmaps all currently existing IOMMU mappings. ++ ++ @param[in] Event Event whose notification function is being invoked. Event ++ is permitted to request the queueing of this function ++ only at TPL_CALLBACK task priority level. ++ ++ @param[in] Context Ignored. ++**/ ++STATIC ++VOID ++EFIAPI ++ArmCcaIoMmuUnmapAllMappings ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ MAP_INFO *MapInfo; ++ ++ // All drivers that had set up IOMMU mappings have halted their respective ++ // controllers by now; tear down the mappings. ++ for (Node = GetFirstNode (&mMapInfos); Node != &mMapInfos; Node = NextNode) { ++ NextNode = GetNextNode (&mMapInfos, Node); ++ MapInfo = CR (Node, MAP_INFO, Link, MAP_INFO_SIG); ++ IoMmuUnmapWorker ( ++ &mArmCcaIoMmu, // This ++ MapInfo, // Mapping ++ TRUE // MemoryMapLocked ++ ); ++ } ++} ++ ++/** ++ Initialize and install the ArmCca IoMmu Protocol. ++ ++ @return RETURN_SUCCESS if successful, otherwise any other error. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaInstallIoMmuProtocol ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_EVENT UnmapAllMappingsEvent; ++ EFI_EVENT ExitBootEvent; ++ EFI_HANDLE Handle; ++ ++ // Create the "late" event whose notification function will tear down all ++ // left-over IOMMU mappings. ++ Status = gBS->CreateEvent ( ++ EVT_NOTIFY_SIGNAL, // Type ++ TPL_CALLBACK, // NotifyTpl ++ ArmCcaIoMmuUnmapAllMappings, // NotifyFunction ++ NULL, // NotifyContext ++ &UnmapAllMappingsEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // Create the event whose notification function will be queued by ++ // gBS->ExitBootServices() and will signal the event created above. ++ Status = gBS->CreateEvent ( ++ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type ++ TPL_CALLBACK, // NotifyTpl ++ ArmCcaIoMmuExitBoot, // NotifyFunction ++ UnmapAllMappingsEvent, // NotifyContext ++ &ExitBootEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ goto CloseUnmapAllMappingsEvent; ++ } ++ ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEdkiiIoMmuProtocolGuid, ++ &mArmCcaIoMmu, ++ NULL ++ ); ++ if (!EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ // cleanup on error ++ gBS->CloseEvent (ExitBootEvent); ++ ++CloseUnmapAllMappingsEvent: ++ gBS->CloseEvent (UnmapAllMappingsEvent); ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h +new file mode 100644 +index 0000000..a12ca77 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmu.h +@@ -0,0 +1,66 @@ ++/** @file ++ The protocol provides support to allocate, free, map and umap a DMA buffer ++ for bus master (e.g PciHostBridge). When the execution context is a Realm, ++ the DMA operations must be performed on buffers that are shared with the HOST, ++ hence the RAMP protocol is used to manage the sharing of the DMA buffers or in ++ some cases bounce the buffers. ++ ++ Copyright (c) 2017, Intel Corporation. All rights reserved.
++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ (C) Copyright 2017 Hewlett Packard Enterprise Development LP
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#ifndef ARM_CCA_IOMMU_H_ ++#define ARM_CCA_IOMMU_H_ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ A macro defning the signature for the MAP_INFO structure. ++*/ ++#define MAP_INFO_SIG SIGNATURE_64 ('M', 'A', 'P', '_', 'I', 'N', 'F', 'O') ++ ++/** A structure describing the mapping for the buffers shared with the host. ++*/ ++typedef struct { ++ /// Signature. ++ UINT64 Signature; ++ /// Linked List node entry. ++ LIST_ENTRY Link; ++ /// IoMMU operation. ++ EDKII_IOMMU_OPERATION Operation; ++ /// Number of bytes. ++ UINTN NumberOfBytes; ++ /// Number of pages. ++ UINTN NumberOfPages; ++ /// Address of the Host buffer. ++ VOID *HostAddress; ++ ++ /// Address for the Bounce Buffer. ++ EFI_PHYSICAL_ADDRESS BbAddress; ++ /// Handle to the Aperture. ++ EFI_HANDLE ApertureRef; ++} MAP_INFO; ++ ++/** ++ Install IOMMU protocol to provide the DMA support for PciHostBridge and ++ RAMP. ++ ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaInstallIoMmuProtocol ( ++ VOID ++ ); ++ ++#endif +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c +new file mode 100644 +index 0000000..01e4e6f +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.c +@@ -0,0 +1,60 @@ ++/** @file ++ ++ IoMmuArmBowDxe driver installs EDKII_IOMMU_PROTOCOL to support ++ DMA operations when the execution context is a Realm. ++ ++ Copyright (c) 2017, AMD Inc. All rights reserved.
++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++**/ ++ ++#include "ArmCcaIoMmu.h" ++ ++/** Pointer to the Realm Aperture Management Protocol ++*/ ++EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL *mRamp = NULL; ++ ++/** Entrypoint of Arm CCA IoMMU Dxe. ++ ++ @param [in] ImageHandle Image handle of this driver. ++ @param [in] SystemTable Pointer to the EFI System Table. ++ ++ @return RETURN_SUCCESS if successful, otherwise any other error. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaIoMmuDxeEntryPoint ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle; ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 1.\n")); ++ // When the execution context is a Realm, install ArmCcaIoMmu protocol ++ // otherwise install the placeholder protocol so that other dependent ++ // module can run. ++ Status = gBS->LocateProtocol ( ++ &gEfiRealmApertureManagementProtocolGuid, ++ NULL, ++ (VOID **)&mRamp ++ ); ++ if (!EFI_ERROR (Status)) { ++ // If the Realm Aperture Management Protocol is present ++ // then the execution context is a Realm. ++ Status = ArmCcaInstallIoMmuProtocol (); ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 1.1.\n")); ++ } else { ++ DEBUG ((DEBUG_INFO, "Execution context is not a Realm.\n")); ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gIoMmuAbsentProtocolGuid, ++ NULL, ++ NULL ++ ); ++ } ++ DEBUG ((DEBUG_INFO, "ArmCcaIoMmuDxeEntryPoint 2.\n")); ++ return Status; ++} +diff --git a/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +new file mode 100644 +index 0000000..59fa1ab +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +@@ -0,0 +1,45 @@ ++## @file ++# Driver provides the IOMMU protcol support for PciHostBridgeIo and others ++# drivers. ++# ++# Copyright (c) 2017, AMD Inc. All rights reserved.
++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = IoMmuDxe ++ FILE_GUID = AA6C1A48-A341-439C-950E-CC394FDFE144 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = ArmCcaIoMmuDxeEntryPoint ++ ++[Sources] ++ ArmCcaIoMmu.c ++ ArmCcaIoMmu.h ++ ArmCcaIoMmuDxe.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ OvmfPkg/OvmfPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ MemoryAllocationLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ ++[Protocols] ++ gEdkiiIoMmuProtocolGuid ## SOMETIME_PRODUCES ++ gIoMmuAbsentProtocolGuid ## SOMETIME_PRODUCES ++ gEfiRealmApertureManagementProtocolGuid ++ ++[Depex] ++ gEfiRealmApertureManagementProtocolGuid +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 0831906..3476471 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -111,6 +111,11 @@ READ_LOCK_STATUS = TRUE + INF ArmPkg/Drivers/CpuPei/CpuPei.inf + INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf + ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + !if $(TPM2_ENABLE) == TRUE + INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf + INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf +-- +1.8.3.1 + diff --git a/0089-ArmVirtPkg-Add-library-for-Arm-CCA-initialisation-in.patch b/0089-ArmVirtPkg-Add-library-for-Arm-CCA-initialisation-in.patch new file mode 100644 index 0000000..03bc8eb --- /dev/null +++ b/0089-ArmVirtPkg-Add-library-for-Arm-CCA-initialisation-in.patch @@ -0,0 +1,256 @@ +From 93d95bddcd6ee28aedd3cd5109012df1835609c8 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:41:06 +0800 +Subject: [PATCH 02/22] ArmVirtPkg: Add library for Arm CCA initialisation in + PEI + +Add ArmCcaInitPeiLib library that performs the Arm CCA specific +initialisation in the PEI phase like: + - Configuring the system memory as Protected RAM. + - Reading the Realm Config and storing the IPA width in + a GUID HOB i.e., gArmCcaIpaWidthGuid for subsequent use. + - Calling ArmCcaConfigureMmio () to configure the MMIO regions + by setting the Unprotected IPA attribute in the page tables. + +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/0a39bde30ba0a26f891f27b9c4bd316aed4f49d4 +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtPkg.dec | 4 +- + ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h | 49 ++++++++++++++++++ + .../Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c | 60 ++++++++++++++++++++++ + .../Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf | 38 ++++++++++++++ + .../ArmVirtMemoryInitPeiLib.c | 3 +- + .../ArmVirtMemoryInitPeiLib.inf | 1 + + .../PrePi/ArmVirtPrePiUniCoreRelocatable.inf | 1 + + 7 files changed, 154 insertions(+), 2 deletions(-) + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h + create mode 100644 ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf + +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index b5df14c..1843524 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -33,7 +33,9 @@ + gEarlyPL011BaseAddressGuid = { 0xB199DEA9, 0xFD5C, 0x4A84, { 0x80, 0x82, 0x2F, 0x41, 0x70, 0x78, 0x03, 0x05 } } + gEarly16550UartBaseAddressGuid = { 0xea67ca3e, 0x1f54, 0x436b, { 0x97, 0x88, 0xd4, 0xeb, 0x29, 0xc3, 0x42, 0x67 } } + gArmVirtSystemMemorySizeGuid = { 0x504eccb9, 0x1bf0, 0x4420, { 0x86, 0x5d, 0xdc, 0x66, 0x06, 0xd4, 0x13, 0xbf } } +- ++ gArmCcaIpaWidthGuid = { 0xbdb66787, 0xfc8a, 0x412e, { 0xa0, 0x9b, 0x84, 0x96, 0x61, 0x81, 0x72, 0xc0 } } ++[Protocols] ++ gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } } + [PcdsFeatureFlag] + # + # Feature Flag PCD that defines whether TPM2 support is enabled +diff --git a/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h b/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h +new file mode 100644 +index 0000000..9374fe8 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaInitPeiLib.h +@@ -0,0 +1,49 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 2023, Arm Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++ ++#ifndef ARM_CCA_INIT_PEI_LIB_ ++#define ARM_CCA_INIT_PEI_LIB_ ++ ++#include ++ ++/** ++ Configure the System Memory region as Protected RAM. ++ ++ When a VMM creates a Realm, a small amount of DRAM (which contains the ++ firmware image) and the initial content is configured as Protected RAM. ++ The remaining System Memory is in the Protected Empty state. The firmware ++ must then initialise the remaining System Memory as Protected RAM before ++ it can be accessed. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaConfigureSystemMemory ( ++ VOID ++ ); ++ ++/** ++ Perform Arm CCA specific initialisations. ++ ++ @retval RETURN_SUCCESS Success or execution context is not a Realm. ++ @retval RETURN_OUT_OF_RESOURCES Out of resources. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaInitialize ( ++ VOID ++ ); ++ ++#endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c +new file mode 100644 +index 0000000..dc3f55a +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.c +@@ -0,0 +1,60 @@ ++/** @file ++ Library that implements the Arm CCA initialisation in PEI phase. ++ ++ Copyright (c) 2022 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ Configure the System Memory region as Protected RAM. ++ ++ When a VMM creates a Realm, a small amount of DRAM (which contains the ++ firmware image) and the initial content is configured as Protected RAM. ++ The remaining System Memory is in the Protected Empty state. The firmware ++ must then initialise the remaining System Memory as Protected RAM before ++ it can be accessed. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaConfigureSystemMemory ( ++ VOID ++ ) ++{ ++ return RETURN_SUCCESS; ++} ++ ++/** ++ Perform Arm CCA specific initialisations. ++ ++ @retval RETURN_SUCCESS Success or execution context is not a Realm. ++ @retval RETURN_OUT_OF_RESOURCES Out of resources. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaInitialize ( ++ VOID ++ ) ++{ ++ return ArmCcaConfigureMmio (48); ++} +diff --git a/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +new file mode 100644 +index 0000000..b3c17a6 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf +@@ -0,0 +1,38 @@ ++## @file ++# Library that implements the Arm CCA initialisation in PEI phase. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaInitPeiLib ++ FILE_GUID = 9A8C3768-79ED-487E-8155-BBF4DD638296 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaInitPeiLib ++ ++[Sources] ++ ArmCcaInitPeiLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmCcaLib ++ ArmLib ++ ArmMmuLib ++ ArmVirtMemInfoLib ++ BaseLib ++ ++[Pcd] ++ gArmTokenSpaceGuid.PcdSystemMemoryBase ++ gArmTokenSpaceGuid.PcdSystemMemorySize ++ ++[Guids] ++ gArmCcaIpaWidthGuid +diff --git a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c +index 08beeac..1a9a967 100644 +--- a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c ++++ b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.c +@@ -9,6 +9,7 @@ + + #include + ++#include + #include + #include + #include +@@ -106,6 +107,6 @@ MemoryPeim ( + // Optional feature that helps prevent EFI memory map fragmentation. + BuildMemoryTypeInformationHob (); + } +- ++ ArmCcaInitialize(); + return EFI_SUCCESS; + } +diff --git a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf +index 34b9fbf..edd2e61 100644 +--- a/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf ++++ b/ArmVirtPkg/Library/ArmVirtMemoryInitPeiLib/ArmVirtMemoryInitPeiLib.inf +@@ -26,6 +26,7 @@ + ArmVirtPkg/ArmVirtPkg.dec + + [LibraryClasses] ++ ArmCcaInitPeiLib + DebugLib + HobLib + ArmLib +diff --git a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf +index 9e2a273..f2ddcc5 100755 +--- a/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf ++++ b/ArmVirtPkg/PrePi/ArmVirtPrePiUniCoreRelocatable.inf +@@ -37,6 +37,7 @@ + ArmVirtPkg/ArmVirtPkg.dec + + [LibraryClasses] ++ ArmCcaInitPeiLib + BaseLib + DebugLib + FdtLib +-- +1.8.3.1 + diff --git a/0090-ArmVirtPkg-Add-library-for-Arm-CCA-helper-functions.patch b/0090-ArmVirtPkg-Add-library-for-Arm-CCA-helper-functions.patch new file mode 100644 index 0000000..9baf0a5 --- /dev/null +++ b/0090-ArmVirtPkg-Add-library-for-Arm-CCA-helper-functions.patch @@ -0,0 +1,369 @@ +From a9ddf7315101e22c04435c6195ab30a218ecc239 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:46:04 +0800 +Subject: [PATCH 03/22] ArmVirtPkg: Add library for Arm CCA helper functions + +Introduce ArmCcaLib library that implements helper +functions to: +- probe if the code is executing in a Realm context +- configure the protection attribute in page tables + for the memory regions shared with the host +- get the IPA width of the Realm which was stored in + the GUID HOB gArmCcaIpaWidthGuid. + +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/3d4d8cb052bc3bf3aa1bbc50e63f90a9db99ec41 +Signed-off-by: gongchangsui +--- + ArmVirtPkg/Include/Library/ArmCcaLib.h | 114 +++++++++++++++++++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 176 +++++++++++++++++++++++++++++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | 34 ++++++ + 3 files changed, 324 insertions(+) + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaLib.h + create mode 100644 ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf + +diff --git a/ArmVirtPkg/Include/Library/ArmCcaLib.h b/ArmVirtPkg/Include/Library/ArmCcaLib.h +new file mode 100644 +index 0000000..ff9c2e9 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaLib.h +@@ -0,0 +1,114 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 - 2023, Arm Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++ ++#ifndef ARM_CCA_LIB_ ++#define ARM_CCA_LIB_ ++ ++#include ++#include ++ ++/** ++ Check if running in a Realm. ++ ++ @retval TRUE The execution is within the context of a Realm. ++ @retval FALSE The execution is not within the context of a Realm. ++**/ ++BOOLEAN ++EFIAPI ++IsRealm ( ++ VOID ++ ); ++ ++/** ++ Configure the protection attribute for the page tables ++ describing the memory region. ++ ++ The IPA space of a Realm is divided into two halves: ++ - Protected IPA space and ++ - Unprotected IPA space. ++ ++ Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ ++ A Protected IPA is an address in the lower half of a Realms IPA ++ space. The most significant bit of a Protected IPA is 0. ++ ++ An Unprotected IPA is an address in the upper half of a Realms ++ IPA space. The most significant bit of an Unprotected IPA is 1. ++ ++ Note: ++ - Configuring the memory region as Unprotected IPA enables the ++ Realm to share the memory region with the Host. ++ - This function updates the page table entries to reflect the ++ protection attribute. ++ - A separate call to transition the memory range using the Realm ++ Service Interface (RSI) RSI_IPA_STATE_SET command is additionally ++ required and is expected to be done outside this function. ++ ++ @param [in] BaseAddress Base address of the memory region. ++ @param [in] Length Length of the memory region. ++ @param [in] IpaWidth IPA width of the Realm. ++ @param [in] Share If TRUE, set the most significant ++ bit of the IPA to configure the memory ++ region as Unprotected IPA. ++ If FALSE, clear the most significant ++ bit of the IPA to configure the memory ++ region as Protected IPA. ++ ++ @retval RETURN_SUCCESS IPA protection attribute updated. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The request is not initiated in a ++ Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaSetMemoryProtectAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 IpaWidth, ++ IN BOOLEAN Share ++ ); ++ ++/** ++ Return the IPA width of the Realm. ++ ++ The IPA width of the Realm is used to configure the protection attribute ++ for memory regions, see ArmCcaSetMemoryProtectAttribute(). ++ ++ The IPA width of the Realm is present in the Realm config which is read ++ when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is ++ called in the PrePi phase. ArmCcaInitialize () stores the IPA width of ++ the Realm in a GUID HOB gArmCcaIpaWidthGuid. ++ ++ This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the ++ IPA width value stored therein. ++ ++ Note: ++ - This function must only be called after ArmCcaInitialize () has setup ++ the GUID HOB gArmCcaIpaWidthGuid. ++ ++ @param [out] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not ++ found and could mean that this function ++ was called before ArmCcaInitialize () ++ has created and initialised the GUID ++ HOB gArmCcaIpaWidthGuid. ++**/ ++RETURN_STATUS ++EFIAPI ++GetIpaWidth ( ++ OUT UINT64 *IpaWidth ++ ); ++ ++#endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +new file mode 100644 +index 0000000..894c6db +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -0,0 +1,176 @@ ++/** @file ++ Library that implements the Arm CCA helper functions. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/** ++ Check if running in a Realm. ++ ++ @retval TRUE The execution is within the context of a Realm. ++ @retval FALSE The execution is not within the context of a Realm. ++**/ ++BOOLEAN ++EFIAPI ++IsRealm ( ++ VOID ++ ) ++{ ++ return TRUE; ++} ++ ++/** ++ Configure the protection attribute for the page tables ++ describing the memory region. ++ ++ The IPA space of a Realm is divided into two halves: ++ - Protected IPA space and ++ - Unprotected IPA space. ++ ++ Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ ++ A Protected IPA is an address in the lower half of a Realms IPA ++ space. The most significant bit of a Protected IPA is 0. ++ ++ An Unprotected IPA is an address in the upper half of a Realms ++ IPA space. The most significant bit of an Unprotected IPA is 1. ++ ++ Note: ++ - Configuring the memory region as Unprotected IPA enables the ++ Realm to share the memory region with the Host. ++ - This function updates the page table entries to reflect the ++ protection attribute. ++ - A separate call to transition the memory range using the Realm ++ Service Interface (RSI) RSI_IPA_STATE_SET command is additionally ++ required and is expected to be done outside this function. ++ ++ @param [in] BaseAddress Base address of the memory region. ++ @param [in] Length Length of the memory region. ++ @param [in] IpaWidth IPA width of the Realm. ++ @param [in] Share If TRUE, set the most significant ++ bit of the IPA to configure the memory ++ region as Unprotected IPA. ++ If FALSE, clear the most significant ++ bit of the IPA to configure the memory ++ region as Protected IPA. ++ ++ @retval RETURN_SUCCESS IPA protection attribute updated. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The request is not initiated in a ++ Realm. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmCcaSetMemoryProtectAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 IpaWidth, ++ IN BOOLEAN Share ++ ) ++{ ++ UINT64 Val; ++ UINT64 Mask; ++ UINT64 ProtectionAttributeMask; ++ ++ if (!IsRealm ()) { ++ return RETURN_UNSUPPORTED; ++ } ++ ++ if (IpaWidth == 0) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ /* Software in a Realm should treat the most significant bit of an ++ IPA as a protection attribute. ++ */ ++ ProtectionAttributeMask = 1ULL << 5; ++ if (Share) { ++ Val = ProtectionAttributeMask; ++ Mask = 0xFFFFFFFFFFFFFFFF; ++ } else { ++ Val = 0; ++ Mask = ~(TT_ADDRESS_MASK_BLOCK_ENTRY | ProtectionAttributeMask); ++ } ++ return SetMemoryRegionAttribute ( ++ BaseAddress, ++ Length, ++ Val, ++ Mask ++ ); ++} ++ ++/** ++ Return the IPA width of the Realm. ++ ++ The IPA width of the Realm is used to configure the protection attribute ++ for memory regions, see ArmCcaSetMemoryProtectAttribute(). ++ ++ The IPA width of the Realm is present in the Realm config which is read ++ when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is ++ called in the PrePi phase. ArmCcaInitialize () stores the IPA width of ++ the Realm in a GUID HOB gArmCcaIpaWidthGuid. ++ ++ This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the ++ IPA width value stored therein. ++ ++ Note: ++ - This function must only be called after ArmCcaInitialize () has setup ++ the GUID HOB gArmCcaIpaWidthGuid. ++ ++ @param [out] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not ++ found and could mean that this function ++ was called before ArmCcaInitialize () ++ has created and initialised the GUID ++ HOB gArmCcaIpaWidthGuid. ++**/ ++RETURN_STATUS ++EFIAPI ++GetIpaWidth ( ++ OUT UINT64 *IpaWidth ++ ) ++{ ++ VOID *Hob; ++ UINT64 *CcaIpaWidth; ++ ++ if (IpaWidth == NULL) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ Hob = GetFirstGuidHob (&gArmCcaIpaWidthGuid); ++ if ((Hob == NULL) || ++ (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) ++ { ++ return RETURN_NOT_FOUND; ++ } ++ ++ CcaIpaWidth = GET_GUID_HOB_DATA (Hob); ++ if ((UINT64)*CcaIpaWidth == 0) { ++ return RETURN_NOT_FOUND; ++ } ++ ++ *IpaWidth = *CcaIpaWidth; ++ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +new file mode 100644 +index 0000000..c0d703b +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +@@ -0,0 +1,34 @@ ++## @file ++# Library that implements the Arm CCA helper functions. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaLib ++ FILE_GUID = 11C18743-52F9-405E-B35B-D7BE91A26F9F ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaLib ++ ++[Sources] ++ ArmCcaLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ArmPlatformPkg/ArmPlatformPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmLib ++ ArmMmuLib ++ BaseLib ++ HobLib ++ ++[Guids] ++ gArmCcaIpaWidthGuid +-- +1.8.3.1 + diff --git a/0091-ArmVirtPkg-Define-an-interface-to-configure-MMIO-reg.patch b/0091-ArmVirtPkg-Define-an-interface-to-configure-MMIO-reg.patch new file mode 100644 index 0000000..15e2802 --- /dev/null +++ b/0091-ArmVirtPkg-Define-an-interface-to-configure-MMIO-reg.patch @@ -0,0 +1,59 @@ +From 151d9964930aba94a98ace9bc3b0e33b4ca3e33d Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:48:00 +0800 +Subject: [PATCH 04/22] ArmVirtPkg: Define an interface to configure MMIO + regions for Arm CCA + +The IPA space of a Realm is divided into two halves: + - Protected IPA space and + - Unprotected IPA space. + +Software in a Realm should treat the most significant bit of an +IPA as a protection attribute. + +The Unprotected IPA space is used for sharing memory and for performing +MMIO accesses with the Host. + +An Unprotected IPA is an address in the upper half of a Realm's +IPA space. The most significant bit of an Unprotected IPA is 1. + +Therefore, the page tables for the MMIO regions must be updated to set +the most significant bit of the IPA space. + +To facilitate this define ArmCcaConfigureMmio () that can be called +during the early firmware startup. + +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/354de43f626528898d1ea8056fd558457b3f1d1c +Signed-off-by: gongchangsui +--- + ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h b/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h +index 5e64091..58b13b7 100644 +--- a/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h ++++ b/ArmVirtPkg/Include/Library/ArmVirtMemInfoLib.h +@@ -32,4 +32,20 @@ ArmVirtGetMemoryMap ( + OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap + ); + ++/** ++ Configure the MMIO regions as shared with the VMM. ++ ++ Set the protection attribute for the MMIO regions as Unprotected IPA. ++ ++ @param[in] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaConfigureMmio ( ++ IN UINT64 IpaWidth ++ ); + #endif +-- +1.8.3.1 + diff --git a/0092-ArmVirtPkg-Introduce-Realm-Aperture-Management-Proto.patch b/0092-ArmVirtPkg-Introduce-Realm-Aperture-Management-Proto.patch new file mode 100644 index 0000000..e35ecb6 --- /dev/null +++ b/0092-ArmVirtPkg-Introduce-Realm-Aperture-Management-Proto.patch @@ -0,0 +1,821 @@ +From 98eebff68d0ba9ca637660f9e7dd59f6a24f1bf3 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:50:08 +0800 +Subject: [PATCH 05/22] ArmVirtPkg: Introduce Realm Aperture Management + Protocol + +The Realm Aperture Management Protocol (RAMP) is used to manage +the sharing of buffers between the Guest and Host. It configures +the memory regions as Protected EMPTY or Protected RAM by calling +RSI_IPA_STATE_SET command. The RAMP provides interfaces that device +drivers can use to open/close apertures for sharing buffers. + +The RAMP also keeps track of the apertures that have been opened +and closes them on ExitBootServices. It also registers for reset +notification and closes all open apertures before the platform +resets the system. + +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/009e0c36ed3df13e089e36aef43bfc59b5fc3a1a +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtQemu.fdf | 4 + + .../Protocol/RealmApertureManagementProtocol.h | 103 ++++ + .../RealmApertureManagementProtocolDxe.c | 593 +++++++++++++++++++++ + .../RealmApertureManagementProtocolDxe.inf | 47 ++ + OvmfPkg/OvmfPkg.dec | 1 + + 5 files changed, 748 insertions(+) + create mode 100644 ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h + create mode 100644 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c + create mode 100644 ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf + +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 3476471..9cdbf33 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -111,6 +111,10 @@ READ_LOCK_STATUS = TRUE + INF ArmPkg/Drivers/CpuPei/CpuPei.inf + INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf + ++ # ++ # Realm Aperture Management ++ # ++ INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf + + # + # IoMMU support for Arm CCA +diff --git a/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h +new file mode 100644 +index 0000000..a3f200b +--- /dev/null ++++ b/ArmVirtPkg/Include/Protocol/RealmApertureManagementProtocol.h +@@ -0,0 +1,103 @@ ++/** @file ++ Realm Aperture Management Protocol (RAMP) ++ On Arm CCA Systems the Realm protects access and visibility of Guest memory ++ and code execution from software outside the realm. ++ ++ However, software executing in a Realm needs to interact with the external ++ world. This may be done using virtualised disk, network interfaces, etc. ++ The drivers for these virtualised devices need to share buffers with the host ++ OS to exchange information/data. ++ ++ Since the Guest memory is protected by the Realm, the host cannot access these ++ buffers unless the IPA state of the buffers is changed to Protected EMPTY by ++ the software executing in the Realm. ++ ++ By enabling the sharing of the buffers, we are essentially opening an ++ aperture so that the host OS can access the range of pages that are shared. ++ ++ The virtual firmware (Guest firmware) needs a mechanism to manage the sharing ++ of buffers. The Realm Aperture Management Protocol provides an interface that ++ UEFI drivers/modules can use to enable/disable the sharing of buffers with the ++ Host. The protocol also tracks open apertures and ensures they are shut on ++ ExitBootServices. ++ ++ Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - RAMP - Realm Aperture Management Protocol ++**/ ++ ++#ifndef REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ ++#define REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ ++ ++/** This macro defines the Realm Aperture Management Protocol GUID. ++ ++ GUID: {585C00BE-CF7C-4DB8-8AA2-490D67F5F6E6} ++*/ ++#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_GUID \ ++ { 0x585c00be, 0xcf7c, 0x4db8, \ ++ { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } \ ++ }; ++ ++/** This macro defines the Realm Aperture Management Protocol Revision. ++*/ ++#define EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION 0x00010000 ++ ++#pragma pack(1) ++ ++/** Enables sharing of the memory buffers with the host. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ @param [out] ApertureReference Reference to the opened aperture. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Memory allocation failed. ++ @retval EFI_ACCESS_DENIED Aperture already open over memory region. ++**/ ++typedef ++EFI_STATUS ++(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE)( ++ IN CONST EFI_PHYSICAL_ADDRESS Memory, ++ IN CONST UINTN Pages, ++ OUT EFI_HANDLE *CONST ApertureReference ++ ); ++ ++/** Disables the sharing of the buffers. ++ ++ @param [in] ApertureReference Reference to the aperture for closing. ++ ++ @retval EFI_SUCCESS The operation completed successfully. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_NOT_FOUND The required buffer information is not found. ++**/ ++typedef ++EFI_STATUS ++(EFIAPI *EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE)( ++ IN CONST EFI_HANDLE ApertureReference ++ ); ++ ++/** A structure describing the interface provided by the Realm Aperture ++ Management Protocol. ++*/ ++typedef struct RealmApertureManagementProtocol { ++ /// The Realm Aperture Management Protocol revision. ++ UINT64 Revision; ++ ++ /// Shares Realm Pages(s) with the Host. ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_OPEN_APERTURE OpenAperture; ++ ++ /// Makes the Realm Pages(s) private to the Realm. ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_CLOSE_APERTURE CloseAperture; ++} EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL; ++ ++/** The Realm Aperture Management Protocol GUID. ++*/ ++extern EFI_GUID gEfiRealmApertureManagementProtocolGuid; ++ ++#pragma pack() ++ ++#endif // REALM_APERTURE_MANAGEMENT_PROTOCOL_H_ +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +new file mode 100644 +index 0000000..58ea4c6 +--- /dev/null ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +@@ -0,0 +1,593 @@ ++/** @file ++ Realm Aperture Management Protocol Dxe ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - IPA - Intermediate Physical Address ++ - RAMP - Realm Aperture Management Protocol ++ - RIPAS - Realm IPA state ++ - RSI - Realm Service Interface ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ A macro defining the signature for the aperture information structure. ++*/ ++#define APERTURE_INFO_SIG SIGNATURE_64 ('A', 'P', 'E', 'R', 'T', 'U', 'R', 'E') ++ ++/** ++ A structure describing the aperture. ++*/ ++typedef struct { ++ /// Signature for identifying this structure. ++ UINT64 Signature; ++ ++ /// The linked list entry. ++ LIST_ENTRY Link; ++ ++ /// The base address for the start of the aperture. ++ EFI_PHYSICAL_ADDRESS BaseAddress; ++ ++ /// The number of pages covered by the aperture. ++ UINTN Pages; ++ ++ /// The bit mask of attributes for the memory region. The ++ /// bit mask of available attributes is defined in GetMemoryMap(). ++ UINT64 MemoryAttributes; ++} APERTURE_INFO; ++ ++/** ++ List of the APERTURE_INFO structures that have been set up by OpenAperture() ++ and not yet torn down by CloseAperture(). The list represents the full set ++ of open apertures currently in effect. ++*/ ++STATIC ++LIST_ENTRY mApertureInfos = INITIALIZE_LIST_HEAD_VARIABLE (mApertureInfos); ++ ++/** ++ A local variable to store the IPA width of the Realm. The IPA width ++ of the Realm is required to configure the protection attribute of ++ memory regions. ++*/ ++STATIC UINT64 mIpaWidth; ++ ++/** Checks if an open aperture is overlapping the memory region. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ ++ @retval TRUE If memory region overlaps an open aperture. ++ @retval FALSE Memory region does not overlap any open apertures. ++**/ ++STATIC ++BOOLEAN ++EFIAPI ++IsApertureOverlapping ( ++ IN CONST EFI_PHYSICAL_ADDRESS MemStart, ++ IN CONST UINTN Pages ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ APERTURE_INFO *ApertureInfo; ++ EFI_PHYSICAL_ADDRESS MemEnd; ++ EFI_PHYSICAL_ADDRESS ApertureStart; ++ EFI_PHYSICAL_ADDRESS ApertureEnd; ++ ++ MemEnd = MemStart + (EFI_PAGE_SIZE * Pages) - 1; ++ ++ // All drivers that had opened the apertures have halted their respective ++ // controllers by now; close all the apertures. ++ for ( ++ Node = GetFirstNode (&mApertureInfos); ++ Node != &mApertureInfos; ++ Node = NextNode ++ ) ++ { ++ NextNode = GetNextNode (&mApertureInfos, Node); ++ ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ ApertureStart = ApertureInfo->BaseAddress; ++ ApertureEnd = ApertureStart + (EFI_PAGE_SIZE * ApertureInfo->Pages) - 1; ++ ++ if (((ApertureStart >= MemStart) && (ApertureStart <= MemEnd)) || ++ ((ApertureEnd >= MemStart) && (ApertureEnd <= MemEnd)) || ++ ((MemStart >= ApertureStart) && (MemStart <= ApertureEnd)) || ++ ((MemEnd >= ApertureStart) && (MemEnd <= ApertureEnd))) ++ { ++ return TRUE; ++ } ++ } ++ ++ return FALSE; ++} ++ ++/** Enables sharing of the memory buffers with the host. ++ ++ @param [in] Memory Pointer to the page start address. ++ @param [in] Pages Number of pages to share. ++ @param [out] ApertureReference Reference to the opened aperture. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Memory allocation failed. ++ @retval EFI_ACCESS_DENIED Aperture already open over memory region. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++RampOpenAperture ( ++ IN CONST EFI_PHYSICAL_ADDRESS Memory, ++ IN CONST UINTN Pages, ++ OUT EFI_HANDLE *CONST ApertureReference ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_STATUS Status1; ++ APERTURE_INFO *ApertInfo; ++ EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor; ++ EFI_PHYSICAL_ADDRESS MemRangeAddr; ++ UINTN Index; ++ ++ if ((Memory == 0) || ++ (Pages == 0) || ++ (ApertureReference == NULL) || ++ ((Memory & (EFI_PAGE_SIZE - 1)) != 0)) ++ { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // The pages size must be aligned to the Realm Granule size. ++ // STATIC_ASSERT ((EFI_PAGE_SIZE & (REALM_GRANULE_SIZE - 1)) == 0); ++ ++ // Checks if we already have an open aperture that overlaps the ++ // memory region. If so return the request as invalid. ++ if (IsApertureOverlapping (Memory, Pages)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ MemRangeAddr = Memory; ++ for (Index = 0; Index < Pages; Index++) { ++ Status = gDS->GetMemorySpaceDescriptor (MemRangeAddr, &GcdDescriptor); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: Memory = 0x%lx, MemType = %a\n", ++ __func__, ++ MemRangeAddr, ++ ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) ? ++ "Runtime Services Memory" : "Boot Services Memory" ++ )); ++ ++ // We currently do not have a usecase where we would want to open apertures ++ // for runtime services memory ++ if ((GcdDescriptor.Attributes & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ MemRangeAddr += EFI_PAGE_SIZE; ++ } // for ++ ++ Status = ArmCcaSetMemoryProtectAttribute ( ++ Memory, ++ EFI_PAGES_TO_SIZE (Pages), ++ mIpaWidth, ++ TRUE ++ ); ++ if (RETURN_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables for Protected EMPTY page mapping, " ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ Memory, ++ Pages, ++ Status ++ )); ++ return Status; ++ } ++ DEBUG ((DEBUG_INFO, "RampOpenAperture set 0x%p NS 1.\n", Memory)); ++ ++ // Allocate a APERTURE_INFO structure to remember the apertures opened. ++ ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); ++ if (ApertInfo == NULL) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto error_handler1; ++ } ++ ++ InitializeListHead (&ApertInfo->Link); ++ ApertInfo->Signature = APERTURE_INFO_SIG; ++ ApertInfo->BaseAddress = Memory; ++ ApertInfo->Pages = Pages; ++ ApertInfo->MemoryAttributes = GcdDescriptor.Attributes; ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " ++ "MemoryAttributes = 0x%x\n", ++ __func__, ++ ApertInfo, ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ ApertInfo->MemoryAttributes ++ )); ++ ++ InsertHeadList (&mApertureInfos, &ApertInfo->Link); ++ *ApertureReference = (EFI_HANDLE *)&ApertInfo->Link; ++ ++ return Status; ++ ++error_handler1: ++ Status1 = ArmCcaSetMemoryProtectAttribute ( ++ Memory, ++ EFI_PAGES_TO_SIZE (Pages), ++ mIpaWidth, ++ TRUE ++ ); ++ if (RETURN_ERROR (Status1)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables to Protected page mapping, " ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ Memory, ++ Pages, ++ Status1 ++ )); ++ } ++ ++ *ApertureReference = NULL; ++ return Status; ++} ++ ++/** Disables the sharing of the buffers. ++ ++ @param [in] ApertureReference Reference to the aperture for closing. ++ ++ @retval EFI_SUCCESS The operation completed successfully. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_NOT_FOUND The required buffer information is not found. ++**/ ++STATIC ++EFI_STATUS ++EFIAPI ++RampCloseAperture ( ++ IN CONST EFI_HANDLE ApertureReference ++ ) ++{ ++ EFI_STATUS Status; ++ APERTURE_INFO *ApertInfo = NULL; ++ ++ if (ApertureReference == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ ApertInfo = CR (ApertureReference, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ if (ApertInfo == NULL) { ++ return EFI_NOT_FOUND; ++ } ++ ++ DEBUG (( ++ DEBUG_INFO, ++ "%a: ApertRef = 0x%p, Memory = 0x%lx, Pages = 0x%x, " ++ "MemoryAttributes = 0x%x\n", ++ __func__, ++ ApertInfo, ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ ApertInfo->MemoryAttributes ++ )); ++ ++ Status = ArmCcaSetMemoryProtectAttribute ( ++ ApertInfo->BaseAddress, ++ EFI_PAGES_TO_SIZE (ApertInfo->Pages), ++ mIpaWidth, ++ FALSE ++ ); ++ if (RETURN_ERROR (Status)) { ++ DEBUG (( ++ DEBUG_ERROR, ++ "ERROR: Failed to update page tables for Protected RAM page mapping," ++ "Address = %p, Pages = 0x%lx, Status = %r\n", ++ ApertInfo->BaseAddress, ++ ApertInfo->Pages, ++ Status ++ )); ++ } ++ ++ RemoveEntryList (&ApertInfo->Link); ++ FreePool (ApertInfo); ++ ++ return Status; ++} ++ ++/** Closes all open apertures. ++ ++**/ ++STATIC ++VOID ++EFIAPI ++RampCloseAllApertures ( ++ VOID ++ ) ++{ ++ LIST_ENTRY *Node; ++ LIST_ENTRY *NextNode; ++ APERTURE_INFO *ApertureInfo; ++ ++ // All drivers that had opened the apertures have halted their respective ++ // controllers by now; close all the apertures. ++ for ( ++ Node = GetFirstNode (&mApertureInfos); ++ Node != &mApertureInfos; ++ Node = NextNode ++ ) ++ { ++ NextNode = GetNextNode (&mApertureInfos, Node); ++ ApertureInfo = CR (Node, APERTURE_INFO, Link, APERTURE_INFO_SIG); ++ RampCloseAperture (&ApertureInfo->Link); ++ } ++} ++ ++/** ++ Notification function that is queued after the notification functions of all ++ events in the EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. ++ ++ This function invokes the closing of all open apertures. ++ ++ @param[in] Event Event whose notification function is being invoked. Event ++ is permitted to request the queueing of this function ++ only at TPL_CALLBACK task priority level. ++ ++ @param[in] Context Ignored. ++**/ ++STATIC ++VOID ++EFIAPI ++OnRampExitBootServicesEvent ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ RampCloseAllApertures (); ++} ++ ++/** ++ Notification function that is queued when gBS->ExitBootServices() signals the ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES event group. This function signals another ++ event, received as Context, and returns. ++ ++ Signaling an event in this context is safe. The UEFI spec allows ++ gBS->SignalEvent() to return EFI_SUCCESS only; EFI_OUT_OF_RESOURCES is not ++ listed, hence memory is not allocated. ++ ++ @param[in] Event Event whose notification function is being invoked. ++ Event is permitted to request the queueing of this ++ function at TPL_CALLBACK or TPL_NOTIFY task ++ priority level. ++ ++ @param[in] EventToSignal Identifies the EFI_EVENT to signal. EventToSignal ++ is permitted to request the queueing of its ++ notification function only at TPL_CALLBACK level. ++**/ ++STATIC ++VOID ++EFIAPI ++RampExitBootServices ( ++ IN EFI_EVENT Event, ++ IN VOID *EventToSignal ++ ) ++{ ++ /** ++ (1) The NotifyFunctions of all the events in ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES will have been queued before ++ RampExitBootServices() is entered. ++ ++ (2) RampExitBootServices() is executing minimally at TPL_CALLBACK. ++ ++ (3) RampExitBootServices() has been queued in unspecified order relative ++ to the NotifyFunctions of all the other events in ++ EFI_EVENT_GROUP_EXIT_BOOT_SERVICES whose NotifyTpl is the same as ++ Event's. ++ ++ Consequences: ++ ++ - If Event's NotifyTpl is TPL_CALLBACK, then some other NotifyFunctions ++ queued at TPL_CALLBACK may be invoked after RampExitBootServices() ++ returns. ++ ++ - If Event's NotifyTpl is TPL_NOTIFY, then some other NotifyFunctions ++ queued at TPL_NOTIFY may be invoked after RampExitBootServices() ++ returns; plus *all* NotifyFunctions queued at TPL_CALLBACK will be ++ invoked strictly after all NotifyFunctions queued at TPL_NOTIFY, ++ including RampExitBootServices(), have been invoked. ++ ++ - By signaling EventToSignal here, whose NotifyTpl is TPL_CALLBACK, we ++ queue EventToSignal's NotifyFunction after the NotifyFunctions of *all* ++ events in EFI_EVENT_GROUP_EXIT_BOOT_SERVICES. ++ */ ++ gBS->SignalEvent (EventToSignal); ++} ++ ++/** A structure describing the Realm Aperture Management protocol. ++*/ ++STATIC ++CONST ++EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL Ramp = { ++ EDKII_REALM_APERTURE_MANAGEMENT_PROTOCOL_REVISION, ++ RampOpenAperture, ++ RampCloseAperture ++}; ++ ++/** ++ This routine is called to close all apertures before system reset. ++ ++ @param[in] ResetType The type of reset to perform. ++ @param[in] ResetStatus The status code for the reset. ++ @param[in] DataSize The size, in bytes, of ResetData. ++ @param[in] ResetData For a ResetType of EfiResetCold, EfiResetWarm, or ++ EfiResetShutdown the data buffer starts with a Null- ++ terminated string, optionally followed by additional ++ binary data. The string is a description that the ++ caller may use to further indicate the reason for ++ the system reset. ResetData is only valid if ++ ResetStatus is something other than EFI_SUCCESS ++ unless the ResetType is EfiResetPlatformSpecific ++ where a minimum amount of ResetData is always ++ required. ++ For a ResetType of EfiResetPlatformSpecific the data ++ buffer also starts with a Null-terminated string ++ that is followed by an EFI_GUID that describes the ++ specific type of reset to perform. ++**/ ++VOID ++EFIAPI ++OnResetEvent ( ++ IN EFI_RESET_TYPE ResetType, ++ IN EFI_STATUS ResetStatus, ++ IN UINTN DataSize, ++ IN VOID *ResetData OPTIONAL ++ ) ++{ ++ RampCloseAllApertures (); ++} ++ ++/** ++ Hook the system reset to close all apertures. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++OnResetNotificationInstall ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_RESET_NOTIFICATION_PROTOCOL *ResetNotify; ++ ++ Status = gBS->LocateProtocol ( ++ &gEfiResetNotificationProtocolGuid, ++ NULL, ++ (VOID **)&ResetNotify ++ ); ++ if (!EFI_ERROR (Status)) { ++ Status = ResetNotify->RegisterResetNotify (ResetNotify, OnResetEvent); ++ ASSERT_EFI_ERROR (Status); ++ DEBUG ((DEBUG_INFO, "RAMP: Hook system reset to close all apertures.\n")); ++ gBS->CloseEvent (Event); ++ } ++} ++ ++/** Entry point for Realm Aperture Management Protocol Dxe ++ ++ @param [in] ImageHandle Handle for this image. ++ @param [in] SystemTable Pointer to the EFI system table. ++ ++ @retval EFI_SUCCESS When executing in a Realm the RAMP was ++ installed successfully. ++ When execution context is not a Realm, this ++ function returns success indicating nothing ++ needs to be done and allow other modules to ++ run. ++ @retval EFI_OUT_OF_RESOURCES There was not enough memory to install the ++ protocols. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ ++**/ ++EFI_STATUS ++EFIAPI ++RealmApertureManagementProtocolDxeInitialize ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle = NULL; ++ EFI_EVENT CloseAllAperturesEvent; ++ EFI_EVENT ExitBootEvent; ++ VOID *Registration; ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 1.\n")); ++ // When the execution context is a Realm, install the Realm Aperture ++ // Management protocol otherwise return success so that other modules ++ // can run. ++ if (!IsRealm ()) { ++ return EFI_SUCCESS; ++ } ++ ++ mIpaWidth = 64; ++ ++ /* ++ Create the "late" event whose notification function will close all ++ apertures. ++ */ ++ Status = gBS->CreateEvent ( ++ EVT_NOTIFY_SIGNAL, // Type ++ TPL_CALLBACK, // NotifyTpl ++ OnRampExitBootServicesEvent, // NotifyFunction ++ NULL, // NotifyContext ++ &CloseAllAperturesEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ /* ++ Create the event whose notification function will be queued by ++ gBS->ExitBootServices() and will signal the event created above. ++ */ ++ Status = gBS->CreateEvent ( ++ EVT_SIGNAL_EXIT_BOOT_SERVICES, // Type ++ TPL_CALLBACK, // NotifyTpl ++ RampExitBootServices, // NotifyFunction ++ CloseAllAperturesEvent, // NotifyContext ++ &ExitBootEvent // Event ++ ); ++ if (EFI_ERROR (Status)) { ++ goto error_handler1; ++ } ++ ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEfiRealmApertureManagementProtocolGuid, ++ &Ramp, ++ NULL ++ ); ++ if (!EFI_ERROR (Status)) { ++ // RAMP Protocol installed successfully ++ // Hook the system reset to close all apertures. ++ EfiCreateProtocolNotifyEvent ( ++ &gEfiResetNotificationProtocolGuid, ++ TPL_CALLBACK, ++ OnResetNotificationInstall, ++ NULL, ++ &Registration ++ ); ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 2.\n")); ++ return Status; ++ } ++ ++ // cleanup on error ++ gBS->CloseEvent (ExitBootEvent); ++ ++error_handler1: ++ gBS->CloseEvent (CloseAllAperturesEvent); ++ DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 3.\n")); ++ return Status; ++} +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +new file mode 100644 +index 0000000..029e933 +--- /dev/null ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +@@ -0,0 +1,47 @@ ++## @file ++# Module to manage the sharing of buffers in a Realm with the Host. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = RealmApertureManagementProtocolDxe ++ FILE_GUID = CEC2F7D5-2564-46D4-A23F-501623F7F56A ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = RealmApertureManagementProtocolDxeInitialize ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = AARCH64 ++# ++ ++[Sources] ++ RealmApertureManagementProtocolDxe.c ++ ++[Packages] ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmCcaLib ++ BaseLib ++ DxeServicesTableLib ++ MemoryAllocationLib ++ PrintLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ UefiLib ++ ++[Protocols] ++ gEfiRealmApertureManagementProtocolGuid ## SOMETIME_PRODUCES ++ gEfiResetNotificationProtocolGuid ## CONSUMES ++ ++[Depex] ++ TRUE +diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec +index 25c05a9..4285730 100644 +--- a/OvmfPkg/OvmfPkg.dec ++++ b/OvmfPkg/OvmfPkg.dec +@@ -185,6 +185,7 @@ + gEfiPeiMpInitLibUpDepPpiGuid = {0xb590774, 0xbc67, 0x49f4, { 0xa7, 0xdb, 0xe8, 0x2e, 0x89, 0xe6, 0xb5, 0xd6}} + + [Protocols] ++ gEfiRealmApertureManagementProtocolGuid = { 0x585c00be, 0xcf7c, 0x4db8, { 0x8a, 0xa2, 0x49, 0xd, 0x67, 0xf5, 0xf6, 0xe6 } } + gVirtioDeviceProtocolGuid = {0xfa920010, 0x6785, 0x4941, {0xb6, 0xec, 0x49, 0x8c, 0x57, 0x9f, 0x16, 0x0a}} + gXenBusProtocolGuid = {0x3d3ca290, 0xb9a5, 0x11e3, {0xb7, 0x5d, 0xb8, 0xac, 0x6f, 0x7d, 0x65, 0xe6}} + gXenIoProtocolGuid = {0x6efac84f, 0x0ab0, 0x4747, {0x81, 0xbe, 0x85, 0x55, 0x62, 0x59, 0x04, 0x49}} +-- +1.8.3.1 + diff --git a/0093-ArmVirtPkg-ArmVirtQemu-Implement-ArmMonitorLib-for-Q.patch b/0093-ArmVirtPkg-ArmVirtQemu-Implement-ArmMonitorLib-for-Q.patch new file mode 100644 index 0000000..d9f9f4e --- /dev/null +++ b/0093-ArmVirtPkg-ArmVirtQemu-Implement-ArmMonitorLib-for-Q.patch @@ -0,0 +1,202 @@ +From 00aa13acee1f8b19f615f8624c70187eda6b2400 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:57:15 +0800 +Subject: [PATCH 06/22] ArmVirtPkg/ArmVirtQemu: Implement ArmMonitorLib for + QEMU specifically + +Whether SMCCC calls use HVC or SMC generally depends on the exception +level that the firmware executes at, but also on whether or not EL2 is +implemented. + +This is almost always known at build time, which is why the default +ArmMonitorLib used to model this as a feature PCD. However, on QEMU, +things are not that simple. + +However, SMCCC specifies that the conduit is the same as the one used +for PSCI calls (which has been retrofitted into SMCCC when it was +defined). Given that QEMU provides this information via the device tree, +let's use it to select the conduit, using a special ArmMonitorLib +implementation. + +This also removes the need to set the associated PCD at runtime, given +that its updated value will no longer be used. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/059676e4faef29ebe50549ed9cd80b6f68a0d556 + +Signed-off-by: gongchangsui +--- + .../Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c | 119 +++++++++++++++++++++ + .../ArmVirtMonitorLib/ArmVirtMonitorLib.inf | 36 +++++++ + 2 files changed, 155 insertions(+) + create mode 100644 ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c + create mode 100644 ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf + +diff --git a/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c +new file mode 100644 +index 0000000..efc03e2 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.c +@@ -0,0 +1,119 @@ ++/** @file ++ Arm Monitor Library. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ An enum representing the PSCI conduits for issuing monitor calls. ++*/ ++typedef enum PsciConduit { ++ PsciConduitHvc, // < HVC conduit ++ PsciConduitSmc, // < SMC conduit ++ PsciConduitMax ++} PSCI_CONDUIT; ++ ++/** ++ A variable that stores the PSCI conduit to be used. ++*/ ++STATIC PSCI_CONDUIT mArmPsciConduit = PsciConduitMax; ++ ++/** Monitor call. ++ ++ An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued ++ depending on the conduit. The library constructor for ArmVirtMonitorLib ++ determines the conduit by parsing the Device Tree handed off by the VMM ++ and initialising mArmPsciConduit. ++ ++ @param [in,out] Args Arguments for the HVC/SMC. ++**/ ++VOID ++EFIAPI ++ArmMonitorCall ( ++ IN OUT ARM_MONITOR_ARGS *Args ++ ) ++{ ++ switch (mArmPsciConduit) { ++ case PsciConduitHvc: ++ ArmCallHvc ((ARM_HVC_ARGS *)Args); ++ break; ++ case PsciConduitSmc: ++ ArmCallSmc ((ARM_SMC_ARGS *)Args); ++ break; ++ default: ++ ASSERT (0); ++ CpuDeadLoop (); ++ } ++} ++ ++/** Constructor for ArmVirtMonitorLib. ++ ++ The library constructor for ArmVirtMonitorLib determines the conduit ++ by parsing the Device Tree handed off by the VMM and initialising ++ mArmPsciConduit, which can then be used to select the appropriate ++ conduit for invoking the monitor call. ++ ++ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS. ++ @retval RETURN_NOT_FOUND An entry for the PSCI conduit was not found in ++ the platform device tree. ++**/ ++RETURN_STATUS ++EFIAPI ++ArmVirtMonitorLibConstructor ( ++ VOID ++ ) ++{ ++ RETURN_STATUS Status; ++ FDT_CLIENT_PROTOCOL *FdtClient; ++ CONST VOID *Prop; ++ ++ Status = gBS->LocateProtocol ( ++ &gFdtClientProtocolGuid, ++ NULL, ++ (VOID **)&FdtClient ++ ); ++ if (RETURN_ERROR (Status)) { ++ ASSERT (0); ++ return Status; ++ } ++ ++ Status = FdtClient->FindCompatibleNodeProperty ( ++ FdtClient, ++ "arm,psci-0.2", ++ "method", ++ &Prop, ++ NULL ++ ); ++ if (RETURN_ERROR (Status)) { ++ return Status; ++ } ++ ++ if (AsciiStrnCmp (Prop, "hvc", 3) == 0) { ++ mArmPsciConduit = PsciConduitHvc; ++ } else if (AsciiStrnCmp (Prop, "smc", 3) == 0) { ++ mArmPsciConduit = PsciConduitSmc; ++ } else { ++ DEBUG (( ++ DEBUG_ERROR, ++ "%a: Unknown PSCI method \"%a\"\n", ++ __func__, ++ Prop ++ )); ++ return RETURN_NOT_FOUND; ++ } ++ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf +new file mode 100644 +index 0000000..fbc2193 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmVirtMonitorLib/ArmVirtMonitorLib.inf +@@ -0,0 +1,36 @@ ++## @file ++# Arm Virt Monitor Library ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++## ++ ++[Defines] ++ INF_VERSION = 1.29 ++ BASE_NAME = ArmVirtMonitorLib ++ FILE_GUID = 3E464134-890D-4C3F-A559-D0FE2803E332 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmMonitorLib|DXE_DRIVER DXE_RUNTIME_DRIVER ++ CONSTRUCTOR = ArmVirtMonitorLibConstructor ++ ++[Sources] ++ ArmVirtMonitorLib.c ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ EmbeddedPkg/EmbeddedPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmHvcLib ++ ArmSmcLib ++ DebugLib ++ UefiBootServicesTableLib ++ ++[Protocols] ++ gFdtClientProtocolGuid ## CONSUMES ++ ++[Depex] ++ gFdtClientProtocolGuid +-- +1.8.3.1 + diff --git a/0094-ArmVirtPkg-Qemu-Add-a-NULL-implementation-of-ArmCcaC.patch b/0094-ArmVirtPkg-Qemu-Add-a-NULL-implementation-of-ArmCcaC.patch new file mode 100644 index 0000000..d751abe --- /dev/null +++ b/0094-ArmVirtPkg-Qemu-Add-a-NULL-implementation-of-ArmCcaC.patch @@ -0,0 +1,71 @@ +From 0d71a57d28c252e7fbda0be64784fb7b8d579303 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 19:59:43 +0800 +Subject: [PATCH 07/22] ArmVirtPkg: Qemu: Add a NULL implementation of + ArmCcaConfigureMmio + +To support Arm CCA, a hook function ArmCcaConfigureMmio () has +been added to the ArmVirtMemInfoLib library. + +Since, Arm CCA has not been enabled for the Qemu guest firmware, +update the QemuVirtMemInfoLib library to add a NULL implementation +for ArmCcaConfigureMmio () that returns RETURN_UNSUPPORTED. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/5bcb8cb235bbdf13b98b2dc55d00fd4bcb6e3a44 + +Signed-off-by: gongchangsui +--- + .../Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c | 21 +++++++++++++++++++++ + .../QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c +index e6362a6..5315177 100644 +--- a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c ++++ b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.c +@@ -8,6 +8,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -122,3 +123,23 @@ ArmVirtGetMemoryMap ( + + *VirtualMemoryMap = VirtualMemoryTable; + } ++ ++/** ++ Configure the MMIO regions as shared with the VMM. ++ ++ Set the protection attribute for the MMIO regions as Unprotected IPA. ++ ++ @param[in] IpaWidth IPA width of the Realm. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_UNSUPPORTED The execution context is not in a Realm. ++**/ ++EFI_STATUS ++EFIAPI ++ArmCcaConfigureMmio ( ++ IN UINT64 IpaWidth ++ ) ++{ ++ return RETURN_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf +index f209b03..69b8708 100644 +--- a/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf ++++ b/ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoLib.inf +@@ -27,6 +27,7 @@ + MdePkg/MdePkg.dec + + [LibraryClasses] ++ ArmCcaLib + ArmLib + BaseMemoryLib + DebugLib +-- +1.8.3.1 + diff --git a/0095-ArmVirtPkg-Perform-Arm-CCA-initialisation-in-the-Pei.patch b/0095-ArmVirtPkg-Perform-Arm-CCA-initialisation-in-the-Pei.patch new file mode 100644 index 0000000..c16f815 --- /dev/null +++ b/0095-ArmVirtPkg-Perform-Arm-CCA-initialisation-in-the-Pei.patch @@ -0,0 +1,41 @@ +From 59b82e638865bae66024708ee09e5073389ab651 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 20:00:52 +0800 +Subject: [PATCH 08/22] ArmVirtPkg: Perform Arm CCA initialisation in the Pei + phase + +Add ArmCcaInitialize () to perform Arm CCA specific initialisation +like: + - Reading the Realm Config by calling the RSI interface. + - Storing the IPA width of the Realm in PcdArmCcaEarlyIpaWidth. + - Configuring the MMIO regions to update the page tables to set + the protection attribute as Unprotected IPA. + +Note: ArmCcaInitialize () is implemented in ArmCcaInitPeiLib for +which a Null implementation is provided. Therefore, this change +should not break existing platforms that do not implement the +Arm CCA. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/99dd7edad7c9716c3d6bcc82d3ad32a91761b29d + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/PrePi/PrePi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ArmVirtPkg/PrePi/PrePi.c b/ArmVirtPkg/PrePi/PrePi.c +index 31b1cf0..bdd2094 100755 +--- a/ArmVirtPkg/PrePi/PrePi.c ++++ b/ArmVirtPkg/PrePi/PrePi.c +@@ -66,7 +66,8 @@ PrePiMain ( + // Initialize MMU and Memory HOBs (Resource Descriptor HOBs) + Status = MemoryPeim (UefiMemoryBase, FixedPcdGet32 (PcdSystemMemoryUefiRegionSize)); + ASSERT_EFI_ERROR (Status); +- ++ // Perform the Arm CCA specific initialisations. ++ ArmCcaInitialize (); + // Initialize the Serial Port + SerialPortInitialize (); + CharCount = AsciiSPrint ( +-- +1.8.3.1 + diff --git a/0096-ArmVirtPkg-ArmVirtQemu-Dispatch-variable-store-emula.patch b/0096-ArmVirtPkg-ArmVirtQemu-Dispatch-variable-store-emula.patch new file mode 100644 index 0000000..6e18773 --- /dev/null +++ b/0096-ArmVirtPkg-ArmVirtQemu-Dispatch-variable-store-emula.patch @@ -0,0 +1,187 @@ +From 54df3a902dbc7ab17af74738e65ed83b85d65c73 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 20:02:26 +0800 +Subject: [PATCH 09/22] ArmVirtPkg/ArmVirtQemu: Dispatch variable store + emulation when necessary + +Add QemuPlatformDxe which installs the Variable store emulation when a +Flash device is not available. + +Link NorFlashQemuLib as a NULL library so that it can setup +PcdEmuVariableNvModeEnable. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/426beb9d07345ebbf908c8aa42f5e6ccfc17fc22 + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtQemu.dsc | 21 +++++++++++++- + ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 1 + + ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c | 38 +++++++++++++++++++++++++ + ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf | 39 ++++++++++++++++++++++++++ + 4 files changed, 98 insertions(+), 1 deletion(-) + create mode 100644 ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c + create mode 100644 ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf + +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index ae342bc..0bee4d1 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -81,7 +81,7 @@ + PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf + PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf + PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf +- ++ ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf + !if $(TPM2_ENABLE) == TRUE + Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf + Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf +@@ -100,6 +100,7 @@ + + [LibraryClasses.common.PEIM] + ArmVirtMemInfoLib|ArmVirtPkg/Library/QemuVirtMemInfoLib/QemuVirtMemInfoPeiLib.inf ++ ArmCcaInitPeiLib|ArmVirtPkg/Library/ArmCcaInitPeiLib/ArmCcaInitPeiLib.inf + + !if $(TPM2_ENABLE) == TRUE + BaseCryptLib|CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf +@@ -254,6 +255,10 @@ + gArmTokenSpaceGuid.PcdArmArchTimerVirtIntrNum|0x0 + gArmTokenSpaceGuid.PcdArmArchTimerHypIntrNum|0x0 + ++ # Define PCD for emulating runtime variable storage when CFI flash is absent ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|FALSE ++ ++ + # + # ARM General Interrupt Controller + # +@@ -442,6 +447,10 @@ + # + # Platform Driver + # ++ ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf { ++ ++ NULL|ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++ } + OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf + EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf + OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf +@@ -579,6 +588,16 @@ + # ACPI Support + # + OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + [Components.AARCH64] + MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { +diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +index e5d7f8d..3a35916 100644 +--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc ++++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +@@ -42,6 +42,7 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf + INF OvmfPkg/Fdt/VirtioFdtDxe/VirtioFdtDxe.inf + INF EmbeddedPkg/Drivers/FdtClientDxe/FdtClientDxe.inf ++ INF ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf + INF OvmfPkg/Fdt/HighMemDxe/HighMemDxe.inf + + # +diff --git a/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c +new file mode 100644 +index 0000000..cabda23 +--- /dev/null ++++ b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.c +@@ -0,0 +1,38 @@ ++/** @file ++ ++ The QemuPlatformDxe performs platform specific initialization. ++ ++ Copyright (c) 2018 - 2023, Arm Limited. All rights reserved. ++ ++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++#include ++#include ++#include ++ ++EFI_STATUS ++EFIAPI ++QemuPlatformDxeEntryPoint ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ) ++{ ++ EFI_STATUS Status = EFI_SUCCESS; ++ ++ if (PcdGetBool (PcdEmuVariableNvModeEnable)) { ++ ++ // The driver implementing the variable service can now be dispatched. ++ Status = gBS->InstallProtocolInterface ( ++ &gImageHandle, ++ &gEdkiiNvVarStoreFormattedGuid, ++ EFI_NATIVE_INTERFACE, ++ NULL ++ ); ++ ASSERT_EFI_ERROR (Status); ++ } ++ ++ return Status; ++} +diff --git a/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf +new file mode 100644 +index 0000000..b62f527 +--- /dev/null ++++ b/ArmVirtPkg/QemuPlatformDxe/QemuPlatformDxe.inf +@@ -0,0 +1,39 @@ ++## @file ++# ++# Copyright (c) 2018 - 2023, Arm Limited. All rights reserved. ++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = QemuPlatformDxe ++ FILE_GUID = 30E617DC-3EB6-4225-B990-A5C22C87AC27 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = QemuPlatformDxeEntryPoint ++ ++[Sources] ++ QemuPlatformDxe.c ++ ++[Packages] ++ OvmfPkg/OvmfPkg.dec ++ EmbeddedPkg/EmbeddedPkg.dec ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ DebugLib ++ UefiBootServicesTableLib ++ UefiDriverEntryPoint ++ ++[Guids] ++ gEdkiiNvVarStoreFormattedGuid ## SOMETIMES_PRODUCES ## PROTOCOL ++ ++[Pcd] ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable ++ ++[Depex] ++ TRUE +-- +1.8.3.1 + diff --git a/0097-ArmPkg-Introduce-SetMemoryProtectionAttribute-for-Re.patch b/0097-ArmPkg-Introduce-SetMemoryProtectionAttribute-for-Re.patch new file mode 100644 index 0000000..b87a84c --- /dev/null +++ b/0097-ArmPkg-Introduce-SetMemoryProtectionAttribute-for-Re.patch @@ -0,0 +1,84 @@ +From d8c264f25ed63410adec4a923e664e1b8eaf2e99 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 20:05:46 +0800 +Subject: [PATCH 10/22] ArmPkg: Introduce SetMemoryProtectionAttribute() for + Realms + +Arm CCA requires the software in a Realm to treat the most +significant bit of an IPA as a protection attribute. To +enable/disable sharing of memory regions with the host, the +protection attribute needs to be set/cleared accordingly. + +Therefore, introduce SetMemoryProtectionAttribute() so that +the memory regions can be shared/unshared with the host. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/571106d95978e22c931cb6ef3d42543728a8ed7b + +Signed-off-by: gongchangsui +--- + ArmPkg/Include/Library/ArmMmuLib.h | 22 +++++++++++++++++++++- + ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c | 14 ++++++++++++++ + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/ArmPkg/Include/Library/ArmMmuLib.h b/ArmPkg/Include/Library/ArmMmuLib.h +index 6aba78f..ece136d 100644 +--- a/ArmPkg/Include/Library/ArmMmuLib.h ++++ b/ArmPkg/Include/Library/ArmMmuLib.h +@@ -64,11 +64,31 @@ ArmReplaceLiveTranslationEntry ( + + **/ + EFI_STATUS ++EFIAPI + ArmSetMemoryAttributes ( + IN EFI_PHYSICAL_ADDRESS BaseAddress, + IN UINT64 Length, + IN UINT64 Attributes, + IN UINT64 AttributeMask + ); +- ++ /** ++ Set the attributes for the memory region. ++ ++ @param[in] BaseAddress Start address of the memory region. ++ @param[in] Length Length memory region. ++ @param[in] Attributes Attributes to set for the memory region. ++ @param[in] BlockEntryMask Mask to be used for the block entry. ++ ++ @retval EFI_SUCCESS Success. ++ @retval EFI_INVALID_PARAMETER A parameter is invalid. ++ @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. ++ **/ ++ EFI_STATUS ++ EFIAPI ++ SetMemoryRegionAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 Attributes, ++ IN UINT64 BlockEntryMask ++ ); + #endif // ARM_MMU_LIB_H_ +diff --git a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +index 741785b..09b1022 100644 +--- a/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c ++++ b/ArmPkg/Library/ArmMmuLib/AArch64/ArmMmuLibCore.c +@@ -756,3 +756,17 @@ ArmMmuBaseLibConstructor ( + + return RETURN_SUCCESS; + } ++EFI_STATUS ++EFIAPI ++SetMemoryRegionAttribute ( ++ IN EFI_PHYSICAL_ADDRESS BaseAddress, ++ IN UINT64 Length, ++ IN UINT64 Attributes, ++ IN UINT64 BlockEntryMask ++ ) ++{ ++ DEBUG ((DEBUG_INFO, "SetMemoryRegionAttribute base 0x%llx, Length 0x%llx, set 0x%llx, clear 0x%llx\n", ++ BaseAddress, Length, Attributes, BlockEntryMask)); ++ return UpdateRegionMapping (BaseAddress, Length, Attributes, BlockEntryMask,ArmGetTTBR0BaseAddress (), ++ TRUE); ++} +\ No newline at end of file +-- +1.8.3.1 + diff --git a/0098-OvmfPkg-FdtNorFlashQemuLib-Parse-device-tree-earlier.patch b/0098-OvmfPkg-FdtNorFlashQemuLib-Parse-device-tree-earlier.patch new file mode 100644 index 0000000..fddc40e --- /dev/null +++ b/0098-OvmfPkg-FdtNorFlashQemuLib-Parse-device-tree-earlier.patch @@ -0,0 +1,218 @@ +From 22cb1cca3ee9f088c74c2c13368328c2d498cc9d Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 20:12:03 +0800 +Subject: [PATCH 11/22] OvmfPkg/FdtNorFlashQemuLib: Parse device tree earlier + +Move the device tree parsing routine into the library constructor, so +that the flash device configuration is available to all drivers that +include this library. The QEMU platform initialization driver will need +to instantiate variable storage emulation depending on the availability +of flash devices. + +Move the device tree modification to VirtNorFlashPlatformInitialization(), +because it should only be done once. +refer: https://git.codelinaro.org/linaro/dcap/edk2/-/commit/642cc833e02ed40fcd9b27069a6094a21931e958 + +OvmfPkg/FdtNorFlashQemuLib: Fallback to runtime variable emulation + +QEMU does not include a flash device when spawning a confidential VM on +Arm, because it cannot do read-only mappings. Support VMs without NOR +flash, by falling back to the emulated variable store. +https://git.codelinaro.org/linaro/dcap/edk2/-/commit/70eab2cb53eb5d59ba4e7a6ee66426dcf124074a + +Signed-off-by: gongchangsui +--- + .../Library/NorFlashQemuLib/NorFlashQemuLib.c | 111 ++++++++++++++------- + .../Library/NorFlashQemuLib/NorFlashQemuLib.inf | 4 +- + 2 files changed, 76 insertions(+), 39 deletions(-) + +diff --git a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c +index 55b419c..2fbb483 100644 +--- a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c ++++ b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.c +@@ -17,23 +17,71 @@ + + #define MAX_FLASH_BANKS 4 + ++STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_BANKS]; ++STATIC UINTN mNorFlashDeviceCount = 0; ++STATIC INT32 mNorFlashNodes[MAX_FLASH_BANKS]; ++STATIC UINTN mNorFlashNodeCount = 0; ++FDT_CLIENT_PROTOCOL *mFdtClient; ++ + EFI_STATUS + VirtNorFlashPlatformInitialization ( + VOID + ) + { ++ EFI_STATUS Status; ++ UINTN Index; ++ // ++ // UEFI takes ownership of the NOR flash, and exposes its functionality ++ // through the UEFI Runtime Services GetVariable, SetVariable, etc. This ++ // means we need to disable it in the device tree to prevent the OS from ++ // attaching its device driver as well. ++ // Note that this also hides other flash banks, but the only other flash ++ // bank we expect to encounter is the one that carries the UEFI executable ++ // code, which is not intended to be guest updatable, and is usually backed ++ // in a readonly manner by QEMU anyway. ++ // ++ for (Index = 0; Index < mNorFlashNodeCount; Index++) { ++ Status = mFdtClient->SetNodeProperty ( ++ mFdtClient, ++ mNorFlashNodes[Index], ++ "status", ++ "disabled", ++ sizeof ("disabled") ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n")); ++ } ++ } + return EFI_SUCCESS; + } + +-STATIC VIRT_NOR_FLASH_DESCRIPTION mNorFlashDevices[MAX_FLASH_BANKS]; +- + EFI_STATUS + VirtNorFlashPlatformGetDevices ( + OUT VIRT_NOR_FLASH_DESCRIPTION **NorFlashDescriptions, + OUT UINT32 *Count + ) + { +- FDT_CLIENT_PROTOCOL *FdtClient; ++ ++ if (mNorFlashDeviceCount == 0) { ++ return EFI_NOT_FOUND; ++ } ++ ++ *NorFlashDescriptions = mNorFlashDevices; ++ *Count = mNorFlashDeviceCount; ++ ++ return EFI_SUCCESS; ++} ++ ++ ++ ++EFI_STATUS ++EFIAPI ++NorFlashQemuLibConstructor ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++ ++ ) ++{ + INT32 Node; + EFI_STATUS Status; + EFI_STATUS FindNodeStatus; +@@ -46,26 +94,26 @@ VirtNorFlashPlatformGetDevices ( + Status = gBS->LocateProtocol ( + &gFdtClientProtocolGuid, + NULL, +- (VOID **)&FdtClient ++ (VOID **)&mFdtClient + ); + ASSERT_EFI_ERROR (Status); + + Num = 0; +- for (FindNodeStatus = FdtClient->FindCompatibleNode ( +- FdtClient, ++ for (FindNodeStatus = mFdtClient->FindCompatibleNode ( ++ mFdtClient, + "cfi-flash", + &Node + ); + !EFI_ERROR (FindNodeStatus) && Num < MAX_FLASH_BANKS; +- FindNodeStatus = FdtClient->FindNextCompatibleNode ( +- FdtClient, ++ FindNodeStatus = mFdtClient->FindNextCompatibleNode ( ++ mFdtClient, + "cfi-flash", + Node, + &Node + )) + { +- Status = FdtClient->GetNodeProperty ( +- FdtClient, ++ Status = mFdtClient->GetNodeProperty ( ++ mFdtClient, + Node, + "reg", + (CONST VOID **)&Reg, +@@ -104,33 +152,20 @@ VirtNorFlashPlatformGetDevices ( + mNorFlashDevices[Num].RegionBaseAddress = (UINTN)Base; + mNorFlashDevices[Num].Size = (UINTN)Size; + mNorFlashDevices[Num].BlockSize = QEMU_NOR_BLOCK_SIZE; +- Num++; +- } +- +- // +- // UEFI takes ownership of the NOR flash, and exposes its functionality +- // through the UEFI Runtime Services GetVariable, SetVariable, etc. This +- // means we need to disable it in the device tree to prevent the OS from +- // attaching its device driver as well. +- // Note that this also hides other flash banks, but the only other flash +- // bank we expect to encounter is the one that carries the UEFI executable +- // code, which is not intended to be guest updatable, and is usually backed +- // in a readonly manner by QEMU anyway. +- // +- Status = FdtClient->SetNodeProperty ( +- FdtClient, +- Node, +- "status", +- "disabled", +- sizeof ("disabled") +- ); +- if (EFI_ERROR (Status)) { +- DEBUG ((DEBUG_WARN, "Failed to set NOR flash status to 'disabled'\n")); ++ mNorFlashDeviceCount = ++Num; + } ++ mNorFlashNodes[mNorFlashNodeCount++] = Node; + } +- +- *NorFlashDescriptions = mNorFlashDevices; +- *Count = Num; +- +- return EFI_SUCCESS; +-} ++ if (Num == 0) { ++ DEBUG ((DEBUG_INFO, ++ "No Flash device found, falling back to Runtime Variable Emulation\n")); ++ ++ Status = PcdSetBoolS (PcdEmuVariableNvModeEnable, TRUE); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, ++ "Failed to set PcdEmuVariableNvModeEnable, Status = %r\n", ++ Status)); ++ } ++ } ++ return EFI_SUCCESS; ++} +\ No newline at end of file +diff --git a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +index 8c77a18..a5ff4be 100644 +--- a/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf ++++ b/ArmVirtPkg/Library/NorFlashQemuLib/NorFlashQemuLib.inf +@@ -15,12 +15,13 @@ + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = VirtNorFlashPlatformLib +- ++ CONSTRUCTOR = NorFlashQemuLibConstructor + [Sources.common] + NorFlashQemuLib.c + + [Packages] + MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec + ArmPkg/ArmPkg.dec + ArmVirtPkg/ArmVirtPkg.dec + EmbeddedPkg/EmbeddedPkg.dec +@@ -40,3 +41,4 @@ + [Pcd] + gArmTokenSpaceGuid.PcdFvBaseAddress + gArmTokenSpaceGuid.PcdFvSize ++ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable +-- +1.8.3.1 + diff --git a/0099-OvmfPkg-Enforce-to-use-MMIO.patch b/0099-OvmfPkg-Enforce-to-use-MMIO.patch new file mode 100644 index 0000000..4eb323e --- /dev/null +++ b/0099-OvmfPkg-Enforce-to-use-MMIO.patch @@ -0,0 +1,183 @@ +From 6acbb7236aa4fb7420215ffb9554f5956a97a4fe Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Wed, 26 Mar 2025 20:20:37 +0800 +Subject: [PATCH 12/22] OvmfPkg: Enforce to use MMIO Between UEFI and QEMU + firmware, MMIO or DMA can be used. To simplify, MMIO is forced to be used + between UEFI and QEMU firmware. + +Signed-off-by: gongchangsui +--- + OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c | 122 ------------------------ + 1 file changed, 122 deletions(-) + +diff --git a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c +index 59efb6f..e1598bb 100644 +--- a/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c ++++ b/OvmfPkg/Library/QemuFwCfgLib/QemuFwCfgLibMmio.c +@@ -22,7 +22,6 @@ + + STATIC UINTN mFwCfgSelectorAddress; + STATIC UINTN mFwCfgDataAddress; +-STATIC UINTN mFwCfgDmaAddress; + + /** + Reads firmware configuration bytes into a buffer +@@ -67,9 +66,6 @@ VOID(EFIAPI SKIP_BYTES_FUNCTION)( + STATIC READ_BYTES_FUNCTION MmioReadBytes; + STATIC WRITE_BYTES_FUNCTION MmioWriteBytes; + STATIC SKIP_BYTES_FUNCTION MmioSkipBytes; +-STATIC READ_BYTES_FUNCTION DmaReadBytes; +-STATIC WRITE_BYTES_FUNCTION DmaWriteBytes; +-STATIC SKIP_BYTES_FUNCTION DmaSkipBytes; + + // + // These correspond to the implementation we detect at runtime. +@@ -201,12 +197,6 @@ QemuFwCfgInitialize ( + + QemuFwCfgSelectItem (QemuFwCfgItemInterfaceVersion); + Features = QemuFwCfgRead32 (); +- if ((Features & FW_CFG_F_DMA) != 0) { +- mFwCfgDmaAddress = FwCfgDmaAddress; +- InternalQemuFwCfgReadBytes = DmaReadBytes; +- InternalQemuFwCfgWriteBytes = DmaWriteBytes; +- InternalQemuFwCfgSkipBytes = DmaSkipBytes; +- } + } + } else { + mFwCfgSelectorAddress = 0; +@@ -292,91 +282,6 @@ MmioReadBytes ( + } + + /** +- Transfer an array of bytes, or skip a number of bytes, using the DMA +- interface. +- +- @param[in] Size Size in bytes to transfer or skip. +- +- @param[in,out] Buffer Buffer to read data into or write data from. Ignored, +- and may be NULL, if Size is zero, or Control is +- FW_CFG_DMA_CTL_SKIP. +- +- @param[in] Control One of the following: +- FW_CFG_DMA_CTL_WRITE - write to fw_cfg from Buffer. +- FW_CFG_DMA_CTL_READ - read from fw_cfg into Buffer. +- FW_CFG_DMA_CTL_SKIP - skip bytes in fw_cfg. +-**/ +-STATIC +-VOID +-DmaTransferBytes ( +- IN UINTN Size, +- IN OUT VOID *Buffer OPTIONAL, +- IN UINT32 Control +- ) +-{ +- volatile FW_CFG_DMA_ACCESS Access; +- UINT32 Status; +- +- ASSERT ( +- Control == FW_CFG_DMA_CTL_WRITE || Control == FW_CFG_DMA_CTL_READ || +- Control == FW_CFG_DMA_CTL_SKIP +- ); +- +- if (Size == 0) { +- return; +- } +- +- ASSERT (Size <= MAX_UINT32); +- +- Access.Control = SwapBytes32 (Control); +- Access.Length = SwapBytes32 ((UINT32)Size); +- Access.Address = SwapBytes64 ((UINT64)(UINTN)Buffer); +- +- // +- // We shouldn't start the transfer before setting up Access. +- // +- MemoryFence (); +- +- // +- // This will fire off the transfer. +- // +- #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_RISCV64) +- MmioWrite64 (mFwCfgDmaAddress, SwapBytes64 ((UINT64)&Access)); +- #else +- MmioWrite32 ((UINT32)(mFwCfgDmaAddress + 4), SwapBytes32 ((UINT32)&Access)); +- #endif +- +- // +- // We shouldn't look at Access.Control before starting the transfer. +- // +- MemoryFence (); +- +- do { +- Status = SwapBytes32 (Access.Control); +- ASSERT ((Status & FW_CFG_DMA_CTL_ERROR) == 0); +- } while (Status != 0); +- +- // +- // The caller will want to access the transferred data. +- // +- MemoryFence (); +-} +- +-/** +- Fast READ_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaReadBytes ( +- IN UINTN Size, +- IN VOID *Buffer OPTIONAL +- ) +-{ +- DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_READ); +-} +- +-/** + Reads firmware configuration bytes into a buffer + + If called multiple times, then the data read will continue at the offset of +@@ -419,20 +324,6 @@ MmioWriteBytes ( + } + + /** +- Fast WRITE_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaWriteBytes ( +- IN UINTN Size, +- IN VOID *Buffer OPTIONAL +- ) +-{ +- DmaTransferBytes (Size, Buffer, FW_CFG_DMA_CTL_WRITE); +-} +- +-/** + Write firmware configuration bytes from a buffer + + If called multiple times, then the data written will continue at the offset +@@ -482,19 +373,6 @@ MmioSkipBytes ( + } + + /** +- Fast SKIP_BYTES_FUNCTION. +-**/ +-STATIC +-VOID +-EFIAPI +-DmaSkipBytes ( +- IN UINTN Size +- ) +-{ +- DmaTransferBytes (Size, NULL, FW_CFG_DMA_CTL_SKIP); +-} +- +-/** + Skip bytes in the firmware configuration item. + + Increase the offset of the firmware configuration item without transferring +-- +1.8.3.1 + diff --git a/0100-clean-code-for-virtCCA-support.patch b/0100-clean-code-for-virtCCA-support.patch new file mode 100644 index 0000000..94569e4 --- /dev/null +++ b/0100-clean-code-for-virtCCA-support.patch @@ -0,0 +1,266 @@ +From a502cc30b599d204e18f7e5624c56cdcffb51a20 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:27:50 -0400 +Subject: [PATCH 13/22] clean code for virtCCA support + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtPkg.dec | 1 + + ArmVirtPkg/ArmVirtQemu.dsc | 18 +++---- + ArmVirtPkg/ArmVirtQemu.fdf | 9 ---- + ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc | 10 ++++ + ArmVirtPkg/Include/Library/ArmCcaLib.h | 34 ------------- + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 57 ---------------------- + .../RealmApertureManagementProtocolDxe.c | 7 ++- + 7 files changed, 23 insertions(+), 113 deletions(-) + +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index 1843524..187f600 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -26,6 +26,7 @@ + Include # Root include for the package + + [LibraryClasses] ++ ArmCcaLib|Include/Library/ArmCcaLib.h + ArmVirtMemInfoLib|Include/Library/ArmVirtMemInfoLib.h + + [Guids.common] +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index 0bee4d1..5331672 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -81,7 +81,7 @@ + PciHostBridgeLib|OvmfPkg/Fdt/FdtPciHostBridgeLib/FdtPciHostBridgeLib.inf + PciHostBridgeUtilityLib|OvmfPkg/Library/PciHostBridgeUtilityLib/PciHostBridgeUtilityLib.inf + PeiHardwareInfoLib|OvmfPkg/Library/HardwareInfoLib/PeiHardwareInfoLib.inf +- ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++ + !if $(TPM2_ENABLE) == TRUE + Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf + Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf +@@ -94,6 +94,7 @@ + + [LibraryClasses.AARCH64] + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf ++ ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +@@ -588,7 +589,12 @@ + # ACPI Support + # + OvmfPkg/PlatformHasAcpiDtDxe/PlatformHasAcpiDtDxe.inf +- ++[Components.AARCH64] ++ MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf ++ OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { ++ ++ NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf ++ } + # + # Realm Aperture Management + # +@@ -597,10 +603,4 @@ + # + # IoMMU support for Arm CCA + # +- ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +-[Components.AARCH64] +- MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf +- OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf { +- +- NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf +- } ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 9cdbf33..0831906 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -111,15 +111,6 @@ READ_LOCK_STATUS = TRUE + INF ArmPkg/Drivers/CpuPei/CpuPei.inf + INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf + +- # +- # Realm Aperture Management +- # +- INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +- +- # +- # IoMMU support for Arm CCA +- # +- INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + !if $(TPM2_ENABLE) == TRUE + INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf + INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf +diff --git a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +index 3a35916..8500979 100644 +--- a/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc ++++ b/ArmVirtPkg/ArmVirtQemuFvMain.fdf.inc +@@ -148,6 +148,16 @@ READ_LOCK_STATUS = TRUE + INF MdeModulePkg/Universal/Acpi/AcpiTableDxe/AcpiTableDxe.inf + INF MdeModulePkg/Universal/Acpi/BootGraphicsResourceTableDxe/BootGraphicsResourceTableDxe.inf + INF OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf ++ ++ # ++ # Realm Aperture Management ++ # ++ INF ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++ ++ # ++ # IoMMU support for Arm CCA ++ # ++ INF ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf + !endif + + # +diff --git a/ArmVirtPkg/Include/Library/ArmCcaLib.h b/ArmVirtPkg/Include/Library/ArmCcaLib.h +index ff9c2e9..322c237 100644 +--- a/ArmVirtPkg/Include/Library/ArmCcaLib.h ++++ b/ArmVirtPkg/Include/Library/ArmCcaLib.h +@@ -77,38 +77,4 @@ ArmCcaSetMemoryProtectAttribute ( + IN BOOLEAN Share + ); + +-/** +- Return the IPA width of the Realm. +- +- The IPA width of the Realm is used to configure the protection attribute +- for memory regions, see ArmCcaSetMemoryProtectAttribute(). +- +- The IPA width of the Realm is present in the Realm config which is read +- when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is +- called in the PrePi phase. ArmCcaInitialize () stores the IPA width of +- the Realm in a GUID HOB gArmCcaIpaWidthGuid. +- +- This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the +- IPA width value stored therein. +- +- Note: +- - This function must only be called after ArmCcaInitialize () has setup +- the GUID HOB gArmCcaIpaWidthGuid. +- +- @param [out] IpaWidth IPA width of the Realm. +- +- @retval RETURN_SUCCESS Success. +- @retval RETURN_INVALID_PARAMETER A parameter is invalid. +- @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not +- found and could mean that this function +- was called before ArmCcaInitialize () +- has created and initialised the GUID +- HOB gArmCcaIpaWidthGuid. +-**/ +-RETURN_STATUS +-EFIAPI +-GetIpaWidth ( +- OUT UINT64 *IpaWidth +- ); +- + #endif // ARM_CCA_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +index 894c6db..9b7b87d 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -117,60 +117,3 @@ ArmCcaSetMemoryProtectAttribute ( + ); + } + +-/** +- Return the IPA width of the Realm. +- +- The IPA width of the Realm is used to configure the protection attribute +- for memory regions, see ArmCcaSetMemoryProtectAttribute(). +- +- The IPA width of the Realm is present in the Realm config which is read +- when the ArmCcaInitPeiLib library hook function ArmCcaInitialize () is +- called in the PrePi phase. ArmCcaInitialize () stores the IPA width of +- the Realm in a GUID HOB gArmCcaIpaWidthGuid. +- +- This function searches the GUID HOB gArmCcaIpaWidthGuid and returns the +- IPA width value stored therein. +- +- Note: +- - This function must only be called after ArmCcaInitialize () has setup +- the GUID HOB gArmCcaIpaWidthGuid. +- +- @param [out] IpaWidth IPA width of the Realm. +- +- @retval RETURN_SUCCESS Success. +- @retval RETURN_INVALID_PARAMETER A parameter is invalid. +- @retval RETURN_NOT_FOUND The GUID HOB gArmCcaIpaWidthGuid is not +- found and could mean that this function +- was called before ArmCcaInitialize () +- has created and initialised the GUID +- HOB gArmCcaIpaWidthGuid. +-**/ +-RETURN_STATUS +-EFIAPI +-GetIpaWidth ( +- OUT UINT64 *IpaWidth +- ) +-{ +- VOID *Hob; +- UINT64 *CcaIpaWidth; +- +- if (IpaWidth == NULL) { +- return RETURN_INVALID_PARAMETER; +- } +- +- Hob = GetFirstGuidHob (&gArmCcaIpaWidthGuid); +- if ((Hob == NULL) || +- (GET_GUID_HOB_DATA_SIZE (Hob) != sizeof (UINT64))) +- { +- return RETURN_NOT_FOUND; +- } +- +- CcaIpaWidth = GET_GUID_HOB_DATA (Hob); +- if ((UINT64)*CcaIpaWidth == 0) { +- return RETURN_NOT_FOUND; +- } +- +- *IpaWidth = *CcaIpaWidth; +- +- return RETURN_SUCCESS; +-} +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +index 58ea4c6..82ae957 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.c +@@ -201,7 +201,6 @@ RampOpenAperture ( + )); + return Status; + } +- DEBUG ((DEBUG_INFO, "RampOpenAperture set 0x%p NS 1.\n", Memory)); + + // Allocate a APERTURE_INFO structure to remember the apertures opened. + ApertInfo = AllocateZeroPool (sizeof (APERTURE_INFO)); +@@ -523,7 +522,7 @@ RealmApertureManagementProtocolDxeInitialize ( + EFI_EVENT CloseAllAperturesEvent; + EFI_EVENT ExitBootEvent; + VOID *Registration; +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 1.\n")); ++ + // When the execution context is a Realm, install the Realm Aperture + // Management protocol otherwise return success so that other modules + // can run. +@@ -579,7 +578,7 @@ RealmApertureManagementProtocolDxeInitialize ( + NULL, + &Registration + ); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 2.\n")); ++ + return Status; + } + +@@ -588,6 +587,6 @@ RealmApertureManagementProtocolDxeInitialize ( + + error_handler1: + gBS->CloseEvent (CloseAllAperturesEvent); +- DEBUG ((DEBUG_INFO, "RealmApertureManagementProtocolDxeInitialize 3.\n")); ++ + return Status; + } +-- +1.8.3.1 + diff --git a/0101-update-ArmCcaLib-to-support-RSI-calls.patch b/0101-update-ArmCcaLib-to-support-RSI-calls.patch new file mode 100644 index 0000000..00c7b57 --- /dev/null +++ b/0101-update-ArmCcaLib-to-support-RSI-calls.patch @@ -0,0 +1,456 @@ +From f5762899e5fa077f2695db48a8f8f8eb8170d47b Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:30:25 -0400 +Subject: [PATCH 14/22] update ArmCcaLib to support RSI calls + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtPkg.dec | 1 + + ArmVirtPkg/ArmVirtQemu.dsc | 1 + + ArmVirtPkg/Include/Library/ArmCcaRsiLib.h | 84 +++++++++++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c | 13 ++ + ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf | 1 + + ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h | 51 +++++++ + ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c | 163 +++++++++++++++++++++ + ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf | 29 ++++ + .../RealmApertureManagementProtocolDxe.inf | 1 + + 9 files changed, 344 insertions(+) + create mode 100644 ArmVirtPkg/Include/Library/ArmCcaRsiLib.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c + create mode 100644 ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf + +diff --git a/ArmVirtPkg/ArmVirtPkg.dec b/ArmVirtPkg/ArmVirtPkg.dec +index 187f600..58765e9 100644 +--- a/ArmVirtPkg/ArmVirtPkg.dec ++++ b/ArmVirtPkg/ArmVirtPkg.dec +@@ -27,6 +27,7 @@ + + [LibraryClasses] + ArmCcaLib|Include/Library/ArmCcaLib.h ++ ArmCcaRsiLib|Include/Library/ArmCcaRsiLib.h + ArmVirtMemInfoLib|Include/Library/ArmVirtMemInfoLib.h + + [Guids.common] +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index 5331672..7ac19ae 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -95,6 +95,7 @@ + [LibraryClasses.AARCH64] + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf + ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++ ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +diff --git a/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +new file mode 100644 +index 0000000..746c5e3 +--- /dev/null ++++ b/ArmVirtPkg/Include/Library/ArmCcaRsiLib.h +@@ -0,0 +1,84 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - RIM - Realm Initial Measurement ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_LIB_ ++#define ARM_CCA_RSI_LIB_ ++ ++#include ++ ++/** ++ A macro defining the size of a Realm Granule. ++ See Section A2.2, RMM Specification, version A-bet0 ++ DNBXXX A Granule is a unit of physical memory whose size is 4KB. ++*/ ++#define REALM_GRANULE_SIZE SIZE_4KB ++ ++/* Maximum measurement data size in bytes. ++ See Section C1.11 RmmRealmMeasurement type, RMM Specification, version A-bet0 ++ The width of the RmmRealmMeasurement type is 512 bits. ++*/ ++#define MAX_MEASUREMENT_DATA_SIZE_BYTES 64 ++ ++/* Minimum and Maximum indices for REMs ++ See Section A2.1.3 Realm attributes, RMM Specification, version A-bet0 ++ IFMPYL - Attributes of a Realm include an array of measurement values. The ++ first entry in this array is a RIM. The remaining entries in this array are ++ REMs. ++*/ ++#define MIN_REM_INDEX 1 ++#define MAX_REM_INDEX 4 ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ); ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ); ++ ++#endif // ARM_CCA_RSI_LIB_ +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +index 9b7b87d..561a414 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.c +@@ -13,6 +13,7 @@ + + #include + #include ++#include + #include + #include + +@@ -33,7 +34,19 @@ IsRealm ( + VOID + ) + { ++ RETURN_STATUS Status; ++ UINT32 UefiImpl; ++ UINT32 RmmImpl; ++ ++ Status = RsiGetVersion ( ++ &UefiImpl, ++ &RmmImpl ++ ); ++ if (!RETURN_ERROR (Status)) { + return TRUE; ++ } ++ ++ return FALSE; + } + + /** +diff --git a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +index c0d703b..2c96d2a 100644 +--- a/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf ++++ b/ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +@@ -25,6 +25,7 @@ + MdePkg/MdePkg.dec + + [LibraryClasses] ++ ArmCcaRsiLib + ArmLib + ArmMmuLib + BaseLib +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +new file mode 100644 +index 0000000..87002cd +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsi.h +@@ -0,0 +1,51 @@ ++/** @file ++ Definitions for Arm CCA Realm Service Interface. ++ ++ Copyright (c) 2022 - 2023, ARM Ltd. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++**/ ++ ++#ifndef ARM_CCA_RSI_H_ ++#define ARM_CCA_RSI_H_ ++ ++// FIDs for Realm Service Interface calls. ++#define FID_RSI_MEASUREMENT_EXTEND 0xC4000193 ++#define FID_RSI_VERSION 0xC4000190 ++ ++/** RSI Command Return codes ++ See Section B4.4.1, RMM Specification, version A-bet0. ++ The width of the RsiCommandReturnCode enumeration is 64 bits. ++*/ ++#define RSI_SUCCESS 0ULL ++#define RSI_ERROR_INPUT 1ULL ++#define RSI_ERROR_STATE 2ULL ++#define RSI_INCOMPLETE 3ULL ++ ++/** RSI interface Version ++ See Section B4.4.3, RMM Specification, version A-bet0. ++ The width of the RsiInterfaceVersion fieldset is 64 bits. ++*/ ++#define RSI_VER_MINOR_MASK 0x0000FFFFULL ++#define RSI_VER_MAJOR_MASK 0x7FFF0000ULL ++#define RSI_VER_MAJOR_SHIFT 16 ++#define RSI_VERSION_MASK (RSI_VER_MAJOR_MASK | RSI_VER_MINOR_MASK) ++ ++#define RMM_VERSION(Major, Minor) ((Minor & RSI_VER_MINOR_MASK) | \ ++ ((Major << RSI_VER_MAJOR_SHIFT) & RSI_VER_MAJOR_MASK)) ++ ++#define GET_MAJOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MAJOR_MASK) >> RSI_VER_MAJOR_SHIFT) ++ ++#define GET_MINOR_REVISION(Rev) \ ++ ((Rev & RSI_VER_MINOR_MASK)) ++ ++#endif // ARM_CCA_RSI_H_ +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +new file mode 100644 +index 0000000..8a000f9 +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.c +@@ -0,0 +1,163 @@ ++/** @file ++ Library that implements the Arm CCA Realm Service Interface calls. ++ ++ Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++ SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++ @par Glossary: ++ - Rsi or RSI - Realm Service Interface ++ - IPA - Intermediate Physical Address ++ - RIPAS - Realm IPA state ++ - REM - Realm Extensible Measurement ++ ++ @par Reference(s): ++ - Realm Management Monitor (RMM) Specification, version 1.0-eac5 ++ (https://developer.arm.com/documentation/den0137/) ++ ++**/ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ArmCcaRsi.h" ++ ++/** The version of RSI specification implemented by this module. ++*/ ++STATIC CONST UINT32 mRsiImplVersion = RMM_VERSION (1, 0); ++ ++/** ++ Convert the RSI status code to EFI Status code. ++ ++ @param [in] RsiCommandReturnCode RSI status code. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++ @retval RETURN_ABORTED The operation was aborted as the state ++ of the Realm or REC does not match the ++ state expected by the command. ++ @retval RETURN_NOT_READY The operation requested by the command ++ is not complete. ++ **/ ++STATIC ++RETURN_STATUS ++RsiCmdStatusToEfiStatus ( ++ IN UINT64 RsiCommandReturnCode ++ ) ++{ ++ switch (RsiCommandReturnCode) { ++ /* TODO: when running in the host, RSI is not available. Find out how to probe ++ * this reliably. ++ */ ++ case 0xFFFFFFFFFFFFFFFF: ++ return RETURN_ABORTED; ++ case RSI_SUCCESS: ++ return RETURN_SUCCESS; ++ case RSI_ERROR_INPUT: ++ return RETURN_INVALID_PARAMETER; ++ case RSI_ERROR_STATE: ++ return RETURN_ABORTED; ++ case RSI_INCOMPLETE: ++ return RETURN_NOT_READY; ++ default: ++ // Unknown error code. ++ ASSERT (0); ++ break; ++ } // switch ++ ++ return RETURN_ABORTED; ++} ++ ++/** ++ Extends a measurement to a REM. ++ ++ @param [in] MeasurementIndex Index of the REM. ++ @param [in] Measurement Pointer to the measurement buffer. ++ @param [in] MeasurementSize Size of the measurement data. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiExtendMeasurement ( ++ IN UINTN MeasurementIndex, ++ IN CONST UINT8 *CONST Measurement, ++ IN UINTN MeasurementSize ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((MeasurementIndex < MIN_REM_INDEX) || ++ (MeasurementIndex > MAX_REM_INDEX) || ++ (Measurement == NULL) || ++ (MeasurementSize == 0) || ++ (MeasurementSize > MAX_MEASUREMENT_DATA_SIZE_BYTES)) ++ { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ ++ SmcCmd.Arg0 = FID_RSI_MEASUREMENT_EXTEND; ++ SmcCmd.Arg1 = MeasurementIndex; ++ SmcCmd.Arg2 = MeasurementSize; ++ ++ SmcCmd.Arg3 = (UINTN) Measurement; ++ ++ ArmCallSmc (&SmcCmd); ++ return RsiCmdStatusToEfiStatus (SmcCmd.Arg0); ++} ++ ++/** ++ Get the version of the RSI implementation. ++ ++ @param [out] UefiImpl The version of the RSI specification ++ implemented by the UEFI firmware. ++ @param [out] RmmImpl The version of the RSI specification ++ implemented by the RMM. ++ ++ @retval RETURN_SUCCESS Success. ++ @retval RETURN_UNSUPPORTED The execution context is not a Realm. ++ @retval RETURN_INCOMPATIBLE_VERSION The Firmware and RMM specification ++ revisions are not compatible. ++ @retval RETURN_INVALID_PARAMETER A parameter is invalid. ++**/ ++RETURN_STATUS ++EFIAPI ++RsiGetVersion ( ++ OUT UINT32 *CONST UefiImpl, ++ OUT UINT32 *CONST RmmImpl ++ ) ++{ ++ ARM_SMC_ARGS SmcCmd; ++ ++ if ((UefiImpl == NULL) || (RmmImpl == NULL)) { ++ return RETURN_INVALID_PARAMETER; ++ } ++ ++ ZeroMem (&SmcCmd, sizeof (SmcCmd)); ++ SmcCmd.Arg0 = FID_RSI_VERSION; ++ ArmCallSmc (&SmcCmd); ++ if (SmcCmd.Arg0 == MAX_UINT64) { ++ // This FID is not implemented, which means ++ // we are not running in a Realm, therefore ++ // return the error code as unsupported. ++ return RETURN_UNSUPPORTED; ++ } ++ ++ *RmmImpl = (SmcCmd.Arg0 & RSI_VERSION_MASK); ++ *UefiImpl = mRsiImplVersion; ++ if (*RmmImpl != *UefiImpl) { ++ // The RSI version implemented by UEFI ++ // firmware and RMM dose not match, return ++ // the status code as RETURN_INCOMPATIBLE_VERSION. ++ return RETURN_INCOMPATIBLE_VERSION; ++ } ++ ++ return RETURN_SUCCESS; ++} ++ +diff --git a/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +new file mode 100644 +index 0000000..24506ba +--- /dev/null ++++ b/ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf +@@ -0,0 +1,29 @@ ++## @file ++# Library that implements the Arm CCA Realm Service Interface calls. ++# ++# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
++# ++# SPDX-License-Identifier: BSD-2-Clause-Patent ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x0001001B ++ BASE_NAME = ArmCcaRsiLib ++ FILE_GUID = 5EF34A0A-28B5-4E57-A999-CC1528FC629A ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = ArmCcaRsiLib ++ ++[Sources] ++ ArmCcaRsiLib.c ++ ArmCcaRsi.h ++ ++[Packages] ++ ArmPkg/ArmPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ MdePkg/MdePkg.dec ++ ++[LibraryClasses] ++ ArmLib ++ ArmSmcLib +diff --git a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +index 029e933..8f8e758 100644 +--- a/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf ++++ b/ArmVirtPkg/RealmApertureManagementProtocolDxe/RealmApertureManagementProtocolDxe.inf +@@ -31,6 +31,7 @@ + + [LibraryClasses] + ArmCcaLib ++ ArmCcaRsiLib + BaseLib + DxeServicesTableLib + MemoryAllocationLib +-- +1.8.3.1 + diff --git a/0102-add-HashLib-for-Arm-CCA-and-SHA256-is-supported.patch b/0102-add-HashLib-for-Arm-CCA-and-SHA256-is-supported.patch new file mode 100644 index 0000000..48ce918 --- /dev/null +++ b/0102-add-HashLib-for-Arm-CCA-and-SHA256-is-supported.patch @@ -0,0 +1,285 @@ +From bf87c1a6840847bb39fab626bda4bcb09309a49c Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:36:30 -0400 +Subject: [PATCH 15/22] add HashLib for Arm CCA and SHA256 is supported + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmVirtQemu.dsc | 1 + + ArmVirtPkg/Library/HashLibCca/HashLibCca.c | 209 +++++++++++++++++++++++++++ + ArmVirtPkg/Library/HashLibCca/HashLibCca.inf | 35 +++++ + 3 files changed, 245 insertions(+) + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.c + create mode 100644 ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index 7ac19ae..b370cd9 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -96,6 +96,7 @@ + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf + ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf + ArmCcaRsiLib|ArmVirtPkg/Library/ArmCcaRsiLib/ArmCcaRsiLib.inf ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf + + [LibraryClasses.ARM] + ArmPlatformLib|ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.inf +diff --git a/ArmVirtPkg/Library/HashLibCca/HashLibCca.c b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +new file mode 100644 +index 0000000..44e7138 +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.c +@@ -0,0 +1,209 @@ ++/** @file ++ This library is HashLib for Cca. ++**/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++EFI_GUID mSha256Guid = HASH_ALGORITHM_SHA256_GUID; ++ ++// ++// Currently CCA supports SHA256. ++// ++HASH_INTERFACE mHashInterface = { ++ { 0 }, NULL, NULL, NULL ++}; ++ ++UINTN mHashInterfaceCount = 0; ++ ++/** ++ Start hash sequence. ++ ++ @param HashHandle Hash handle. ++ ++ @retval EFI_SUCCESS Hash sequence start and HandleHandle returned. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to start hash. ++**/ ++EFI_STATUS ++EFIAPI ++HashStart ( ++ OUT HASH_HANDLE *HashHandle ++ ) ++{ ++ HASH_HANDLE HashCtx; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ HashCtx = 0; ++ mHashInterface.HashInit (&HashCtx); ++ ++ *HashHandle = HashCtx; ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Update hash sequence data. ++ ++ @param HashHandle Hash handle. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ ++ @retval EFI_SUCCESS Hash sequence updated. ++**/ ++EFI_STATUS ++EFIAPI ++HashUpdate ( ++ IN HASH_HANDLE HashHandle, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen ++ ) ++{ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Hash sequence complete and extend to PCR. ++ ++ @param HashHandle Hash handle. ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash sequence complete and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashCompleteAndExtend ( ++ IN HASH_HANDLE HashHandle, ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ TPML_DIGEST_VALUES Digest; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ZeroMem (DigestList, sizeof (*DigestList)); ++ ++ mHashInterface.HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ mHashInterface.HashFinal (HashHandle, &Digest); ++ ++ CopyMem ( ++ &DigestList->digests[0], ++ &Digest.digests[0], ++ sizeof (Digest.digests[0]) ++ ); ++ DigestList->count++; ++ ++ ASSERT (DigestList->count == 1 && DigestList->digests[0].hashAlg == TPM_ALG_SHA256); ++ ++ Status = RsiExtendMeasurement ( ++ (UINTN)PcrIndex, ++ (UINT8 *)DigestList->digests[0].digest.sha256, ++ SHA256_DIGEST_SIZE ++ ); ++ ++ ASSERT (!EFI_ERROR (Status)); ++ return Status; ++} ++ ++/** ++ Hash data and extend to REM. ++ ++ @param PcrIndex PCR to be extended. ++ @param DataToHash Data to be hashed. ++ @param DataToHashLen Data size. ++ @param DigestList Digest list. ++ ++ @retval EFI_SUCCESS Hash data and DigestList is returned. ++**/ ++EFI_STATUS ++EFIAPI ++HashAndExtend ( ++ IN TPMI_DH_PCR PcrIndex, ++ IN VOID *DataToHash, ++ IN UINTN DataToHashLen, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ HASH_HANDLE HashHandle; ++ EFI_STATUS Status; ++ ++ if (mHashInterfaceCount == 0) { ++ ASSERT (FALSE); ++ return EFI_UNSUPPORTED; ++ } ++ ++ ASSERT (IsRealm ()); ++ ++ HashStart (&HashHandle); ++ HashUpdate (HashHandle, DataToHash, DataToHashLen); ++ Status = HashCompleteAndExtend (HashHandle, PcrIndex, NULL, 0, DigestList); ++ ++ return Status; ++} ++ ++/** ++ This service register Hash. ++ ++ @param HashInterface Hash interface ++ ++ @retval EFI_SUCCESS This hash interface is registered successfully. ++ @retval EFI_UNSUPPORTED System does not support register this interface. ++ @retval EFI_ALREADY_STARTED System already register this interface. ++**/ ++EFI_STATUS ++EFIAPI ++RegisterHashInterfaceLib ( ++ IN HASH_INTERFACE *HashInterface ++ ) ++{ ++ // ++ // HashLibCca is designed for Cca guest. So if it is not Cca guest, ++ // return EFI_UNSUPPORTED. ++ // ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ // ++ // Only SHA256 is allowed. ++ // ++ if (!CompareGuid (&mSha256Guid, &HashInterface->HashGuid)) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ if (mHashInterfaceCount != 0) { ++ ASSERT (FALSE); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ CopyMem (&mHashInterface, HashInterface, sizeof (*HashInterface)); ++ mHashInterfaceCount++; ++ ++ return EFI_SUCCESS; ++} +diff --git a/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +new file mode 100644 +index 0000000..1246829 +--- /dev/null ++++ b/ArmVirtPkg/Library/HashLibCca/HashLibCca.inf +@@ -0,0 +1,35 @@ ++## @file ++# ++# This library is HashLib for Cca. Currently only SHA256 is supported. ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = HashLibCca ++ FILE_GUID = 60a6d467-4f75-4089-8c8e-52a74af1e068 ++ MODULE_TYPE = BASE ++ VERSION_STRING = 1.0 ++ LIBRARY_CLASS = HashLib|DXE_DRIVER ++ ++# ++# The following information is for reference only and not required by the build tools. ++# ++# VALID_ARCHITECTURES = AARCH64 ++# ++ ++[Sources] ++ HashLibCca.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ BaseLib ++ BaseMemoryLib ++ DebugLib ++ PcdLib ++ ArmCcaLib ++ ArmCcaRsiLib +-- +1.8.3.1 + diff --git a/0103-add-CcaTcg2Dxe-to-produce-EFI_CC_MEASUREMENT_PROTOCO.patch b/0103-add-CcaTcg2Dxe-to-produce-EFI_CC_MEASUREMENT_PROTOCO.patch new file mode 100644 index 0000000..95a1a99 --- /dev/null +++ b/0103-add-CcaTcg2Dxe-to-produce-EFI_CC_MEASUREMENT_PROTOCO.patch @@ -0,0 +1,430 @@ +From 429f6d9a3370657194146681f3954c9b74920f23 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:37:19 -0400 +Subject: [PATCH 16/22] add CcaTcg2Dxe to produce EFI_CC_MEASUREMENT_PROTOCOL + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 251 ++++++++++++++++++++++++++++++++ + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf | 81 +++++++++++ + ArmVirtPkg/ArmVirtQemu.dsc | 10 +- + ArmVirtPkg/ArmVirtQemu.fdf | 4 + + MdePkg/Include/Protocol/CcMeasurement.h | 5 +- + 5 files changed, 349 insertions(+), 2 deletions(-) + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +new file mode 100644 +index 0000000..b3b7c8c +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -0,0 +1,251 @@ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define PERF_ID_CC_TCG2_DXE 0x3130 ++ ++#define CC_EVENT_LOG_AREA_COUNT_MAX 1 ++#define CC_MR_INDEX_0_RIM 0 ++#define CC_MR_INDEX_1_REM0 1 ++#define CC_MR_INDEX_2_REM1 2 ++#define CC_MR_INDEX_3_REM2 3 ++#define CC_MR_INDEX_INVALID 4 ++ ++typedef struct { ++ EFI_CC_EVENT_LOG_FORMAT EventLogFormat; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINT64 Laml; ++ UINTN EventLogSize; ++ UINT8 *LastEvent; ++ BOOLEAN EventLogStarted; ++ BOOLEAN EventLogTruncated; ++ UINTN Next800155EventOffset; ++} CC_EVENT_LOG_AREA_STRUCT; ++ ++typedef struct _CCA_DXE_DATA { ++ EFI_CC_BOOT_SERVICE_CAPABILITY BsCap; ++ CC_EVENT_LOG_AREA_STRUCT EventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ BOOLEAN GetEventLogCalled[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ CC_EVENT_LOG_AREA_STRUCT FinalEventLogAreaStruct[CC_EVENT_LOG_AREA_COUNT_MAX]; ++ EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX]; ++} CCA_DXE_DATA; ++ ++CCA_DXE_DATA mCcaDxeData = { ++ { ++ sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size ++ { 1, 1 }, // StructureVersion ++ { 1, 1 }, // ProtocolVersion ++ EFI_CC_BOOT_HASH_ALG_SHA256, // HashAlgorithmBitmap ++ EFI_CC_EVENT_LOG_FORMAT_TCG_2, // SupportedEventLogs ++ { 2, 0 } // {CC_TYPE, CC_SUBTYPE} ++ }, ++}; ++ ++EFI_HANDLE mImageHandle; ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides protocol ++ capability information and state information. ++ ++ @param[in] This Indicates the calling context ++ @param[in, out] ProtocolCapability The caller allocates memory for a EFI_CC_BOOT_SERVICE_CAPABILITY ++ structure and sets the size field to the size of the structure allocated. ++ The callee fills in the fields with the EFI protocol capability information ++ and the current EFI TCG2 state information up to the number of fields which ++ fit within the size of the structure passed in. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ The ProtocolCapability variable will not be populated. ++ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is too small to hold the full response. ++ It will be partially populated (required Size field will be set). ++**/ ++EFI_STATUS ++EFIAPI ++CcaGetCapability ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN OUT EFI_CC_BOOT_SERVICE_CAPABILITY *ProtocolCapability ++ ) ++{ ++ DEBUG ((DEBUG_VERBOSE, "CcaGetCapability\n")); ++ ++ if ((This == NULL) || (ProtocolCapability == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ CopyMem (ProtocolCapability, &mCcaDxeData.BsCap, sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY)); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a caller to ++ retrieve the address of a given event log and its last entry. ++ ++ @param[in] This Indicates the calling context ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[out] EventLogLocation A pointer to the memory address of the event log. ++ @param[out] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[out] EventLogTruncated If the Event Log is missing at least one entry because an event would ++ have exceeded the area allocated for events, this value is set to TRUE. ++ Otherwise, the value will be FALSE and the Event Log will be complete. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect ++ (e.g. asking for an event log whose format is not supported). ++**/ ++EFI_STATUS ++EFIAPI ++CcaGetEventLog ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation, ++ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry, ++ OUT BOOLEAN *EventLogTruncated ++ ) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++EFI_STATUS ++EFIAPI ++CcaMapPcrToMrIndex ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT32 PCRIndex, ++ OUT UINT32 *MrIndex ++ ) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++/** ++ The EFI_CC_MEASUREMENT_PROTOCOL HashLogExtendEvent function call provides callers with ++ an opportunity to extend and optionally log events without requiring ++ knowledge of actual TPM commands. ++ The extend operation will occur even if this function cannot create an event ++ log entry (e.g. due to the event log being full). ++ ++ @param[in] This Indicates the calling context ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] DataToHash Physical address of the start of the data buffer to be hashed. ++ @param[in] DataToHashLen The length in bytes of the buffer referenced by DataToHash. ++ @param[in] Event Pointer to data buffer containing information about the event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ @retval EFI_VOLUME_FULL The extend operation occurred, but the event could not be written to one or more event logs. ++ @retval EFI_INVALID_PARAMETER One or more of the parameters are incorrect. ++ @retval EFI_UNSUPPORTED The PE/COFF image type is not supported. ++**/ ++EFI_STATUS ++EFIAPI ++CcaHashLogExtendEvent ( ++ IN EFI_CC_MEASUREMENT_PROTOCOL *This, ++ IN UINT64 Flags, ++ IN EFI_PHYSICAL_ADDRESS DataToHash, ++ IN UINT64 DataToHashLen, ++ IN EFI_CC_EVENT *CcEvent ++ ) ++{ ++ return EFI_UNSUPPORTED; ++} ++ ++EFI_CC_MEASUREMENT_PROTOCOL mCcaProtocol = { ++ CcaGetCapability, ++ CcaGetEventLog, ++ CcaHashLogExtendEvent, ++ CcaMapPcrToMrIndex ++}; ++ ++/** ++ The function install CcaTcg2 protocol. ++ ++ @retval EFI_SUCCESS CcaTcg2 protocol is installed. ++ @retval other Some error occurs. ++**/ ++EFI_STATUS ++InstallCcMeasurementProtocol ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_HANDLE Handle; ++ ++ Handle = NULL; ++ Status = gBS->InstallMultipleProtocolInterfaces ( ++ &Handle, ++ &gEfiCcMeasurementProtocolGuid, ++ &mCcaProtocol, ++ NULL ++ ); ++ DEBUG ((DEBUG_INFO, "CcProtocol: Install %r\n", Status)); ++ return Status; ++} ++ ++EFI_STATUS ++EFIAPI ++DriverEntry ( ++ IN EFI_HANDLE ImageHandle, ++ IN EFI_SYSTEM_TABLE *SystemTable ++) ++{ ++ EFI_STATUS Status; ++ ++ if (!IsRealm ()) { ++ return EFI_UNSUPPORTED; ++ } ++ ++ mImageHandle = ImageHandle; ++ ++ // ++ // Fill information ++ // ++ mCcaDxeData.BsCap.Size = sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY); ++ mCcaDxeData.BsCap.ProtocolVersion.Major = 1; ++ mCcaDxeData.BsCap.ProtocolVersion.Minor = 0; ++ mCcaDxeData.BsCap.StructureVersion.Major = 1; ++ mCcaDxeData.BsCap.StructureVersion.Minor = 0; ++ ++ // ++ // Get supported PCR and current Active PCRs ++ // ++ mCcaDxeData.BsCap.HashAlgorithmBitmap = HASH_ALG_SHA256; ++ ++ // Realm guest only supports EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 ++ mCcaDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // Install CcMeasurementProtocol ++ // ++ Status = InstallCcMeasurementProtocol (); ++ DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status)); ++ ++ return Status; ++} +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +new file mode 100644 +index 0000000..5575d3c +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +@@ -0,0 +1,81 @@ ++## @file ++# ++# Produces EFI_CC_MEASUREMENT_PROTOCOL and measure boot environment ++# ++## ++ ++[Defines] ++ INF_VERSION = 0x00010005 ++ BASE_NAME = CcaTcg2Dxe ++ FILE_GUID = 1788737c-83c4-47b9-899c-b741ab263964 ++ MODULE_TYPE = DXE_DRIVER ++ VERSION_STRING = 1.0 ++ ENTRY_POINT = DriverEntry ++ ++[Sources] ++ CcaTcg2Dxe.c ++ ++[Packages] ++ MdePkg/MdePkg.dec ++ MdeModulePkg/MdeModulePkg.dec ++ SecurityPkg/SecurityPkg.dec ++ ArmVirtPkg/ArmVirtPkg.dec ++ ++[LibraryClasses] ++ MemoryAllocationLib ++ BaseLib ++ UefiBootServicesTableLib ++ HobLib ++ UefiDriverEntryPoint ++ UefiRuntimeServicesTableLib ++ BaseMemoryLib ++ DebugLib ++ PrintLib ++ UefiLib ++ HashLib ++ PerformanceLib ++ PeCoffLib ++ ArmCcaLib ++ ++[Guids] ++ ## SOMETIMES_CONSUMES ## Variable:L"SecureBoot" ++ ## SOMETIMES_CONSUMES ## Variable:L"PK" ++ ## SOMETIMES_CONSUMES ## Variable:L"KEK" ++ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" ++ gEfiGlobalVariableGuid ++ ++ ## SOMETIMES_CONSUMES ## Variable:L"db" ++ ## SOMETIMES_CONSUMES ## Variable:L"dbx" ++ gEfiImageSecurityDatabaseGuid ++ ++ # gTcgEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiEventExitBootServicesGuid ## CONSUMES ## Event ++ gEventExitBootServicesFailedGuid ## SOMETIMES_CONSUMES ## Event ++ ++ gCcEventEntryHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gTcg800155PlatformIdEventHobGuid ## SOMETIMES_CONSUMES ## HOB ++ gEfiCcFinalEventsTableGuid ## PRODUCES ++ ++[Protocols] ++ gEfiCcMeasurementProtocolGuid ## PRODUCES ++ gEfiVariableWriteArchProtocolGuid ## NOTIFY ++ gEfiAcpiTableProtocolGuid ## NOTIFY ++ ++[Pcd] ++ gEfiSecurityPkgTokenSpaceGuid.PcdTpmPlatformClass ## SOMETIMES_CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdFirmwareDebuggerInitialized ## SOMETIMES_CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdStatusCodeSubClassTpmDevice ## SOMETIMES_CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdTcg2HashAlgorithmBitmap ## CONSUMES ++ # gEfiSecurityPkgTokenSpaceGuid.PcdTcg2NumberOfPCRBanks ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcgLogAreaMinLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdTcg2FinalLogAreaLen ## CONSUMES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLaml ## PRODUCES ++ gEfiSecurityPkgTokenSpaceGuid.PcdCcEventlogAcpiTableLasa ## PRODUCES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ++ ++[Depex] ++ gEfiVariableArchProtocolGuid AND gEfiAcpiTableProtocolGuid +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index b370cd9..d85e714 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -32,6 +32,7 @@ + DEFINE TPM2_ENABLE = FALSE + DEFINE TPM2_CONFIG_ENABLE = FALSE + DEFINE CAVIUM_ERRATUM_27456 = FALSE ++ DEFINE CC_MEASUREMENT_ENABLE = FALSE + + # + # Network definition +@@ -605,4 +606,11 @@ + # + # IoMMU support for Arm CCA + # +- ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf +\ No newline at end of file ++ ArmVirtPkg/ArmCcaIoMmuDxe/ArmCcaIoMmuDxe.inf ++ ++ # ++ # Cc Measurement Protocol for Cca guest ++ # ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++!endif +\ No newline at end of file +diff --git a/ArmVirtPkg/ArmVirtQemu.fdf b/ArmVirtPkg/ArmVirtQemu.fdf +index 0831906..1cc3f4e 100644 +--- a/ArmVirtPkg/ArmVirtQemu.fdf ++++ b/ArmVirtPkg/ArmVirtQemu.fdf +@@ -111,6 +111,10 @@ READ_LOCK_STATUS = TRUE + INF ArmPkg/Drivers/CpuPei/CpuPei.inf + INF MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf + ++!if $(CC_MEASUREMENT_ENABLE) == TRUE ++ INF ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++!endif ++ + !if $(TPM2_ENABLE) == TRUE + INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf + INF MdeModulePkg/Universal/ResetSystemPei/ResetSystemPei.inf +diff --git a/MdePkg/Include/Protocol/CcMeasurement.h b/MdePkg/Include/Protocol/CcMeasurement.h +index 43d2403..282b7b9 100644 +--- a/MdePkg/Include/Protocol/CcMeasurement.h ++++ b/MdePkg/Include/Protocol/CcMeasurement.h +@@ -36,6 +36,7 @@ typedef struct { + #define EFI_CC_TYPE_NONE 0 + #define EFI_CC_TYPE_SEV 1 + #define EFI_CC_TYPE_TDX 2 ++#define EFI_CC_TYPE_CCA 3 + + typedef struct { + UINT8 Type; +@@ -57,7 +58,9 @@ typedef UINT32 EFI_CC_MR_INDEX; + #define TDX_MR_INDEX_RTMR3 4 + + #define EFI_CC_EVENT_LOG_FORMAT_TCG_2 0x00000002 +-#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA256 0x00000002 ++#define EFI_CC_BOOT_HASH_ALG_SHA384 0x00000004 ++#define EFI_CC_BOOT_HASH_ALG_SHA512 0x00000008 + + // + // This bit is shall be set when an event shall be extended but not logged. +-- +1.8.3.1 + diff --git a/0104-implement-CcaHashLogExtendEvent-and-CcaMapPcrToMrInd.patch b/0104-implement-CcaHashLogExtendEvent-and-CcaMapPcrToMrInd.patch new file mode 100644 index 0000000..3f45fd7 --- /dev/null +++ b/0104-implement-CcaHashLogExtendEvent-and-CcaMapPcrToMrInd.patch @@ -0,0 +1,726 @@ +From af07da7d283452e43a1949b1c7fb18261f24e886 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:37:55 -0400 +Subject: [PATCH 17/22] implement CcaHashLogExtendEvent and CcaMapPcrToMrIndex + of EFI_CC_MEASUREMENT_PROTOCOL + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 615 ++++++++++++++++++++- + ArmVirtPkg/ArmVirtQemu.dsc | 6 +- + MdePkg/Include/IndustryStandard/UefiTcgPlatform.h | 1 + + .../HashInstanceLibSha256/HashInstanceLibSha256.c | 1 - + .../HashInstanceLibSha256.inf | 1 - + 5 files changed, 619 insertions(+), 5 deletions(-) + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index b3b7c8c..912666c 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -54,6 +54,12 @@ typedef struct _CCA_DXE_DATA { + EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable[CC_EVENT_LOG_AREA_COUNT_MAX]; + } CCA_DXE_DATA; + ++typedef struct { ++ TPMI_ALG_HASH HashAlgo; ++ UINT16 HashSize; ++ UINT32 HashMask; ++} CCA_HASH_INFO; ++ + CCA_DXE_DATA mCcaDxeData = { + { + sizeof (EFI_CC_BOOT_SERVICE_CAPABILITY), // Size +@@ -65,9 +71,131 @@ CCA_DXE_DATA mCcaDxeData = { + }, + }; + ++// ++// Currently SHA256 is supported. ++// ++CCA_HASH_INFO mHashInfo[] = { ++ { TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256 } ++}; ++ ++/** ++ Get hash size based on Algo ++ ++ @param[in] HashAlgo Hash Algorithm Id. ++ ++ @return Size of the hash. ++**/ ++UINT16 ++GetHashSizeFromAlgo ( ++ IN TPMI_ALG_HASH HashAlgo ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < sizeof (mHashInfo)/sizeof (mHashInfo[0]); Index++) { ++ if (mHashInfo[Index].HashAlgo == HashAlgo) { ++ return mHashInfo[Index].HashSize; ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ Copy TPML_DIGEST_VALUES into a buffer ++ ++ @param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary. ++ @param[in] DigestList TPML_DIGEST_VALUES to be copied. ++ @param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy. ++ ++ @return The end of buffer to hold TPML_DIGEST_VALUES. ++**/ ++VOID * ++CopyDigestListToBuffer ( ++ IN OUT VOID *Buffer, ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN UINT32 HashAlgorithmMask ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 DigestListCount; ++ UINT32 *DigestListCountPtr; ++ ++ DigestListCountPtr = (UINT32 *)Buffer; ++ DigestListCount = 0; ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->count); ++ for (Index = 0; Index < DigestList->count; Index++) { ++ if ((DigestList->digests[Index].hashAlg & HashAlgorithmMask) == 0) { ++ DEBUG ((DEBUG_ERROR, "WARNING: CC Event log has HashAlg unsupported (0x%x)\n", DigestList->digests[Index].hashAlg)); ++ continue; ++ } ++ ++ CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof (DigestList->digests[Index].hashAlg)); ++ Buffer = (UINT8 *)Buffer + sizeof (DigestList->digests[Index].hashAlg); ++ DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg); ++ CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize); ++ Buffer = (UINT8 *)Buffer + DigestSize; ++ DigestListCount++; ++ } ++ ++ WriteUnaligned32 (DigestListCountPtr, DigestListCount); ++ ++ return Buffer; ++} ++ + EFI_HANDLE mImageHandle; + + /** ++ ++ This function initialize CC_EVENT_HDR for EV_NO_ACTION ++ Event Type other than EFI Specification ID event. The behavior is defined ++ by TCG PC Client PFP Spec. Section 9.3.4 EV_NO_ACTION Event Types ++ ++ @param[in, out] NoActionEvent Event Header of EV_NO_ACTION Event ++ @param[in] EventSize Event Size of the EV_NO_ACTION Event ++ ++**/ ++VOID ++InitNoActionEvent ( ++ IN OUT CC_EVENT_HDR *NoActionEvent, ++ IN UINT32 EventSize ++ ) ++{ ++ UINT32 DigestListCount; ++ TPMI_ALG_HASH HashAlgId; ++ UINT8 *DigestBuffer; ++ ++ DigestBuffer = (UINT8 *)NoActionEvent->Digests.digests; ++ DigestListCount = 0; ++ ++ NoActionEvent->MrIndex = 0; ++ NoActionEvent->EventType = EV_NO_ACTION; ++ ++ // ++ // Set Hash count & hashAlg accordingly, while Digest.digests[n].digest to all 0 ++ // ++ ZeroMem (&NoActionEvent->Digests, sizeof (NoActionEvent->Digests)); ++ ++ if ((mCcaDxeData.BsCap.HashAlgorithmBitmap & EFI_CC_BOOT_HASH_ALG_SHA256) != 0) { ++ HashAlgId = TPM_ALG_SHA256; ++ CopyMem (DigestBuffer, &HashAlgId, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer += sizeof (TPMI_ALG_HASH) + GetHashSizeFromAlgo (HashAlgId); ++ DigestListCount++; ++ } ++ ++ // ++ // Set Digests Count ++ // ++ WriteUnaligned32 ((UINT32 *)&NoActionEvent->Digests.count, DigestListCount); ++ ++ // ++ // Set Event Size ++ // ++ WriteUnaligned32 ((UINT32 *)DigestBuffer, EventSize); ++} ++ ++/** + The EFI_CC_MEASUREMENT_PROTOCOL GetCapability function call provides protocol + capability information and state information. + +@@ -134,6 +262,185 @@ CcaGetEventLog ( + return EFI_UNSUPPORTED; + } + ++/** ++ Return if this is a Tcg800155PlatformIdEvent. ++ ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval TRUE This is a Tcg800155PlatformIdEvent. ++ @retval FALSE This is NOT a Tcg800155PlatformIdEvent. ++ ++**/ ++BOOLEAN ++Is800155Event ( ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ if ((((TCG_PCR_EVENT2_HDR *)NewEventHdr)->EventType == EV_NO_ACTION) && ++ (NewEventSize >= sizeof (TCG_Sp800_155_PlatformId_Event2)) && ++ ((CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event2_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event2_SIGNATURE) - 1 ++ ) == 0) || ++ (CompareMem ( ++ NewEventData, ++ TCG_Sp800_155_PlatformId_Event3_SIGNATURE, ++ sizeof (TCG_Sp800_155_PlatformId_Event3_SIGNATURE) - 1 ++ ) == 0))) ++ { ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in, out] EventLogAreaStruct The event log area data structure ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++TcgCommLogEvent ( ++ IN OUT CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ UINTN NewLogSize; ++ BOOLEAN Record800155Event; ++ CC_EVENT_HDR *CcEventHdr; ++ ++ CcEventHdr = (CC_EVENT_HDR *)NewEventHdr; ++ DEBUG ((DEBUG_INFO, "Cca: Try to log event. Index = %d, EventType = 0x%x\n", CcEventHdr->MrIndex, CcEventHdr->EventType)); ++ ++ if (NewEventSize > MAX_ADDRESS - NewEventHdrSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ NewLogSize = NewEventHdrSize + NewEventSize; ++ ++ if (NewLogSize > MAX_ADDRESS - EventLogAreaStruct->EventLogSize) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ if (NewLogSize + EventLogAreaStruct->EventLogSize > EventLogAreaStruct->Laml) { ++ DEBUG ((DEBUG_INFO, " Laml - 0x%x\n", EventLogAreaStruct->Laml)); ++ DEBUG ((DEBUG_INFO, " NewLogSize - 0x%x\n", NewLogSize)); ++ DEBUG ((DEBUG_INFO, " LogSize - 0x%x\n", EventLogAreaStruct->EventLogSize)); ++ DEBUG ((DEBUG_INFO, "TcgCommLogEvent - %r\n", EFI_OUT_OF_RESOURCES)); ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ // ++ // Check 800-155 event ++ // Record to 800-155 event offset only. ++ // If the offset is 0, no need to record. ++ // ++ Record800155Event = Is800155Event (NewEventHdr, NewEventHdrSize, NewEventData, NewEventSize); ++ if (Record800155Event) { ++ DEBUG ((DEBUG_INFO, "It is 800155Event.\n")); ++ ++ if (EventLogAreaStruct->Next800155EventOffset != 0) { ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewLogSize, ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ EventLogAreaStruct->EventLogSize - EventLogAreaStruct->Next800155EventOffset ++ ); ++ ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset, ++ NewEventHdr, ++ NewEventHdrSize ++ ); ++ CopyMem ( ++ (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->Next800155EventOffset + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ EventLogAreaStruct->Next800155EventOffset += NewLogSize; ++ EventLogAreaStruct->LastEvent += NewLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ } ++ ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct->LastEvent = (UINT8 *)(UINTN)EventLogAreaStruct->Lasa + EventLogAreaStruct->EventLogSize; ++ EventLogAreaStruct->EventLogSize += NewLogSize; ++ ++ CopyMem (EventLogAreaStruct->LastEvent, NewEventHdr, NewEventHdrSize); ++ CopyMem ( ++ EventLogAreaStruct->LastEvent + NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ According to UEFI Spec 2.10 Section 38.4.1: ++ The following table shows the TPM PCR index mapping and CC event log measurement ++ register index interpretation for ARM CCA, where RIM means Realm Initial Measurement ++ and REM means Realm Extensive Measurement ++ ++ // TPM PCR Index | CC Measurement Register Index | CCA-measurement register ++ // ------------------------------------------------------------------------ ++ // 0 | 0 | RIM ++ // 1, 7 | 1 | REM[0] ++ // 2~6 | 2 | REM[1] ++ // 8~15 | 3 | REM[2] ++ ++ @param[in] PCRIndex Index of the TPM PCR ++ ++ @retval UINT32 Index of the CC Event Log Measurement Register Index ++ @retval CC_MR_INDEX_INVALID Invalid MR Index ++**/ ++UINT32 ++EFIAPI ++MapPcrToMrIndex ( ++ IN UINT32 PCRIndex ++ ) ++{ ++ UINT32 MrIndex; ++ ++ if (PCRIndex > 15) { ++ ASSERT (FALSE); ++ return CC_MR_INDEX_INVALID; ++ } ++ ++ MrIndex = 0; ++ if (PCRIndex == 0) { ++ MrIndex = CC_MR_INDEX_0_RIM; ++ } else if ((PCRIndex == 1) || (PCRIndex == 7)) { ++ MrIndex = CC_MR_INDEX_1_REM0; ++ } else if ((PCRIndex >= 2) && (PCRIndex <= 6)) { ++ MrIndex = CC_MR_INDEX_2_REM1; ++ } else if ((PCRIndex >= 8) && (PCRIndex <= 15)) { ++ MrIndex = CC_MR_INDEX_3_REM2; ++ } ++ ++ return MrIndex; ++} ++ + EFI_STATUS + EFIAPI + CcaMapPcrToMrIndex ( +@@ -142,7 +449,268 @@ CcaMapPcrToMrIndex ( + OUT UINT32 *MrIndex + ) + { +- return EFI_UNSUPPORTED; ++ if (MrIndex == NULL) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ *MrIndex = MapPcrToMrIndex (PCRIndex); ++ ++ return *MrIndex == CC_MR_INDEX_INVALID ? EFI_INVALID_PARAMETER : EFI_SUCCESS; ++} ++ ++/** ++ Add a new entry to the Event Log. ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] NewEventHdr Pointer to a TCG_PCR_EVENT_HDR/TCG_PCR_EVENT_EX data structure. ++ @param[in] NewEventHdrSize New event header size. ++ @param[in] NewEventData Pointer to the new event data. ++ @param[in] NewEventSize New event data size. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ ++**/ ++EFI_STATUS ++CcaDxeLogEvent ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN VOID *NewEventHdr, ++ IN UINT32 NewEventHdrSize, ++ IN UINT8 *NewEventData, ++ IN UINT32 NewEventSize ++ ) ++{ ++ EFI_STATUS Status; ++ UINTN Index; ++ CC_EVENT_LOG_AREA_STRUCT *EventLogAreaStruct; ++ ++ if (EventLogFormat != EFI_CC_EVENT_LOG_FORMAT_TCG_2) { ++ ASSERT (FALSE); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ Index = 0; ++ ++ // ++ // Record to normal event log ++ // ++ EventLogAreaStruct = &mCcaDxeData.EventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ } ++ ++ // ++ // If GetEventLog is called, record to FinalEventsTable, too. ++ // ++ if (mCcaDxeData.GetEventLogCalled[Index]) { ++ if (mCcaDxeData.FinalEventsTable[Index] == NULL) { ++ // ++ // no need for FinalEventsTable ++ // ++ return EFI_SUCCESS; ++ } ++ ++ EventLogAreaStruct = &mCcaDxeData.FinalEventLogAreaStruct[Index]; ++ ++ if (EventLogAreaStruct->EventLogTruncated) { ++ return EFI_VOLUME_FULL; ++ } ++ ++ Status = TcgCommLogEvent ( ++ EventLogAreaStruct, ++ NewEventHdr, ++ NewEventHdrSize, ++ NewEventData, ++ NewEventSize ++ ); ++ if (Status == EFI_OUT_OF_RESOURCES) { ++ EventLogAreaStruct->EventLogTruncated = TRUE; ++ return EFI_VOLUME_FULL; ++ } else if (Status == EFI_SUCCESS) { ++ EventLogAreaStruct->EventLogStarted = TRUE; ++ // ++ // Increase the NumberOfEvents in FinalEventsTable ++ // ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents++; ++ DEBUG ((DEBUG_INFO, "FinalEventsTable->NumberOfEvents - 0x%x\n", (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents)); ++ DEBUG ((DEBUG_INFO, " Size - 0x%x\n", (UINTN)EventLogAreaStruct->EventLogSize)); ++ } ++ } ++ ++ return Status; ++} ++ ++/** ++ Get TPML_DIGEST_VALUES compact binary buffer size. ++ ++ @param[in] DigestListBin TPML_DIGEST_VALUES compact binary buffer. ++ ++ @return TPML_DIGEST_VALUES compact binary buffer size. ++**/ ++UINT32 ++GetDigestListBinSize ( ++ IN VOID *DigestListBin ++ ) ++{ ++ UINTN Index; ++ UINT16 DigestSize; ++ UINT32 TotalSize; ++ UINT32 Count; ++ TPMI_ALG_HASH HashAlg; ++ ++ Count = ReadUnaligned32 (DigestListBin); ++ TotalSize = sizeof (Count); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (Count); ++ for (Index = 0; Index < Count; Index++) { ++ HashAlg = ReadUnaligned16 (DigestListBin); ++ TotalSize += sizeof (HashAlg); ++ DigestListBin = (UINT8 *)DigestListBin + sizeof (HashAlg); ++ ++ DigestSize = GetHashSizeFromAlgo (HashAlg); ++ TotalSize += DigestSize; ++ DigestListBin = (UINT8 *)DigestListBin + DigestSize; ++ } ++ ++ return TotalSize; ++} ++ ++/** ++ Add a new entry to the Event Log. The call chain is like below: ++ CcaDxeLogHashEvent -> CcaDxeLogEvent -> TcgCommonLogEvent ++ ++ Before this function is called, the event information (including the digest) ++ is ready. ++ ++ @param[in] DigestList A list of digest. ++ @param[in,out] NewEventHdr Pointer to a CC_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS The new event log entry was added. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++**/ ++EFI_STATUS ++CcaDxeLogHashEvent ( ++ IN TPML_DIGEST_VALUES *DigestList, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_TPL OldTpl; ++ EFI_STATUS RetStatus; ++ CC_EVENT CcEvent; ++ UINT8 *DigestBuffer; ++ UINT32 *EventSizePtr; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ ++ RetStatus = EFI_SUCCESS; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ ZeroMem (&CcEvent, sizeof (CcEvent)); ++ CcEvent.MrIndex = NewEventHdr->MrIndex; ++ CcEvent.EventType = NewEventHdr->EventType; ++ DigestBuffer = (UINT8 *)&CcEvent.Digests; ++ EventSizePtr = CopyDigestListToBuffer (DigestBuffer, DigestList, HASH_ALG_SHA256); ++ CopyMem (EventSizePtr, &NewEventHdr->EventSize, sizeof (NewEventHdr->EventSize)); ++ ++ // ++ // Enter critical region ++ // ++ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &CcEvent, ++ sizeof (CcEvent.MrIndex) + sizeof (CcEvent.EventType) + GetDigestListBinSize (DigestBuffer) + sizeof (CcEvent.EventSize), ++ NewEventData, ++ NewEventHdr->EventSize ++ ); ++ if (Status != EFI_SUCCESS) { ++ RetStatus = Status; ++ } ++ ++ gBS->RestoreTPL (OldTpl); ++ ++ return RetStatus; ++} ++ ++/** ++ Do a hash operation on a data buffer, extend a specific REM with the hash result, ++ and add an entry to the Event Log. ++ ++ @param[in] Flags Bitmap providing additional information. ++ @param[in] HashData Physical address of the start of the data buffer ++ to be hashed, extended, and logged. ++ @param[in] HashDataLen The length, in bytes, of the buffer referenced by HashData ++ @param[in, out] NewEventHdr Pointer to a CC_EVENT_HDR data structure. ++ @param[in] NewEventData Pointer to the new event data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES No enough memory to log the new event. ++ @retval EFI_DEVICE_ERROR The command was unsuccessful. ++ ++**/ ++EFI_STATUS ++CcaDxeHashLogExtendEvent ( ++ IN UINT64 Flags, ++ IN UINT8 *HashData, ++ IN UINT64 HashDataLen, ++ IN OUT CC_EVENT_HDR *NewEventHdr, ++ IN UINT8 *NewEventData ++ ) ++{ ++ EFI_STATUS Status; ++ TPML_DIGEST_VALUES DigestList; ++ CC_EVENT_HDR NoActionEvent; ++ ++ if (NewEventHdr->EventType == EV_NO_ACTION) { ++ // ++ // Do not do REM extend for EV_NO_ACTION ++ // ++ Status = EFI_SUCCESS; ++ InitNoActionEvent (&NoActionEvent, NewEventHdr->EventSize); ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&(NoActionEvent.Digests), NewEventHdr, NewEventData); ++ } ++ ++ return Status; ++ } ++ ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = HashAndExtend ( ++ NewEventHdr->MrIndex, ++ HashData, ++ (UINTN)HashDataLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&DigestList, NewEventHdr, NewEventData); ++ } ++ } ++ ++ return Status; + } + + /** +@@ -174,7 +742,50 @@ CcaHashLogExtendEvent ( + IN EFI_CC_EVENT *CcEvent + ) + { +- return EFI_UNSUPPORTED; ++ EFI_STATUS Status; ++ CC_EVENT_HDR NewEventHdr; ++ ++ DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent ...\n")); ++ ++ if ((This == NULL) || (CcEvent == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ // ++ // Do not check hash data size for EV_NO_ACTION event. ++ // ++ if ((CcEvent->Header.EventType != EV_NO_ACTION) && (DataToHash == 0)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Size < CcEvent->Header.HeaderSize + sizeof (UINT32)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Header.MrIndex == CC_MR_INDEX_0_RIM) { ++ DEBUG ((DEBUG_ERROR, "%a: RIM cannot be extended.\n", __func__)); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (CcEvent->Header.MrIndex >= CC_MR_INDEX_INVALID) { ++ DEBUG ((DEBUG_ERROR, "%a: MrIndex is invalid. (%d)\n", __func__, CcEvent->Header.MrIndex)); ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ NewEventHdr.MrIndex = CcEvent->Header.MrIndex; ++ NewEventHdr.EventType = CcEvent->Header.EventType; ++ NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize; ++ ++ Status = CcaDxeHashLogExtendEvent ( ++ Flags, ++ (UINT8 *)(UINTN)DataToHash, ++ DataToHashLen, ++ &NewEventHdr, ++ CcEvent->Event ++ ); ++ ++ DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent - %r\n", Status)); ++ return Status; + } + + EFI_CC_MEASUREMENT_PROTOCOL mCcaProtocol = { +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index d85e714..f7e872e 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -612,5 +612,9 @@ + # Cc Measurement Protocol for Cca guest + # + !if $(CC_MEASUREMENT_ENABLE) == TRUE +- ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++ ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf { ++ ++ HashLib|ArmVirtPkg/Library/HashLibCca/HashLibCca.inf ++ NULL|SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++ } + !endif +\ No newline at end of file +diff --git a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +index 77866bb..133e22d 100644 +--- a/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h ++++ b/MdePkg/Include/IndustryStandard/UefiTcgPlatform.h +@@ -438,6 +438,7 @@ typedef struct tdTCG_PCClientTaggedEvent { + + #define TCG_Sp800_155_PlatformId_Event_SIGNATURE "SP800-155 Event" + #define TCG_Sp800_155_PlatformId_Event2_SIGNATURE "SP800-155 Event2" ++#define TCG_Sp800_155_PlatformId_Event3_SIGNATURE "SP800-155 Event3" + + typedef struct tdTCG_Sp800_155_PlatformId_Event2 { + UINT8 Signature[16]; +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +index 2e341c6..9e27799 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.c +@@ -10,7 +10,6 @@ SPDX-License-Identifier: BSD-2-Clause-Patent + #include + #include + #include +-#include + #include + #include + #include +diff --git a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +index cecd784..c1002a8 100644 +--- a/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf ++++ b/SecurityPkg/Library/HashInstanceLibSha256/HashInstanceLibSha256.inf +@@ -36,6 +36,5 @@ + BaseLib + BaseMemoryLib + DebugLib +- Tpm2CommandLib + MemoryAllocationLib + BaseCryptLib +-- +1.8.3.1 + diff --git a/0105-implement-CcaGetEventLog-of-EFI_CC_MEASUREMENT_PROTO.patch b/0105-implement-CcaGetEventLog-of-EFI_CC_MEASUREMENT_PROTO.patch new file mode 100644 index 0000000..54d695c --- /dev/null +++ b/0105-implement-CcaGetEventLog-of-EFI_CC_MEASUREMENT_PROTO.patch @@ -0,0 +1,381 @@ +From 092d90c62fe3cb221102ce3e79dd8d44acc8f16f Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:38:31 -0400 +Subject: [PATCH 18/22] implement CcaGetEventLog of EFI_CC_MEASUREMENT_PROTOCOL + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 343 +++++++++++++++++++++++++++++++++- + 1 file changed, 342 insertions(+), 1 deletion(-) + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index 912666c..d731043 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -146,6 +146,62 @@ CopyDigestListToBuffer ( + + EFI_HANDLE mImageHandle; + ++#define COLUME_SIZE (16 * 2) ++ ++/** ++ ++ This function dump raw data. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpData ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ ++ for (Index = 0; Index < Size; Index++) { ++ DEBUG ((DEBUG_INFO, Index == COLUME_SIZE/2 ? " | %02x" : " %02x", (UINTN)Data[Index])); ++ } ++} ++ ++/** ++ ++ This function dump raw data with colume format. ++ ++ @param Data raw data ++ @param Size raw data size ++ ++**/ ++VOID ++InternalDumpHex ( ++ IN UINT8 *Data, ++ IN UINTN Size ++ ) ++{ ++ UINTN Index; ++ UINTN Count; ++ UINTN Left; ++ ++ Count = Size / COLUME_SIZE; ++ Left = Size % COLUME_SIZE; ++ for (Index = 0; Index < Count; Index++) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, COLUME_SIZE); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++ ++ if (Left != 0) { ++ DEBUG ((DEBUG_INFO, "%04x: ", Index * COLUME_SIZE)); ++ InternalDumpData (Data + Index * COLUME_SIZE, Left); ++ DEBUG ((DEBUG_INFO, "\n")); ++ } ++} ++ + /** + + This function initialize CC_EVENT_HDR for EV_NO_ACTION +@@ -233,6 +289,253 @@ CcaGetCapability ( + } + + /** ++ This function dump PCR event. ++ CC Event log reuse the TCG PCR Event spec. ++ The first event in the event log is the SHA1 log format. ++ There is only ONE TCG_PCR_EVENT in CC Event log. ++ ++ @param[in] EventHdr TCG PCR event structure. ++**/ ++VOID ++DumpPcrEvent ( ++ IN TCG_PCR_EVENT_HDR *EventHdr ++ ) ++{ ++ UINTN Index; ++ ++ DEBUG ((DEBUG_INFO, " Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", EventHdr->PCRIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", EventHdr->EventType)); ++ DEBUG ((DEBUG_INFO, " Digest - ")); ++ for (Index = 0; Index < sizeof (TCG_DIGEST); Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", EventHdr->Digest.digest[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventHdr->EventSize)); ++ InternalDumpHex ((UINT8 *)(EventHdr + 1), EventHdr->EventSize); ++} ++ ++/** ++ This function dump TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++VOID ++DumpTcgEfiSpecIdEventStruct ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINTN Index; ++ UINT8 *VendorInfoSize; ++ UINT8 *VendorInfo; ++ UINT32 NumberOfAlgorithms; ++ ++ DEBUG ((DEBUG_INFO, " TCG_EfiSpecIDEventStruct:\n")); ++ DEBUG ((DEBUG_INFO, " signature - '")); ++ for (Index = 0; Index < sizeof (TcgEfiSpecIdEventStruct->signature); Index++) { ++ DEBUG ((DEBUG_INFO, "%c", TcgEfiSpecIdEventStruct->signature[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "'\n")); ++ DEBUG ((DEBUG_INFO, " platformClass - 0x%08x\n", TcgEfiSpecIdEventStruct->platformClass)); ++ DEBUG ((DEBUG_INFO, " specVersion - %d.%d%d\n", TcgEfiSpecIdEventStruct->specVersionMajor, TcgEfiSpecIdEventStruct->specVersionMinor, TcgEfiSpecIdEventStruct->specErrata)); ++ DEBUG ((DEBUG_INFO, " uintnSize - 0x%02x\n", TcgEfiSpecIdEventStruct->uintnSize)); ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ DEBUG ((DEBUG_INFO, " NumberOfAlgorithms - 0x%08x\n", NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ for (Index = 0; Index < NumberOfAlgorithms; Index++) { ++ DEBUG ((DEBUG_INFO, " digest(%d)\n", Index)); ++ DEBUG ((DEBUG_INFO, " algorithmId - 0x%04x\n", DigestSize[Index].algorithmId)); ++ DEBUG ((DEBUG_INFO, " digestSize - 0x%04x\n", DigestSize[Index].digestSize)); ++ } ++ ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ DEBUG ((DEBUG_INFO, " VendorInfoSize - 0x%02x\n", *VendorInfoSize)); ++ VendorInfo = VendorInfoSize + 1; ++ DEBUG ((DEBUG_INFO, " VendorInfo - ")); ++ for (Index = 0; Index < *VendorInfoSize; Index++) { ++ DEBUG ((DEBUG_INFO, "%02x ", VendorInfo[Index])); ++ } ++ ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function get size of TCG_EfiSpecIDEventStruct. ++ ++ @param[in] TcgEfiSpecIdEventStruct A pointer to TCG_EfiSpecIDEventStruct. ++**/ ++UINTN ++GetTcgEfiSpecIdEventStructSize ( ++ IN TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct ++ ) ++{ ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ ++ CopyMem (&NumberOfAlgorithms, TcgEfiSpecIdEventStruct + 1, sizeof (NumberOfAlgorithms)); ++ ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct + sizeof (*TcgEfiSpecIdEventStruct) + sizeof (NumberOfAlgorithms)); ++ VendorInfoSize = (UINT8 *)&DigestSize[NumberOfAlgorithms]; ++ return sizeof (TCG_EfiSpecIDEventStruct) + sizeof (UINT32) + (NumberOfAlgorithms * sizeof (TCG_EfiSpecIdEventAlgorithmSize)) + sizeof (UINT8) + (*VendorInfoSize); ++} ++ ++/** ++ This function dump CCA Event (including the Digests). ++ ++ @param[in] CcEvent CCA Event structure. ++**/ ++VOID ++DumpCcEvent ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DEBUG ((DEBUG_INFO, "Cc Event:\n")); ++ DEBUG ((DEBUG_INFO, " MrIndex - %d\n", CcEvent->MrIndex)); ++ DEBUG ((DEBUG_INFO, " EventType - 0x%08x\n", CcEvent->EventType)); ++ DEBUG ((DEBUG_INFO, " DigestCount: 0x%08x\n", CcEvent->Digests.count)); ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DEBUG ((DEBUG_INFO, " HashAlgo : 0x%04x\n", HashAlgo)); ++ DEBUG ((DEBUG_INFO, " Digest(%d): \n", DigestIndex)); ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ InternalDumpHex (DigestBuffer, DigestSize); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ DEBUG ((DEBUG_INFO, " EventSize - 0x%08x\n", EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ InternalDumpHex (EventBuffer, EventSize); ++ DEBUG ((DEBUG_INFO, "\n")); ++} ++ ++/** ++ This function returns size of CC Table event. ++ ++ @param[in] CcEvent CC Table event structure. ++ ++ @return size of CC event. ++**/ ++UINTN ++GetCcEventSize ( ++ IN CC_EVENT *CcEvent ++ ) ++{ ++ UINT32 DigestIndex; ++ UINT32 DigestCount; ++ TPMI_ALG_HASH HashAlgo; ++ UINT32 DigestSize; ++ UINT8 *DigestBuffer; ++ UINT32 EventSize; ++ UINT8 *EventBuffer; ++ ++ DigestCount = CcEvent->Digests.count; ++ HashAlgo = CcEvent->Digests.digests[0].hashAlg; ++ DigestBuffer = (UINT8 *)&CcEvent->Digests.digests[0].digest; ++ for (DigestIndex = 0; DigestIndex < DigestCount; DigestIndex++) { ++ DigestSize = GetHashSizeFromAlgo (HashAlgo); ++ // ++ // Prepare next ++ // ++ CopyMem (&HashAlgo, DigestBuffer + DigestSize, sizeof (TPMI_ALG_HASH)); ++ DigestBuffer = DigestBuffer + DigestSize + sizeof (TPMI_ALG_HASH); ++ } ++ ++ DigestBuffer = DigestBuffer - sizeof (TPMI_ALG_HASH); ++ ++ CopyMem (&EventSize, DigestBuffer, sizeof (CcEvent->EventSize)); ++ EventBuffer = DigestBuffer + sizeof (CcEvent->EventSize); ++ ++ return (UINTN)EventBuffer + EventSize - (UINTN)CcEvent; ++} ++ ++/** ++ This function dump CC event log. ++ Now only supports EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ ++ @param[in] EventLogFormat The type of the event log for which the information is requested. ++ @param[in] EventLogLocation A pointer to the memory address of the event log. ++ @param[in] EventLogLastEntry If the Event Log contains more than one entry, this is a pointer to the ++ address of the start of the last entry in the event log in memory. ++ @param[in] FinalEventsTable A pointer to the memory address of the final event table. ++**/ ++VOID ++DumpCcEventLog ( ++ IN EFI_CC_EVENT_LOG_FORMAT EventLogFormat, ++ IN EFI_PHYSICAL_ADDRESS EventLogLocation, ++ IN EFI_PHYSICAL_ADDRESS EventLogLastEntry, ++ IN EFI_CC_FINAL_EVENTS_TABLE *FinalEventsTable ++ ) ++{ ++ TCG_PCR_EVENT_HDR *EventHdr; ++ CC_EVENT *CcEvent; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINTN NumberOfEvents; ++ ++ DEBUG ((DEBUG_INFO, "EventLogFormat: (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ // ++ // Dump first event. ++ // The first event is always the TCG_PCR_EVENT_HDR ++ // After this event is a TCG_EfiSpecIDEventStruct ++ // ++ EventHdr = (TCG_PCR_EVENT_HDR *)(UINTN)EventLogLocation; ++ DumpPcrEvent (EventHdr); ++ ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)(EventHdr + 1); ++ DumpTcgEfiSpecIdEventStruct (TcgEfiSpecIdEventStruct); ++ ++ // ++ // Then the CcEvent (Its structure is similar to TCG_PCR_EVENT2) ++ // ++ CcEvent = (CC_EVENT *)((UINTN)TcgEfiSpecIdEventStruct + GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct)); ++ while ((UINTN)CcEvent <= EventLogLastEntry) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ ++ if (FinalEventsTable == NULL) { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: NOT FOUND\n")); ++ } else { ++ DEBUG ((DEBUG_INFO, "FinalEventsTable: (0x%x)\n", FinalEventsTable)); ++ DEBUG ((DEBUG_INFO, " Version: (0x%x)\n", FinalEventsTable->Version)); ++ DEBUG ((DEBUG_INFO, " NumberOfEvents: (0x%x)\n", FinalEventsTable->NumberOfEvents)); ++ ++ CcEvent = (CC_EVENT *)(UINTN)(FinalEventsTable + 1); ++ for (NumberOfEvents = 0; NumberOfEvents < FinalEventsTable->NumberOfEvents; NumberOfEvents++) { ++ DumpCcEvent (CcEvent); ++ CcEvent = (CC_EVENT *)((UINTN)CcEvent + GetCcEventSize (CcEvent)); ++ } ++ } ++ ++ return; ++} ++ ++/** + The EFI_CC_MEASUREMENT_PROTOCOL Get Event Log function call allows a caller to + retrieve the address of a given event log and its last entry. + +@@ -259,7 +562,45 @@ CcaGetEventLog ( + OUT BOOLEAN *EventLogTruncated + ) + { +- return EFI_UNSUPPORTED; ++ UINTN Index = 0; ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog ... (0x%x)\n", EventLogFormat)); ++ ASSERT (EventLogFormat == EFI_CC_EVENT_LOG_FORMAT_TCG_2); ++ ++ if (EventLogLocation != NULL) { ++ *EventLogLocation = mCcaDxeData.EventLogAreaStruct[Index].Lasa; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLocation - %x)\n", *EventLogLocation)); ++ } ++ ++ if (EventLogLastEntry != NULL) { ++ if (!mCcaDxeData.EventLogAreaStruct[Index].EventLogStarted) { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)0; ++ } else { ++ *EventLogLastEntry = (EFI_PHYSICAL_ADDRESS)(UINTN)mCcaDxeData.EventLogAreaStruct[Index].LastEvent; ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogLastEntry - %x)\n", *EventLogLastEntry)); ++ } ++ ++ if (EventLogTruncated != NULL) { ++ *EventLogTruncated = mCcaDxeData.EventLogAreaStruct[Index].EventLogTruncated; ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog (EventLogTruncated - %x)\n", *EventLogTruncated)); ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaGetEventLog - %r\n", EFI_SUCCESS)); ++ ++ // Dump Event Log for debug purpose ++ if ((EventLogLocation != NULL) && (EventLogLastEntry != NULL)) { ++ DumpCcEventLog (EventLogFormat, *EventLogLocation, *EventLogLastEntry, mCcaDxeData.FinalEventsTable[Index]); ++ } ++ ++ // ++ // All events generated after the invocation of EFI_TCG2_GET_EVENT_LOG SHALL be stored ++ // in an instance of an EFI_CONFIGURATION_TABLE named by the VendorGuid of EFI_TCG2_FINAL_EVENTS_TABLE_GUID. ++ // ++ mCcaDxeData.GetEventLogCalled[Index] = TRUE; ++ ++ return EFI_SUCCESS; + } + + /** +-- +1.8.3.1 + diff --git a/0106-setup-CC-eventlog-and-install-its-ACPI-table.patch b/0106-setup-CC-eventlog-and-install-its-ACPI-table.patch new file mode 100644 index 0000000..594fcf9 --- /dev/null +++ b/0106-setup-CC-eventlog-and-install-its-ACPI-table.patch @@ -0,0 +1,342 @@ +From 214daa7e5876ed1fe6728055469ba48a3b195717 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:39:17 -0400 +Subject: [PATCH 19/22] setup CC eventlog and install its ACPI table + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 271 ++++++++++++++++++++++++++++++++++ + MdeModulePkg/MdeModulePkg.dec | 2 +- + 2 files changed, 272 insertions(+), 1 deletion(-) + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index d731043..a7bb184 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -36,6 +36,11 @@ + #define CC_MR_INDEX_INVALID 4 + + typedef struct { ++ CHAR16 *VariableName; ++ EFI_GUID *VendorGuid; ++} VARIABLE_TYPE; ++ ++typedef struct { + EFI_CC_EVENT_LOG_FORMAT EventLogFormat; + EFI_PHYSICAL_ADDRESS Lasa; + UINT64 Laml; +@@ -71,6 +76,22 @@ CCA_DXE_DATA mCcaDxeData = { + }, + }; + ++EFI_CC_EVENTLOG_ACPI_TABLE mCcaEventlogAcpiTemplate = { ++ { ++ EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, ++ sizeof (mCcaEventlogAcpiTemplate), ++ EFI_CC_EVENTLOG_ACPI_TABLE_REVISION, ++ // ++ // Compiler initializes the remaining bytes to 0 ++ // These fields should be filled in production ++ // ++ }, ++ { EFI_CC_TYPE_CCA, 0 }, // CcType ++ 0, // rsvd ++ 0, // laml ++ 0, // lasa ++}; ++ + // + // Currently SHA256 is supported. + // +@@ -1136,6 +1157,237 @@ EFI_CC_MEASUREMENT_PROTOCOL mCcaProtocol = { + CcaMapPcrToMrIndex + }; + ++#define CCA_HASH_COUNT 1 ++#define TEMP_BUF_LEN (sizeof(TCG_EfiSpecIDEventStruct) + sizeof(UINT32) \ ++ + (CCA_HASH_COUNT * sizeof(TCG_EfiSpecIdEventAlgorithmSize)) + sizeof(UINT8)) ++ ++/** ++ Initialize the CC Event Log and log events passed from the PEI phase. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ ++**/ ++EFI_STATUS ++SetupCcEventLog ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_PHYSICAL_ADDRESS Lasa; ++ UINTN Index; ++ TCG_EfiSpecIDEventStruct *TcgEfiSpecIdEventStruct; ++ UINT8 TempBuf[TEMP_BUF_LEN]; ++ TCG_PCR_EVENT_HDR SpecIdEvent; ++ TCG_EfiSpecIdEventAlgorithmSize *DigestSize; ++ TCG_EfiSpecIdEventAlgorithmSize *TempDigestSize; ++ UINT8 *VendorInfoSize; ++ UINT32 NumberOfAlgorithms; ++ EFI_CC_EVENT_LOG_FORMAT LogFormat; ++ EFI_PEI_HOB_POINTERS GuidHob; ++ CC_EVENT_HDR NoActionEvent; ++ ++ Status = EFI_SUCCESS; ++ DEBUG ((DEBUG_INFO, "SetupCcEventLog\n")); ++ ++ Index = 0; ++ LogFormat = EFI_CC_EVENT_LOG_FORMAT_TCG_2; ++ ++ // ++ // 1. Create Log Area ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ ++ // allocate pages for CC Event log ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcgLogAreaMinLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ mCcaDxeData.EventLogAreaStruct[Index].Lasa = Lasa; ++ mCcaDxeData.EventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcgLogAreaMinLen); ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Report CC event log address and length, so that they can be reported in ++ // CC ACPI table. Ignore the return status, because those fields are optional. ++ // ++ PcdSet32S (PcdCcEventlogAcpiTableLaml, (UINT32)mCcaDxeData.EventLogAreaStruct[Index].Laml); ++ PcdSet64S (PcdCcEventlogAcpiTableLasa, mCcaDxeData.EventLogAreaStruct[Index].Lasa); ++ ++ // ++ // To initialize them as 0xFF is recommended ++ // because the OS can know the last entry for that. ++ // ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcgLogAreaMinLen), 0xFF); ++ ++ // ++ // Create first entry for Log Header Entry Data ++ // ++ ++ // ++ // TcgEfiSpecIdEventStruct ++ // ++ TcgEfiSpecIdEventStruct = (TCG_EfiSpecIDEventStruct *)TempBuf; ++ CopyMem (TcgEfiSpecIdEventStruct->signature, TCG_EfiSpecIDEventStruct_SIGNATURE_03, sizeof (TcgEfiSpecIdEventStruct->signature)); ++ ++ TcgEfiSpecIdEventStruct->platformClass = PcdGet8 (PcdTpmPlatformClass); ++ ++ TcgEfiSpecIdEventStruct->specVersionMajor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MAJOR_TPM2; ++ TcgEfiSpecIdEventStruct->specVersionMinor = TCG_EfiSpecIDEventStruct_SPEC_VERSION_MINOR_TPM2; ++ TcgEfiSpecIdEventStruct->specErrata = TCG_EfiSpecIDEventStruct_SPEC_ERRATA_TPM2; ++ TcgEfiSpecIdEventStruct->uintnSize = sizeof (UINTN)/sizeof (UINT32); ++ NumberOfAlgorithms = 0; ++ DigestSize = (TCG_EfiSpecIdEventAlgorithmSize *)((UINT8 *)TcgEfiSpecIdEventStruct ++ + sizeof (*TcgEfiSpecIdEventStruct) ++ + sizeof (NumberOfAlgorithms)); ++ ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ TempDigestSize->algorithmId = TPM_ALG_SHA256; ++ TempDigestSize->digestSize = SHA256_DIGEST_SIZE; ++ NumberOfAlgorithms++; ++ ++ CopyMem (TcgEfiSpecIdEventStruct + 1, &NumberOfAlgorithms, sizeof (NumberOfAlgorithms)); ++ TempDigestSize = DigestSize; ++ TempDigestSize += NumberOfAlgorithms; ++ VendorInfoSize = (UINT8 *)TempDigestSize; ++ *VendorInfoSize = 0; ++ ++ SpecIdEvent.PCRIndex = 1; // PCRIndex 0 maps to MrIndex 1 ++ SpecIdEvent.EventType = EV_NO_ACTION; ++ ZeroMem (&SpecIdEvent.Digest, sizeof (SpecIdEvent.Digest)); ++ SpecIdEvent.EventSize = (UINT32)GetTcgEfiSpecIdEventStructSize (TcgEfiSpecIdEventStruct); ++ ++ // ++ // CC Event log re-use the spec of TCG2 Event log. ++ // Log TcgEfiSpecIdEventStruct as the first Event. Event format is TCG_PCR_EVENT. ++ // TCG EFI Protocol Spec. Section 5.3 Event Log Header ++ // TCG PC Client PFP spec. Section 9.2 Measurement Event Entries and Log ++ // ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &SpecIdEvent, ++ sizeof (SpecIdEvent), ++ (UINT8 *)TcgEfiSpecIdEventStruct, ++ SpecIdEvent.EventSize ++ ); ++ // ++ // record the offset at the end of 800-155 event. ++ // the future 800-155 event can be inserted here. ++ // ++ mCcaDxeData.EventLogAreaStruct[Index].Next800155EventOffset = mCcaDxeData.EventLogAreaStruct[Index].EventLogSize; ++ ++ // ++ // Tcg800155PlatformIdEvent. Event format is TCG_PCR_EVENT2 ++ // ++ GuidHob.Guid = GetFirstGuidHob (&gTcg800155PlatformIdEventHobGuid); ++ while (GuidHob.Guid != NULL) { ++ InitNoActionEvent (&NoActionEvent, GET_GUID_HOB_DATA_SIZE (GuidHob.Guid)); ++ ++ Status = CcaDxeLogEvent ( ++ LogFormat, ++ &NoActionEvent, ++ sizeof (NoActionEvent.MrIndex) + sizeof (NoActionEvent.EventType) + GetDigestListBinSize (&NoActionEvent.Digests) + sizeof (NoActionEvent.EventSize), ++ GET_GUID_HOB_DATA (GuidHob.Guid), ++ GET_GUID_HOB_DATA_SIZE (GuidHob.Guid) ++ ); ++ ++ GuidHob.Guid = GET_NEXT_HOB (GuidHob); ++ GuidHob.Guid = GetNextGuidHob (&gTcg800155PlatformIdEventHobGuid, GuidHob.Guid); ++ } ++ ++ // ++ // 2. Create Final Log Area ++ // ++ Status = gBS->AllocatePages ( ++ AllocateAnyPages, ++ EfiACPIMemoryNVS, ++ EFI_SIZE_TO_PAGES (PcdGet32 (PcdTcg2FinalLogAreaLen)), ++ &Lasa ++ ); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ SetMem ((VOID *)(UINTN)Lasa, PcdGet32 (PcdTcg2FinalLogAreaLen), 0xFF); ++ ++ // ++ // Initialize ++ // ++ mCcaDxeData.FinalEventsTable[Index] = (VOID *)(UINTN)Lasa; ++ (mCcaDxeData.FinalEventsTable[Index])->Version = EFI_TCG2_FINAL_EVENTS_TABLE_VERSION; ++ (mCcaDxeData.FinalEventsTable[Index])->NumberOfEvents = 0; ++ ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogFormat = LogFormat; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa = Lasa + sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Laml = PcdGet32 (PcdTcg2FinalLogAreaLen) - sizeof (EFI_CC_FINAL_EVENTS_TABLE); ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogSize = 0; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].LastEvent = (VOID *)(UINTN)mCcaDxeData.FinalEventLogAreaStruct[Index].Lasa; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogStarted = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].EventLogTruncated = FALSE; ++ mCcaDxeData.FinalEventLogAreaStruct[Index].Next800155EventOffset = 0; ++ ++ // ++ // Install to configuration table for EFI_CC_EVENT_LOG_FORMAT_TCG_2 ++ // ++ Status = gBS->InstallConfigurationTable (&gEfiCcFinalEventsTableGuid, (VOID *)mCcaDxeData.FinalEventsTable[Index]); ++ if (EFI_ERROR (Status)) { ++ return Status; ++ } ++ ++ return Status; ++} ++ ++/** ++ Install ACPI Table when ACPI Table Protocol is available. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++InstallAcpiTable ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ UINTN TableKey; ++ EFI_STATUS Status; ++ EFI_ACPI_TABLE_PROTOCOL *AcpiTable; ++ ++ Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **)&AcpiTable); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "CCA: AcpiTableProtocol is not installed. %r\n", Status)); ++ return; ++ } ++ ++ mCcaEventlogAcpiTemplate.Laml = (UINT64)PcdGet32 (PcdCcEventlogAcpiTableLaml); ++ mCcaEventlogAcpiTemplate.Lasa = PcdGet64 (PcdCcEventlogAcpiTableLasa); ++ CopyMem (mCcaEventlogAcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mCcaEventlogAcpiTemplate.Header.OemId)); ++ mCcaEventlogAcpiTemplate.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); ++ mCcaEventlogAcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision); ++ mCcaEventlogAcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); ++ mCcaEventlogAcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); ++ ++ // ++ // Construct ACPI Table ++ Status = AcpiTable->InstallAcpiTable ( ++ AcpiTable, ++ &mCcaEventlogAcpiTemplate, ++ mCcaEventlogAcpiTemplate.Header.Length, ++ &TableKey ++ ); ++ ASSERT_EFI_ERROR (Status); ++ ++ DEBUG ((DEBUG_INFO, "CCA Eventlog ACPI Table is installed.\n")); ++} ++ + /** + The function install CcaTcg2 protocol. + +@@ -1169,6 +1421,7 @@ DriverEntry ( + ) + { + EFI_STATUS Status; ++ VOID *Registration; + + if (!IsRealm ()) { + return EFI_UNSUPPORTED; +@@ -1194,10 +1447,28 @@ DriverEntry ( + mCcaDxeData.BsCap.SupportedEventLogs = EFI_CC_EVENT_LOG_FORMAT_TCG_2; + + // ++ // Setup the log area and copy event log from hob list to it ++ // ++ Status = SetupCcEventLog (); ++ ASSERT_EFI_ERROR (Status); ++ ++ // + // Install CcMeasurementProtocol + // + Status = InstallCcMeasurementProtocol (); + DEBUG ((DEBUG_INFO, "InstallCcMeasurementProtocol - %r\n", Status)); + ++ if (Status == EFI_SUCCESS) { ++ // ++ // Create event callback to install CC EventLog ACPI Table ++ EfiCreateProtocolNotifyEvent (&gEfiAcpiTableProtocolGuid, TPL_CALLBACK, InstallAcpiTable, NULL, &Registration); ++ } else { ++ // ++ // Cc measurement feature is crucial to a Realm and it shall stop running immediately ++ // when it is failed to be installed. ++ DEBUG ((DEBUG_ERROR, "%a: CcMeasurement protocol failed to be installed - %r\n", __func__, Status)); ++ CpuDeadLoop (); ++ } ++ + return Status; + } +\ No newline at end of file +diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec +index 2edcc2d..f61478a 100644 +--- a/MdeModulePkg/MdeModulePkg.dec ++++ b/MdeModulePkg/MdeModulePkg.dec +@@ -1984,7 +1984,7 @@ + + ## Default OEM ID for ACPI table creation, its length must be 0x6 bytes to follow ACPI specification. + # @Prompt Default OEM ID for ACPI table creation. +- gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"INTEL "|VOID*|0x30001034 ++ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId|"Huawei "|VOID*|0x30001034 + + ## Default OEM Table ID for ACPI table creation, it is "EDK2 ". + # According to ACPI specification, this field is particularly useful when +-- +1.8.3.1 + diff --git a/0107-enable-CC-measurement-for-EFI-boot-variables.patch b/0107-enable-CC-measurement-for-EFI-boot-variables.patch new file mode 100644 index 0000000..3c2e0c0 --- /dev/null +++ b/0107-enable-CC-measurement-for-EFI-boot-variables.patch @@ -0,0 +1,612 @@ +From 7be18410ac1a1feb84909616cc433a9b82be3741 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:40:02 -0400 +Subject: [PATCH 20/22] enable CC measurement for EFI boot variables + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 538 ++++++++++++++++++++++++++++++++++ + ArmVirtPkg/ArmVirtQemu.dsc | 12 +- + 2 files changed, 548 insertions(+), 2 deletions(-) + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index a7bb184..71ac4a7 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -76,6 +76,17 @@ CCA_DXE_DATA mCcaDxeData = { + }, + }; + ++UINTN mBootAttempts = 0; ++CHAR16 mBootVarName[] = L"BootOrder"; ++ ++VARIABLE_TYPE mVariableType[] = { ++ { EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid }, ++ { EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid }, ++}; ++ + EFI_CC_EVENTLOG_ACPI_TABLE mCcaEventlogAcpiTemplate = { + { + EFI_CC_EVENTLOG_ACPI_TABLE_SIGNATURE, +@@ -1345,6 +1356,501 @@ SetupCcEventLog ( + } + + /** ++ Measure and log an action string, and extend the measurement result into REM. ++ ++ @param[in] MrIndex MrIndex to extend ++ @param[in] String A specific string that indicates an Action event. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++CcaMeasureAction ( ++ IN UINT32 MrIndex, ++ IN CHAR8 *String ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = (UINT32)AsciiStrLen (String); ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)String, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)String ++ ); ++} ++ ++/** ++ Measure and log EFI handoff tables, and extend the measurement result into PCR[1]. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureHandoffTables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ Status = EFI_SUCCESS; ++ ++ // TODO: may delete this function ++ if (PcdGet8 (PcdTpmPlatformClass) == TCG_PLATFORM_TYPE_SERVER) { ++ DEBUG ((DEBUG_ERROR, "MeasureHandoffTables: TCG_PLATFORM_TYPE_SERVER")); ++ } ++ ++ return Status; ++} ++ ++/** ++ Measure and log Separator event, and extend the measurement result into a specific PCR. ++ ++ @param[in] MrIndex REM Index. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureSeparatorEvent ( ++ IN UINT32 MrIndex ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ UINT32 EventData; ++ ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent to Rem - %d\n", MrIndex)); ++ ++ EventData = 0; ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EV_SEPARATOR; ++ CcEvent.EventSize = (UINT32)sizeof (EventData); ++ ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)&EventData, ++ sizeof (EventData), ++ &CcEvent, ++ (UINT8 *)&EventData ++ ); ++} ++ ++/** ++ Measure and log an EFI variable, and extend the measurement result into a specific REM. ++ ++ @param[in] MrIndex REM Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[in] VarData The content of the variable data. ++ @param[in] VarSize The size of the variable data. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ IN VOID *VarData, ++ IN UINTN VarSize ++ ) ++{ ++ EFI_STATUS Status; ++ CC_EVENT_HDR CcEvent; ++ UINTN VarNameLength; ++ UEFI_VARIABLE_DATA *VarLog; ++ ++ DEBUG ((DEBUG_INFO, "CcaTcg2Dxe: MeasureVariable (REM - %x, EventType - %x, ", (UINTN)MrIndex, (UINTN)EventType)); ++ DEBUG ((DEBUG_INFO, "VariableName - %s, VendorGuid - %g)\n", VarName, VendorGuid)); ++ ++ VarNameLength = StrLen (VarName); ++ CcEvent.MrIndex = MrIndex; ++ CcEvent.EventType = EventType; ++ ++ CcEvent.EventSize = (UINT32)(sizeof (*VarLog) + VarNameLength * sizeof (*VarName) + VarSize ++ - sizeof (VarLog->UnicodeName) - sizeof (VarLog->VariableData)); ++ ++ VarLog = (UEFI_VARIABLE_DATA *)AllocatePool (CcEvent.EventSize); ++ if (VarLog == NULL) { ++ return EFI_OUT_OF_RESOURCES; ++ } ++ ++ VarLog->VariableName = *VendorGuid; ++ VarLog->UnicodeNameLength = VarNameLength; ++ VarLog->VariableDataLength = VarSize; ++ CopyMem ( ++ VarLog->UnicodeName, ++ VarName, ++ VarNameLength * sizeof (*VarName) ++ ); ++ if ((VarSize != 0) && (VarData != NULL)) { ++ CopyMem ( ++ (CHAR16 *)VarLog->UnicodeName + VarNameLength, ++ VarData, ++ VarSize ++ ); ++ } ++ ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ // ++ // Digest is the event data (UEFI_VARIABLE_DATA) ++ // ++ Status = CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarLog, ++ CcEvent.EventSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } else { ++ ASSERT (VarData != NULL); ++ Status = CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)VarData, ++ VarSize, ++ &CcEvent, ++ (UINT8 *)VarLog ++ ); ++ } ++ ++ FreePool (VarLog); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI variable, and extend the measurement result into a specific REM. ++ ++ @param[in] MrIndex REM Index. ++ @param[in] EventType Event type. ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureVariable ( ++ IN UINT32 MrIndex, ++ IN TCG_EVENTTYPE EventType, ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ EFI_STATUS Status; ++ ++ Status = GetVariable2 (VarName, VendorGuid, VarData, VarSize); ++ if (EventType == EV_EFI_VARIABLE_DRIVER_CONFIG) { ++ if (EFI_ERROR (Status)) { ++ // ++ // It is valid case, so we need handle it. ++ // ++ *VarData = NULL; ++ *VarSize = 0; ++ } ++ } else { ++ // ++ // if status error, VarData is freed and set NULL by GetVariable2 ++ // ++ if (EFI_ERROR (Status)) { ++ return EFI_NOT_FOUND; ++ } ++ } ++ ++ Status = MeasureVariable ( ++ MrIndex, ++ EventType, ++ VarName, ++ VendorGuid, ++ *VarData, ++ *VarSize ++ ); ++ return Status; ++} ++ ++/** ++ Read then Measure and log an EFI boot variable, and extend the measurement result into PCR[1]. ++according to TCG PC Client PFP spec 0021 Section 2.4.4.2 ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureBootVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ MapPcrToMrIndex (1), ++ EV_EFI_VARIABLE_BOOT, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** ++ Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllBootVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ UINT16 *BootOrder; ++ UINTN BootCount; ++ UINTN Index; ++ VOID *BootVarData; ++ UINTN Size; ++ ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &BootCount, ++ (VOID **)&BootOrder ++ ); ++ if ((Status == EFI_NOT_FOUND) || (BootOrder == NULL)) { ++ return EFI_SUCCESS; ++ } ++ ++ if (EFI_ERROR (Status)) { ++ // ++ // BootOrder can't be NULL if status is not EFI_NOT_FOUND ++ // ++ FreePool (BootOrder); ++ return Status; ++ } ++ ++ BootCount /= sizeof (*BootOrder); ++ for (Index = 0; Index < BootCount; Index++) { ++ UnicodeSPrint (mBootVarName, sizeof (mBootVarName), L"Boot%04x", BootOrder[Index]); ++ Status = ReadAndMeasureBootVariable ( ++ mBootVarName, ++ &gEfiGlobalVariableGuid, ++ &Size, ++ &BootVarData ++ ); ++ if (!EFI_ERROR (Status)) { ++ FreePool (BootVarData); ++ } ++ } ++ ++ FreePool (BootOrder); ++ return EFI_SUCCESS; ++} ++ ++/** ++ Ready to Boot Event notification handler. ++ ++ Sequence of OS boot events is measured in this event notification handler. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnReadyToBoot ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ PERF_START_EX (mImageHandle, "EventRec", "CcaTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE); ++ if (mBootAttempts == 0) { ++ // ++ // Measure handoff tables. ++ // ++ Status = MeasureHandoffTables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "HOBs not Measured. Error!\n")); ++ } ++ ++ // ++ // Measure BootOrder & Boot#### variables. ++ // ++ Status = MeasureAllBootVariables (); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Boot Variables not Measured. Error!\n")); ++ } ++ ++ // ++ // 1. This is the first boot attempt. ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ ++ // ++ // 2. Draw a line between pre-boot env and entering post-boot env. ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // REM[0] (i.e. MrIndex 1) is already done. So SepartorEvent shall be extended to ++ // REM[1] (i.e. MrIndex 2) as well. ++ // ++ Status = MeasureSeparatorEvent (CC_MR_INDEX_2_REM1); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "Separator Event not Measured to REM[1]. Error!\n")); ++ } ++ ++ // ++ // 3. Measure GPT. It would be done in SAP driver. ++ // ++ ++ // ++ // 4. Measure PE/COFF OS loader. It would be done in SAP driver. ++ // ++ ++ // ++ // 5. Read & Measure variable. BootOrder already measured. ++ // ++ } else { ++ // ++ // 6. Not first attempt, meaning a return from last attempt ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_RETURNING_FROM_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_RETURNING_FROM_EFI_APPLICATION)); ++ } ++ // ++ // 7. Next boot attempt, measure "Calling EFI Application from Boot Option" again ++ // TCG PC Client PFP spec Section 2.4.4.5 Step 4 ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (4), ++ EFI_CALLING_EFI_APPLICATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_CALLING_EFI_APPLICATION)); ++ } ++ } ++ ++ DEBUG ((DEBUG_INFO, "CcaTcg2Dxe Measure Data when ReadyToBoot\n")); ++ // ++ // Increase boot attempt counter. ++ // ++ mBootAttempts++; ++ PERF_END_EX (mImageHandle, "EventRec", "CcaTcg2Dxe", 0, PERF_ID_CC_TCG2_DXE + 1); ++} ++ ++/** ++ Exit Boot Services Event notification handler. ++ ++ Measure invocation and success of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServices ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure invocation of ExitBootServices, ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_INVOCATION ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_INVOCATION)); ++ } ++ ++ // ++ // Measure success of ExitBootServices ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_SUCCEEDED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_SUCCEEDED)); ++ } ++} ++ ++/** ++ Exit Boot Services Failed Event notification handler. ++ ++ Measure Failure of ExitBootServices. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++ ++**/ ++VOID ++EFIAPI ++OnExitBootServicesFailed ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ ++ // ++ // Measure Failure of ExitBootServices, ++ // ++ Status = CcaMeasureAction ( ++ MapPcrToMrIndex (5), ++ EFI_EXIT_BOOT_SERVICES_FAILED ++ ); ++ if (EFI_ERROR (Status)) { ++ DEBUG ((DEBUG_ERROR, "%a not Measured. Error!\n", EFI_EXIT_BOOT_SERVICES_FAILED)); ++ } ++} ++ ++/** + Install ACPI Table when ACPI Table Protocol is available. + + @param[in] Event Event whose notification function is being invoked +@@ -1421,6 +1927,7 @@ DriverEntry ( + ) + { + EFI_STATUS Status; ++ EFI_EVENT Event; + VOID *Registration; + + if (!IsRealm ()) { +@@ -1453,6 +1960,37 @@ DriverEntry ( + ASSERT_EFI_ERROR (Status); + + // ++ // Measure handoff tables, Boot#### variables etc. ++ // ++ Status = EfiCreateEventReadyToBootEx ( ++ TPL_CALLBACK, ++ OnReadyToBoot, ++ NULL, ++ &Event ++ ); ++ ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServices, ++ NULL, ++ &gEfiEventExitBootServicesGuid, ++ &Event ++ ); ++ ++ // ++ // Measure Exit Boot Service failed ++ // ++ Status = gBS->CreateEventEx ( ++ EVT_NOTIFY_SIGNAL, ++ TPL_NOTIFY, ++ OnExitBootServicesFailed, ++ NULL, ++ &gEventExitBootServicesFailedGuid, ++ &Event ++ ); ++ ++ // + // Install CcMeasurementProtocol + // + Status = InstallCcMeasurementProtocol (); +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index f7e872e..45e7a98 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -86,13 +86,21 @@ + !if $(TPM2_ENABLE) == TRUE + Tpm2CommandLib|SecurityPkg/Library/Tpm2CommandLib/Tpm2CommandLib.inf + Tcg2PhysicalPresenceLib|OvmfPkg/Library/Tcg2PhysicalPresenceLibQemu/DxeTcg2PhysicalPresenceLib.inf +- TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf + TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLib/PeiDxeTpmPlatformHierarchyLib.inf + !else +- TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf + TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf + !endif + ++!if $(TPM2_ENABLE) == TRUE || $(CC_MEASUREMENT_ENABLE) == TRUE ++ # ++ # DxeTpmMeasurementLib supports measurement functions for both TPM and Confidential Computing. ++ # It should be controlled by TPM2_ENABLE and CC_MEASUREMENT_ENABLE. ++ # ++ TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasurementLib.inf ++!else ++ TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf ++!endif ++ + [LibraryClasses.AARCH64] + ArmPlatformLib|ArmVirtPkg/Library/ArmPlatformLibQemu/ArmPlatformLibQemu.inf + ArmCcaLib|ArmVirtPkg/Library/ArmCcaLib/ArmCcaLib.inf +-- +1.8.3.1 + diff --git a/0108-enable-CC-measurement-for-EFI-secure-variables.patch b/0108-enable-CC-measurement-for-EFI-secure-variables.patch new file mode 100644 index 0000000..292f62e --- /dev/null +++ b/0108-enable-CC-measurement-for-EFI-secure-variables.patch @@ -0,0 +1,244 @@ +From 6026e498eeb9bd46db5a76347d5f433ce7ebefb0 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:40:38 -0400 +Subject: [PATCH 21/22] enable CC measurement for EFI secure variables + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 173 ++++++++++++++++++++++++++++++++++ + ArmVirtPkg/ArmVirtQemu.dsc | 13 ++- + 2 files changed, 182 insertions(+), 4 deletions(-) + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index 71ac4a7..3ee04e3 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -1617,6 +1617,37 @@ ReadAndMeasureBootVariable ( + } + + /** ++ Read then Measure and log an EFI Secure variable, and extend the measurement result into PCR[7]. ++ ++ @param[in] VarName A Null-terminated string that is the name of the vendor's variable. ++ @param[in] VendorGuid A unique identifier for the vendor. ++ @param[out] VarSize The size of the variable data. ++ @param[out] VarData Pointer to the content of the variable. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++ReadAndMeasureSecureVariable ( ++ IN CHAR16 *VarName, ++ IN EFI_GUID *VendorGuid, ++ OUT UINTN *VarSize, ++ OUT VOID **VarData ++ ) ++{ ++ return ReadAndMeasureVariable ( ++ MapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ VarName, ++ VendorGuid, ++ VarSize, ++ VarData ++ ); ++} ++ ++/** + Measure and log all EFI boot variables, and extend the measurement result into a specific PCR. + + The EFI boot variables are BootOrder and Boot#### variables. +@@ -1675,6 +1706,141 @@ MeasureAllBootVariables ( + } + + /** ++ Measure and log all EFI Secure variables, and extend the measurement result into a specific PCR. ++ ++ The EFI boot variables are BootOrder and Boot#### variables. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureAllSecureVariables ( ++ VOID ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Data; ++ UINTN DataSize; ++ UINTN Index; ++ ++ Status = EFI_NOT_FOUND; ++ for (Index = 0; Index < sizeof (mVariableType)/sizeof (mVariableType[0]); Index++) { ++ Status = ReadAndMeasureSecureVariable ( ++ mVariableType[Index].VariableName, ++ mVariableType[Index].VendorGuid, ++ &DataSize, ++ &Data ++ ); ++ if (!EFI_ERROR (Status)) { ++ if (Data != NULL) { ++ FreePool (Data); ++ } ++ } ++ } ++ ++ // ++ // Measure DBT if present and not empty ++ // ++ Status = GetVariable2 (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, &Data, &DataSize); ++ if (!EFI_ERROR (Status)) { ++ Status = MeasureVariable ( ++ MapPcrToMrIndex (7), ++ EV_EFI_VARIABLE_DRIVER_CONFIG, ++ EFI_IMAGE_SECURITY_DATABASE2, ++ &gEfiImageSecurityDatabaseGuid, ++ Data, ++ DataSize ++ ); ++ FreePool (Data); ++ } else { ++ DEBUG ((DEBUG_INFO, "Skip measuring variable %s since it's deleted\n", EFI_IMAGE_SECURITY_DATABASE2)); ++ } ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure and log launch of FirmwareDebugger, and extend the measurement result into a specific PCR. ++ ++ @retval EFI_SUCCESS Operation completed successfully. ++ @retval EFI_OUT_OF_RESOURCES Out of memory. ++ @retval EFI_DEVICE_ERROR The operation was unsuccessful. ++ ++**/ ++EFI_STATUS ++MeasureLaunchOfFirmwareDebugger ( ++ VOID ++ ) ++{ ++ CC_EVENT_HDR CcEvent; ++ ++ CcEvent.MrIndex = MapPcrToMrIndex (7); ++ CcEvent.EventType = EV_EFI_ACTION; ++ CcEvent.EventSize = sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1; ++ return CcaDxeHashLogExtendEvent ( ++ 0, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING, ++ sizeof (FIRMWARE_DEBUGGER_EVENT_STRING) - 1, ++ &CcEvent, ++ (UINT8 *)FIRMWARE_DEBUGGER_EVENT_STRING ++ ); ++} ++ ++/** ++ Measure and log all Secure Boot Policy, and extend the measurement result into a specific PCR. ++ ++ Platform firmware adhering to the policy must therefore measure the following values into PCR[7]: (in order listed) ++ - The contents of the SecureBoot variable ++ - The contents of the PK variable ++ - The contents of the KEK variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE variable ++ - The contents of the EFI_IMAGE_SECURITY_DATABASE1 variable ++ - Separator ++ - Entries in the EFI_IMAGE_SECURITY_DATABASE that are used to validate EFI Drivers or EFI Boot Applications in the boot path ++ ++ NOTE: Because of the above, UEFI variables PK, KEK, EFI_IMAGE_SECURITY_DATABASE, ++ EFI_IMAGE_SECURITY_DATABASE1 and SecureBoot SHALL NOT be measured into PCR[3]. ++ ++ @param[in] Event Event whose notification function is being invoked ++ @param[in] Context Pointer to the notification function's context ++**/ ++VOID ++EFIAPI ++MeasureSecureBootPolicy ( ++ IN EFI_EVENT Event, ++ IN VOID *Context ++ ) ++{ ++ EFI_STATUS Status; ++ VOID *Protocol; ++ ++ Status = gBS->LocateProtocol (&gEfiVariableWriteArchProtocolGuid, NULL, (VOID **)&Protocol); ++ if (EFI_ERROR (Status)) { ++ return; ++ } ++ ++ if (PcdGetBool (PcdFirmwareDebuggerInitialized)) { ++ Status = MeasureLaunchOfFirmwareDebugger (); ++ DEBUG ((DEBUG_INFO, "MeasureLaunchOfFirmwareDebugger - %r\n", Status)); ++ } ++ ++ Status = MeasureAllSecureVariables (); ++ DEBUG ((DEBUG_INFO, "MeasureAllSecureVariables - %r\n", Status)); ++ ++ // ++ // We need measure Separator(7) here, because this event must be between SecureBootPolicy (Configure) ++ // and ImageVerification (Authority) ++ // There might be a case that we need measure UEFI image from DriverOrder, besides BootOrder. So ++ // the Authority measurement happen before ReadToBoot event. ++ // ++ Status = MeasureSeparatorEvent (MapPcrToMrIndex (7)); ++ DEBUG ((DEBUG_INFO, "MeasureSeparatorEvent - %r\n", Status)); ++ return; ++} ++ ++/** + Ready to Boot Event notification handler. + + Sequence of OS boot events is measured in this event notification handler. +@@ -1991,6 +2157,13 @@ DriverEntry ( + ); + + // ++ // Create event callback, because we need access variable on SecureBootPolicyVariable ++ // We should use VariableWriteArch instead of VariableArch, because Variable driver ++ // may update SecureBoot value based on last setting. ++ // ++ EfiCreateProtocolNotifyEvent (&gEfiVariableWriteArchProtocolGuid, TPL_CALLBACK, MeasureSecureBootPolicy, NULL, &Registration); ++ ++ // + // Install CcMeasurementProtocol + // + Status = InstallCcMeasurementProtocol (); +diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc +index 45e7a98..0d1e434 100644 +--- a/ArmVirtPkg/ArmVirtQemu.dsc ++++ b/ArmVirtPkg/ArmVirtQemu.dsc +@@ -408,18 +408,23 @@ + # don't use unaligned CopyMem () on the UEFI varstore NOR flash region + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + } +-!if $(SECURE_BOOT_ENABLE) == TRUE + MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf { + ++!if $(SECURE_BOOT_ENABLE) == TRUE + NULL|SecurityPkg/Library/DxeImageVerificationLib/DxeImageVerificationLib.inf +-!if $(TPM2_ENABLE) == TRUE ++!endif ++!if $(TPM2_ENABLE) == TRUE || $(CC_MEASUREMENT_ENABLE) == TRUE ++ # ++ # DxeTpm2MeasureBootLib provides security service of TPM2 measure boot and ++ # Confidential Computing (CC) measure boot. It should be controlled by ++ # TPM2_ENABLE and CC_MEASUREMENT_ENABLE ++ # + NULL|SecurityPkg/Library/DxeTpm2MeasureBootLib/DxeTpm2MeasureBootLib.inf + !endif + } ++!if $(SECURE_BOOT_ENABLE) == TRUE + SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigDxe.inf + OvmfPkg/EnrollDefaultKeys/EnrollDefaultKeys.inf +-!else +- MdeModulePkg/Universal/SecurityStubDxe/SecurityStubDxe.inf + !endif + MdeModulePkg/Universal/CapsuleRuntimeDxe/CapsuleRuntimeDxe.inf + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf +-- +1.8.3.1 + diff --git a/0109-enable-CC-measurement-for-PE-COFF-image.patch b/0109-enable-CC-measurement-for-PE-COFF-image.patch new file mode 100644 index 0000000..2169490 --- /dev/null +++ b/0109-enable-CC-measurement-for-PE-COFF-image.patch @@ -0,0 +1,530 @@ +From 632572a123cd6189a170d46cf3b9ceeabe7a5c37 Mon Sep 17 00:00:00 2001 +From: gongchangsui +Date: Fri, 28 Mar 2025 04:41:15 -0400 +Subject: [PATCH 22/22] enable CC measurement for PE/COFF image + +Signed-off-by: gongchangsui +--- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c | 64 ++++- + ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf | 1 + + ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c | 407 +++++++++++++++++++++++++++ + 3 files changed, 464 insertions(+), 8 deletions(-) + create mode 100644 ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c + +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +index 3ee04e3..ed552c0 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.c +@@ -178,6 +178,33 @@ CopyDigestListToBuffer ( + + EFI_HANDLE mImageHandle; + ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RemIndex REM index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RemIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ); ++ + #define COLUME_SIZE (16 * 2) + + /** +@@ -1117,6 +1144,7 @@ CcaHashLogExtendEvent ( + { + EFI_STATUS Status; + CC_EVENT_HDR NewEventHdr; ++ TPML_DIGEST_VALUES DigestList; + + DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent ...\n")); + +@@ -1148,14 +1176,34 @@ CcaHashLogExtendEvent ( + NewEventHdr.MrIndex = CcEvent->Header.MrIndex; + NewEventHdr.EventType = CcEvent->Header.EventType; + NewEventHdr.EventSize = CcEvent->Size - sizeof (UINT32) - CcEvent->Header.HeaderSize; +- +- Status = CcaDxeHashLogExtendEvent ( +- Flags, +- (UINT8 *)(UINTN)DataToHash, +- DataToHashLen, +- &NewEventHdr, +- CcEvent->Event +- ); ++ if ((Flags & EFI_CC_FLAG_PE_COFF_IMAGE) != 0) { ++ // ++ // According to UEFI Spec 2.10 Section 38.4.x the mapping between MrIndex and ARM ++ // CCA Measurement Register is: ++ // MrIndex 0 <--> RIM ++ // MrIndex 1-3 <--> REM[0-2] ++ // Only the REM registers can be extended in EDK2 by HashAndExtend. ++ // ++ Status = MeasurePeImageAndExtend ( ++ NewEventHdr.MrIndex, ++ DataToHash, ++ (UINTN)DataToHashLen, ++ &DigestList ++ ); ++ if (!EFI_ERROR (Status)) { ++ if ((Flags & EFI_CC_FLAG_EXTEND_ONLY) == 0) { ++ Status = CcaDxeLogHashEvent (&DigestList, &NewEventHdr, CcEvent->Event); ++ } ++ } ++ } else { ++ Status = CcaDxeHashLogExtendEvent ( ++ Flags, ++ (UINT8 *)(UINTN)DataToHash, ++ DataToHashLen, ++ &NewEventHdr, ++ CcEvent->Event ++ ); ++ } + + DEBUG ((DEBUG_VERBOSE, "CcaHashLogExtendEvent - %r\n", Status)); + return Status; +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +index 5575d3c..728ca95 100644 +--- a/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/CcaTcg2Dxe.inf +@@ -14,6 +14,7 @@ + + [Sources] + CcaTcg2Dxe.c ++ MeasureBootPeCoff.c + + [Packages] + MdePkg/MdePkg.dec +diff --git a/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c b/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c +new file mode 100644 +index 0000000..af2d6f9 +--- /dev/null ++++ b/ArmVirtPkg/ArmCcaTcg2Dxe/MeasureBootPeCoff.c +@@ -0,0 +1,407 @@ ++/** @file ++ This module implements measuring PeCoff image for Tcg2 Protocol. ++ ++ Caution: This file requires additional review when modified. ++ This driver will have external input - PE/COFF image. ++ This external input must be validated carefully to avoid security issue like ++ buffer overflow, integer overflow. ++ ++Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
++SPDX-License-Identifier: BSD-2-Clause-Patent ++ ++**/ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++UINTN mTcg2DxeImageSize = 0; ++ ++/** ++ Reads contents of a PE/COFF image in memory buffer. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will make sure the PE/COFF image content ++ read is within the image buffer. ++ ++ @param FileHandle Pointer to the file handle to read the PE/COFF image. ++ @param FileOffset Offset into the PE/COFF image to begin the read operation. ++ @param ReadSize On input, the size in bytes of the requested read operation. ++ On output, the number of bytes actually read. ++ @param Buffer Output buffer that contains the data read from the PE/COFF image. ++ ++ @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size ++**/ ++EFI_STATUS ++EFIAPI ++Tcg2DxeImageRead ( ++ IN VOID *FileHandle, ++ IN UINTN FileOffset, ++ IN OUT UINTN *ReadSize, ++ OUT VOID *Buffer ++ ) ++{ ++ UINTN EndPosition; ++ ++ if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ if (MAX_ADDRESS - FileOffset < *ReadSize) { ++ return EFI_INVALID_PARAMETER; ++ } ++ ++ EndPosition = FileOffset + *ReadSize; ++ if (EndPosition > mTcg2DxeImageSize) { ++ *ReadSize = (UINT32)(mTcg2DxeImageSize - FileOffset); ++ } ++ ++ if (FileOffset >= mTcg2DxeImageSize) { ++ *ReadSize = 0; ++ } ++ ++ CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize); ++ ++ return EFI_SUCCESS; ++} ++ ++/** ++ Measure PE image into TPM log based on the authenticode image hashing in ++ PE/COFF Specification 8.0 Appendix A. ++ ++ Caution: This function may receive untrusted input. ++ PE/COFF image is external input, so this function will validate its data structure ++ within this image buffer before use. ++ ++ Notes: PE/COFF image is checked by BasePeCoffLib PeCoffLoaderGetImageInfo(). ++ ++ @param[in] RemIndex Rem index ++ @param[in] ImageAddress Start address of image buffer. ++ @param[in] ImageSize Image size ++ @param[out] DigestList Digest list of this image. ++ ++ @retval EFI_SUCCESS Successfully measure image. ++ @retval EFI_OUT_OF_RESOURCES No enough resource to measure image. ++ @retval other error value ++**/ ++EFI_STATUS ++MeasurePeImageAndExtend ( ++ IN UINT32 RemIndex, ++ IN EFI_PHYSICAL_ADDRESS ImageAddress, ++ IN UINTN ImageSize, ++ OUT TPML_DIGEST_VALUES *DigestList ++ ) ++{ ++ EFI_STATUS Status; ++ EFI_IMAGE_DOS_HEADER *DosHdr; ++ UINT32 PeCoffHeaderOffset; ++ EFI_IMAGE_SECTION_HEADER *Section; ++ UINT8 *HashBase; ++ UINTN HashSize; ++ UINTN SumOfBytesHashed; ++ EFI_IMAGE_SECTION_HEADER *SectionHeader; ++ UINTN Index; ++ UINTN Pos; ++ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; ++ UINT32 NumberOfRvaAndSizes; ++ UINT32 CertSize; ++ HASH_HANDLE HashHandle; ++ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; ++ ++ HashHandle = 0xFFFFFFFF; // Know bad value ++ ++ Status = EFI_UNSUPPORTED; ++ SectionHeader = NULL; ++ ++ // ++ // Check PE/COFF image ++ // ++ ZeroMem (&ImageContext, sizeof (ImageContext)); ++ ImageContext.Handle = (VOID *)(UINTN)ImageAddress; ++ mTcg2DxeImageSize = ImageSize; ++ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)Tcg2DxeImageRead; ++ ++ // ++ // Get information about the image being loaded ++ // ++ Status = PeCoffLoaderGetImageInfo (&ImageContext); ++ if (EFI_ERROR (Status)) { ++ // ++ // The information can't be got from the invalid PeImage ++ // ++ DEBUG ((DEBUG_INFO, "Tcg2Dxe: PeImage invalid. Cannot retrieve image information.\n")); ++ goto Finish; ++ } ++ ++ DosHdr = (EFI_IMAGE_DOS_HEADER *)(UINTN)ImageAddress; ++ PeCoffHeaderOffset = 0; ++ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { ++ PeCoffHeaderOffset = DosHdr->e_lfanew; ++ } ++ ++ Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINT8 *)(UINTN)ImageAddress + PeCoffHeaderOffset); ++ if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ ++ // ++ // PE/COFF Image Measurement ++ // ++ // NOTE: The following codes/steps are based upon the authenticode image hashing in ++ // PE/COFF Specification 8.0 Appendix A. ++ // ++ // ++ ++ // 1. Load the image header into memory. ++ ++ // 2. Initialize a SHA hash context. ++ ++ Status = HashStart (&HashHandle); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // Measuring PE/COFF Image Header; ++ // But CheckSum field and SECURITY data directory (certificate) are excluded ++ // ++ ++ // ++ // 3. Calculate the distance from the base of the image header to the image checksum address. ++ // 4. Hash the image header from its base to beginning of the image checksum. ++ // ++ HashBase = (UINT8 *)(UINTN)ImageAddress; ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase; ++ } ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ // ++ // 5. Skip over the image checksum (it occupies a single ULONG). ++ // ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ // ++ // 6. Since there is no Cert Directory in optional header, hash everything ++ // from the end of the checksum to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } else { ++ // ++ // 7. Hash everything from the end of the checksum to the start of the Cert Directory. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32); ++ HashSize = (UINTN)(&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase; ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ ++ // ++ // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.) ++ // 9. Hash everything from the end of the Cert Directory to the end of image header. ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ HashBase = (UINT8 *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1]; ++ HashSize = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders - (UINTN)(HashBase - ImageAddress); ++ } ++ ++ if (HashSize != 0) { ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } ++ } ++ ++ // ++ // 10. Set the SUM_OF_BYTES_HASHED to the size of the header ++ // ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset ++ // ++ SumOfBytesHashed = Hdr.Pe32->OptionalHeader.SizeOfHeaders; ++ } else { ++ // ++ // Use PE32+ offset ++ // ++ SumOfBytesHashed = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders; ++ } ++ ++ // ++ // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER ++ // structures in the image. The 'NumberOfSections' field of the image ++ // header indicates how big the table should be. Do not include any ++ // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero. ++ // ++ SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * Hdr.Pe32->FileHeader.NumberOfSections); ++ if (SectionHeader == NULL) { ++ Status = EFI_OUT_OF_RESOURCES; ++ goto Finish; ++ } ++ ++ // ++ // 12. Using the 'PointerToRawData' in the referenced section headers as ++ // a key, arrange the elements in the table in ascending order. In other ++ // words, sort the section headers according to the disk-file offset of ++ // the section. ++ // ++ Section = (EFI_IMAGE_SECTION_HEADER *)( ++ (UINT8 *)(UINTN)ImageAddress + ++ PeCoffHeaderOffset + ++ sizeof (UINT32) + ++ sizeof (EFI_IMAGE_FILE_HEADER) + ++ Hdr.Pe32->FileHeader.SizeOfOptionalHeader ++ ); ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Pos = Index; ++ while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) { ++ CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Pos--; ++ } ++ ++ CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER)); ++ Section += 1; ++ } ++ ++ // ++ // 13. Walk through the sorted table, bring the corresponding section ++ // into memory, and hash the entire section (using the 'SizeOfRawData' ++ // field in the section header to determine the amount of data to hash). ++ // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED . ++ // 15. Repeat steps 13 and 14 for all the sections in the sorted table. ++ // ++ for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) { ++ Section = (EFI_IMAGE_SECTION_HEADER *)&SectionHeader[Index]; ++ if (Section->SizeOfRawData == 0) { ++ continue; ++ } ++ ++ HashBase = (UINT8 *)(UINTN)ImageAddress + Section->PointerToRawData; ++ HashSize = (UINTN)Section->SizeOfRawData; ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++ SumOfBytesHashed += HashSize; ++ } ++ ++ // ++ // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra ++ // data in the file that needs to be added to the hash. This data begins ++ // at file offset SUM_OF_BYTES_HASHED and its length is: ++ // FileSize - (CertDirectory->Size) ++ // ++ if (ImageSize > SumOfBytesHashed) { ++ HashBase = (UINT8 *)(UINTN)ImageAddress + SumOfBytesHashed; ++ ++ if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) { ++ CertSize = 0; ++ } else { ++ if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ++ // ++ // Use PE32 offset. ++ // ++ CertSize = Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } else { ++ // ++ // Use PE32+ offset. ++ // ++ CertSize = Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size; ++ } ++ } ++ ++ if (ImageSize > CertSize + SumOfBytesHashed) { ++ HashSize = (UINTN)(ImageSize - CertSize - SumOfBytesHashed); ++ ++ Status = HashUpdate (HashHandle, HashBase, HashSize); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ } else if (ImageSize < CertSize + SumOfBytesHashed) { ++ Status = EFI_UNSUPPORTED; ++ goto Finish; ++ } ++ } ++ ++ // ++ // 17. Finalize the SHA hash. ++ // ++ Status = HashCompleteAndExtend (HashHandle, RemIndex, NULL, 0, DigestList); ++ if (EFI_ERROR (Status)) { ++ goto Finish; ++ } ++ ++Finish: ++ if (SectionHeader != NULL) { ++ FreePool (SectionHeader); ++ } ++ ++ return Status; ++} +-- +1.8.3.1 + diff --git a/edk2.spec b/edk2.spec index a5eb491..f52e098 100644 --- a/edk2.spec +++ b/edk2.spec @@ -7,7 +7,7 @@ Name: edk2 Version: %{stable_date} -Release: 21 +Release: 22 Summary: EFI Development Kit II License: BSD-2-Clause-Patent and OpenSSL and MIT URL: https://github.com/tianocore/edk2 @@ -143,6 +143,32 @@ patch86: 0086-Check-DSA-parameters.patch # Fix CVE-2024-9143 patch87: 0087-Harden-BN_GF2m_poly2arr-against-misuse.patch +# Support UEFI boot CVM +patch88: 0088-ArmVirtPkg-IoMMU-driver-to-DMA-from-Realms.patch +patch89: 0089-ArmVirtPkg-Add-library-for-Arm-CCA-initialisation-in.patch +patch90: 0090-ArmVirtPkg-Add-library-for-Arm-CCA-helper-functions.patch +patch91: 0091-ArmVirtPkg-Define-an-interface-to-configure-MMIO-reg.patch +patch92: 0092-ArmVirtPkg-Introduce-Realm-Aperture-Management-Proto.patch +patch93: 0093-ArmVirtPkg-ArmVirtQemu-Implement-ArmMonitorLib-for-Q.patch +patch94: 0094-ArmVirtPkg-Qemu-Add-a-NULL-implementation-of-ArmCcaC.patch +patch95: 0095-ArmVirtPkg-Perform-Arm-CCA-initialisation-in-the-Pei.patch +patch96: 0096-ArmVirtPkg-ArmVirtQemu-Dispatch-variable-store-emula.patch +patch97: 0097-ArmPkg-Introduce-SetMemoryProtectionAttribute-for-Re.patch +patch98: 0098-OvmfPkg-FdtNorFlashQemuLib-Parse-device-tree-earlier.patch +patch99: 0099-OvmfPkg-Enforce-to-use-MMIO.patch + +# Support measurement when UEFI Boot CVM +patch100: 0100-clean-code-for-virtCCA-support.patch +patch101: 0101-update-ArmCcaLib-to-support-RSI-calls.patch +patch102: 0102-add-HashLib-for-Arm-CCA-and-SHA256-is-supported.patch +patch103: 0103-add-CcaTcg2Dxe-to-produce-EFI_CC_MEASUREMENT_PROTOCO.patch +patch104: 0104-implement-CcaHashLogExtendEvent-and-CcaMapPcrToMrInd.patch +patch105: 0105-implement-CcaGetEventLog-of-EFI_CC_MEASUREMENT_PROTO.patch +patch106: 0106-setup-CC-eventlog-and-install-its-ACPI-table.patch +patch107: 0107-enable-CC-measurement-for-EFI-boot-variables.patch +patch108: 0108-enable-CC-measurement-for-EFI-secure-variables.patch +patch109: 0109-enable-CC-measurement-for-PE-COFF-image.patch + BuildRequires: acpica-tools gcc gcc-c++ libuuid-devel python3 bc nasm python3-unversioned-command isl %description @@ -230,6 +256,8 @@ COMMON_FLAGS="-D NETWORK_IP6_ENABLE" BUILD_OPTION="$BUILD_OPTION -a AARCH64 -p ArmVirtPkg/ArmVirtQemu.dsc --cmd-len=65536 $COMMON_FLAGS" # In order to be compatible with old os, make EFI_LOADER_DATA executable again. BUILD_OPTION="$BUILD_OPTION --pcd PcdDxeNxMemoryProtectionPolicy=0xC000000000007FD1" + BUILD_OPTION="$BUILD_OPTION -D CC_MEASUREMENT_ENABLE=TRUE" + %endif %ifarch x86_64 @@ -412,6 +440,10 @@ chmod +x %{buildroot}%{_bindir}/Rsa2048Sha256GenerateKeys %endif %changelog +* Sat Mar 29 2025 gongchangsui - 202308-22 +- Support UEFI boot CVM +- Support measurement when UEFI boot CVM + * Fri Mar 28 2025 huyu - 202308-21 - fix CVE-2024-9143 -- Gitee