* [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 18:18 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 02/19] Documentation/x86: Secure Launch kernel documentation Ross Philipson
` (17 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: Arvind Sankar <nivedita@alum.mit.edu>
There are use cases for storing the offset of a symbol in kernel_info.
For example, the trenchboot series [0] needs to store the offset of the
Measured Launch Environment header in kernel_info.
Since commit (note: commit ID from tip/master)
commit 527afc212231 ("x86/boot: Check that there are no run-time relocations")
run-time relocations are not allowed in the compressed kernel, so simply
using the symbol in kernel_info, as
.long symbol
will cause a linker error because this is not position-independent.
With kernel_info being a separate object file and in a different section
from startup_32, there is no way to calculate the offset of a symbol
from the start of the image in a position-independent way.
To enable such use cases, put kernel_info into its own section which is
placed at a predetermined offset (KERNEL_INFO_OFFSET) via the linker
script. This will allow calculating the symbol offset in a
position-independent way, by adding the offset from the start of
kernel_info to KERNEL_INFO_OFFSET.
Ensure that kernel_info is aligned, and use the SYM_DATA.* macros
instead of bare labels. This stores the size of the kernel_info
structure in the ELF symbol table.
Signed-off-by: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Ross Philipson <ross.philipson@oracle.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/boot/compressed/kernel_info.S | 19 +++++++++++++++----
arch/x86/boot/compressed/kernel_info.h | 12 ++++++++++++
arch/x86/boot/compressed/vmlinux.lds.S | 6 ++++++
3 files changed, 33 insertions(+), 4 deletions(-)
create mode 100644 arch/x86/boot/compressed/kernel_info.h
diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
index f818ee8fba38..c18f07181dd5 100644
--- a/arch/x86/boot/compressed/kernel_info.S
+++ b/arch/x86/boot/compressed/kernel_info.S
@@ -1,12 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
#include <asm/bootparam.h>
+#include "kernel_info.h"
- .section ".rodata.kernel_info", "a"
+/*
+ * If a field needs to hold the offset of a symbol from the start
+ * of the image, use the macro below, eg
+ * .long rva(symbol)
+ * This will avoid creating run-time relocations, which are not
+ * allowed in the compressed kernel.
+ */
+
+#define rva(X) (((X) - kernel_info) + KERNEL_INFO_OFFSET)
- .global kernel_info
+ .section ".rodata.kernel_info", "a"
-kernel_info:
+ .balign 16
+SYM_DATA_START(kernel_info)
/* Header, Linux top (structure). */
.ascii "LToP"
/* Size. */
@@ -19,4 +30,4 @@ kernel_info:
kernel_info_var_len_data:
/* Empty for time being... */
-kernel_info_end:
+SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
diff --git a/arch/x86/boot/compressed/kernel_info.h b/arch/x86/boot/compressed/kernel_info.h
new file mode 100644
index 000000000000..c127f84aec63
--- /dev/null
+++ b/arch/x86/boot/compressed/kernel_info.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef BOOT_COMPRESSED_KERNEL_INFO_H
+#define BOOT_COMPRESSED_KERNEL_INFO_H
+
+#ifdef CONFIG_X86_64
+#define KERNEL_INFO_OFFSET 0x500
+#else /* 32-bit */
+#define KERNEL_INFO_OFFSET 0x100
+#endif
+
+#endif /* BOOT_COMPRESSED_KERNEL_INFO_H */
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 083ec6d7722a..718c52f3f1e6 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -7,6 +7,7 @@ OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT)
#include <asm/cache.h>
#include <asm/page_types.h>
+#include "kernel_info.h"
#ifdef CONFIG_X86_64
OUTPUT_ARCH(i386:x86-64)
@@ -27,6 +28,11 @@ SECTIONS
HEAD_TEXT
_ehead = . ;
}
+ .rodata.kernel_info KERNEL_INFO_OFFSET : {
+ *(.rodata.kernel_info)
+ }
+ ASSERT(ABSOLUTE(kernel_info) == KERNEL_INFO_OFFSET, "kernel_info at bad address!")
+
.rodata..compressed : {
*(.rodata..compressed)
}
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset
2024-05-31 1:03 ` [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset Ross Philipson
@ 2024-06-04 18:18 ` Jarkko Sakkinen
2024-06-04 20:28 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 18:18 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> From: Arvind Sankar <nivedita@alum.mit.edu>
>
> There are use cases for storing the offset of a symbol in kernel_info.
> For example, the trenchboot series [0] needs to store the offset of the
> Measured Launch Environment header in kernel_info.
So either there are other use cases that you should enumerate, or just
be straight and state that this is done for Trenchboot.
I believe latter is the case, and there is no reason to project further.
If it does not interfere kernel otherwise, it should be fine just by
that.
Also I believe that it is written as Trenchboot, without "series" ;-)
Think when writing commit message that it will some day be part of the
commit log, not a series flying in the air.
Sorry for the nitpicks but better to be punctual and that way also
transparent as possible, right?
>
> Since commit (note: commit ID from tip/master)
>
> commit 527afc212231 ("x86/boot: Check that there are no run-time relocations")
>
> run-time relocations are not allowed in the compressed kernel, so simply
> using the symbol in kernel_info, as
>
> .long symbol
>
> will cause a linker error because this is not position-independent.
>
> With kernel_info being a separate object file and in a different section
> from startup_32, there is no way to calculate the offset of a symbol
> from the start of the image in a position-independent way.
>
> To enable such use cases, put kernel_info into its own section which is
"To allow Trenchboot to access the fields of kernel_info..."
Much more understandable.
> placed at a predetermined offset (KERNEL_INFO_OFFSET) via the linker
> script. This will allow calculating the symbol offset in a
> position-independent way, by adding the offset from the start of
> kernel_info to KERNEL_INFO_OFFSET.
>
> Ensure that kernel_info is aligned, and use the SYM_DATA.* macros
> instead of bare labels. This stores the size of the kernel_info
> structure in the ELF symbol table.
Aligned to which boundary and short explanation why to that boundary,
i.e. state the obvious if you bring it up anyway here.
Just seems to be progressing pretty well so taking my eye glass and
looking into nitty gritty details...
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset
2024-06-04 18:18 ` Jarkko Sakkinen
@ 2024-06-04 20:28 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 20:28 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 11:18 AM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> From: Arvind Sankar <nivedita@alum.mit.edu>
>>
>> There are use cases for storing the offset of a symbol in kernel_info.
>> For example, the trenchboot series [0] needs to store the offset of the
>> Measured Launch Environment header in kernel_info.
>
> So either there are other use cases that you should enumerate, or just
> be straight and state that this is done for Trenchboot.
The kernel_info concept came about because of the work we were doing on
TrenchBoot but it was not done for TrenchBoot. It was a collaborative
effort between the TrenchBoot team and H. Peter Anvin at Intel. He
actually envisioned it being useful elsewhere. If you find the original
commits for it (that went in stand-alone) from Daniel Kiper, there is a
fair amount of detail what kernel_info is supposed to be and should be
used for.
>
> I believe latter is the case, and there is no reason to project further.
> If it does not interfere kernel otherwise, it should be fine just by
> that.
>
> Also I believe that it is written as Trenchboot, without "series" ;-)
> Think when writing commit message that it will some day be part of the
> commit log, not a series flying in the air.
>
> Sorry for the nitpicks but better to be punctual and that way also
> transparent as possible, right?
No problem. We submit the patch sets to get feedback :)
Thanks for the feedback.
>
>>
>> Since commit (note: commit ID from tip/master)
>>
>> commit 527afc212231 ("x86/boot: Check that there are no run-time relocations")
>>
>> run-time relocations are not allowed in the compressed kernel, so simply
>> using the symbol in kernel_info, as
>>
>> .long symbol
>>
>> will cause a linker error because this is not position-independent.
>>
>> With kernel_info being a separate object file and in a different section
>> from startup_32, there is no way to calculate the offset of a symbol
>> from the start of the image in a position-independent way.
>>
>> To enable such use cases, put kernel_info into its own section which is
>
> "To allow Trenchboot to access the fields of kernel_info..."
>
> Much more understandable.
>
>> placed at a predetermined offset (KERNEL_INFO_OFFSET) via the linker
>> script. This will allow calculating the symbol offset in a
>> position-independent way, by adding the offset from the start of
>> kernel_info to KERNEL_INFO_OFFSET.
>>
>> Ensure that kernel_info is aligned, and use the SYM_DATA.* macros
>> instead of bare labels. This stores the size of the kernel_info
>> structure in the ELF symbol table.
>
> Aligned to which boundary and short explanation why to that boundary,
> i.e. state the obvious if you bring it up anyway here.
>
> Just seems to be progressing pretty well so taking my eye glass and
> looking into nitty gritty details...
So a lot of this is up in the air if you read the responses between us
and Ard Biesheuvel. It would be nice to get rid of the part where
kernel_info is forced to a fixed offset in the setup kernel.
Thanks
Ross
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 02/19] Documentation/x86: Secure Launch kernel documentation
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
2024-05-31 1:03 ` [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 03/19] x86: Secure Launch Kconfig Ross Philipson
` (16 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Introduce background, overview and configuration/ABI information
for the Secure Launch kernel feature.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Reviewed-by: Bagas Sanjaya <bagasdotme@gmail.com>
---
Documentation/security/index.rst | 1 +
.../security/launch-integrity/index.rst | 11 +
.../security/launch-integrity/principles.rst | 320 ++++++++++
.../secure_launch_details.rst | 587 ++++++++++++++++++
.../secure_launch_overview.rst | 227 +++++++
5 files changed, 1146 insertions(+)
create mode 100644 Documentation/security/launch-integrity/index.rst
create mode 100644 Documentation/security/launch-integrity/principles.rst
create mode 100644 Documentation/security/launch-integrity/secure_launch_details.rst
create mode 100644 Documentation/security/launch-integrity/secure_launch_overview.rst
diff --git a/Documentation/security/index.rst b/Documentation/security/index.rst
index 59f8fc106cb0..56e31fb3d91f 100644
--- a/Documentation/security/index.rst
+++ b/Documentation/security/index.rst
@@ -19,3 +19,4 @@ Security Documentation
digsig
landlock
secrets/index
+ launch-integrity/index
diff --git a/Documentation/security/launch-integrity/index.rst b/Documentation/security/launch-integrity/index.rst
new file mode 100644
index 000000000000..838328186dd2
--- /dev/null
+++ b/Documentation/security/launch-integrity/index.rst
@@ -0,0 +1,11 @@
+=====================================
+System Launch Integrity documentation
+=====================================
+
+.. toctree::
+ :maxdepth: 1
+
+ principles
+ secure_launch_overview
+ secure_launch_details
+
diff --git a/Documentation/security/launch-integrity/principles.rst b/Documentation/security/launch-integrity/principles.rst
new file mode 100644
index 000000000000..68a415aec545
--- /dev/null
+++ b/Documentation/security/launch-integrity/principles.rst
@@ -0,0 +1,320 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright © 2019-2023 Daniel P. Smith <dpsmith@apertussolutions.com>
+
+=======================
+System Launch Integrity
+=======================
+
+:Author: Daniel P. Smith
+:Date: October 2023
+
+This document serves to establish a common understanding of what is system
+launch, the integrity concern for system launch, and why using a Root of Trust
+(RoT) from a Dynamic Launch may be desired. Throughout this document
+terminology from the Trusted Computing Group (TCG) and National Institute for
+Science and Technology (NIST) is used to ensure a vendor natural language is
+used to describe and reference security-related concepts.
+
+System Launch
+=============
+
+There is a tendency to only consider the classical power-on boot as the only
+means to launch an Operating System (OS) on a computer system, but in fact most
+modern processors support two methods to launch the system. To provide clarity
+a common definition of a system launch should be established. This definition
+is that a during a single power life cycle of a system, a System Launch
+consists of an initialization event, typically in hardware, that is followed by
+an executing software payload that takes the system from the initialized state
+to a running state. Driven by the Trusted Computing Group (TCG) architecture,
+modern processors are able to support two methods to launch a system, these two
+types of system launch are known as Static Launch and Dynamic Launch.
+
+Static Launch
+-------------
+
+Static launch is the system launch associated with the power cycle of the CPU.
+Thus, static launch refers to the classical power-on boot where the
+initialization event is the release of the CPU from reset and the system
+firmware is the software payload that brings the system up to a running state.
+Since static launch is the system launch associated with the beginning of the
+power lifecycle of a system, it is therefore a fixed, one-time system launch.
+It is because of this that static launch is referred to and thought of as being
+"static".
+
+Dynamic Launch
+--------------
+
+Modern CPUs architectures provides a mechanism to re-initialize the system to a
+"known good" state without requiring a power event. This re-initialization
+event is the event for a dynamic launch and is referred to as the Dynamic
+Launch Event (DLE). The DLE functions by accepting a software payload, referred
+to as the Dynamic Configuration Environment (DCE), that execution is handed to
+after the DLE is invoked. The DCE is responsible for bringing the system back
+to a running state. Since the dynamic launch is not tied to a power event like
+the static launch, this enables a dynamic launch to be initiated at any time
+and multiple times during a single power life cycle. This dynamism is the
+reasoning behind referring to this system launch as being dynamic.
+
+Because a dynamic launch can be conducted at any time during a single power
+life cycle, they are classified into one of two types, an early launch or a
+late launch.
+
+:Early Launch: When a dynamic launch is used as a transition from a static
+ launch chain to the final Operating System.
+
+:Late Launch: The usage of a dynamic launch by an executing Operating System to
+ transition to a “known good” state to perform one or more operations, e.g. to
+ launch into a new Operating System.
+
+System Integrity
+================
+
+A computer system can be considered a collection of mechanisms that work
+together to produce a result. The assurance that the mechanisms are functioning
+correctly and producing the expected result is the integrity of the system. To
+ensure a system's integrity there are a subset of these mechanisms, commonly
+referred to as security mechanisms, that are present to help ensure the system
+produces the expected result or at least detect the potential of an unexpected
+result may have happened. Since the security mechanisms are relied upon to
+ensue the integrity of the system, these mechanisms are trusted. Upon
+inspection these security mechanisms each have a set of properties and these
+properties can be evaluated to determine how susceptible a mechanism might be
+to failure. This assessment is referred to as the Strength of Mechanism and for
+trusted mechanism enables for the trustworthiness of that mechanism to be
+quantified.
+
+For software systems, there are two system states for which the integrity is
+critical, when the software is loaded into memory and when the software is
+executing on the hardware. Ensuring that the expected software is load into
+memory is referred to as load-time integrity while ensuring that the software
+executing is the expected software is the runtime integrity of that software.
+
+Load-time Integrity
+-------------------
+
+It is critical to understand what load-time integrity establishes about a
+system and what is assumed, i.e. what is being trusted. Load-time integrity is
+when a trusted entity, i.e. an entity with an assumed integrity, takes an
+action to assess an entity being loaded into memory before it is used. A
+variety of mechanisms may be used to conduct the assessment, each with
+different properties. A particular property is whether the mechanism creates an
+evidence of the assessment. Often either cryptographic signature checking or
+hashing are the common assessment operations used.
+
+A signature checking assessment functions by requiring a representation of the
+accepted authorities and uses those representations to assess if the entity has
+been signed by an accepted authority. The benefit to this process is that
+assessment process includes an adjudication of the assessment. The drawbacks
+are that 1) the adjudication is susceptible to tampering by the Trusted
+Computing Base (TCB), 2) there is no evidence to assert that an untampered
+adjudication was completed, and 3) the system must be an active participant in
+the key management infrastructure.
+
+A cryptographic hashing assessment does not adjudicate the assessment but
+instead, generates evidence of the assessment to be adjudicated independently.
+The benefits to this approach is that the assessment may be simple such that it
+may be implemented in an immutable mechanism, e.g. in hardware. Additionally,
+it is possible for the adjudication to be conducted where it cannot be tampered
+with by the TCB. The drawback is that a compromised environment will be allowed
+to execute until an adjudication can be completed.
+
+Ultimately, load-time integrity provides confidence that the correct entity was
+loaded and in the absence of a run-time integrity mechanism assumes, i.e.
+trusts, that the entity will never become corrupted.
+
+Runtime Integrity
+-----------------
+
+Runtime integrity in the general sense is when a trusted entity makes an
+assessment of an entity at any point in time during the assessed entity's
+execution. A more concrete explanation is the taking of an integrity assessment
+of an active process executing on the system at any point during the process'
+execution. Often the load-time integrity of an operating system's user-space,
+i.e. the operating environment, is confused to be the runtime integrity of the
+system, since it is an integrity assessment of the "runtime" software. The
+reality is that actual runtime integrity is a very difficult problem and thus
+not very many solutions are public and/or available. One example of a runtime
+integrity solution would be Johns Hopkins Advanced Physics Laboratory's (APL)
+Linux Kernel Integrity Module (LKIM).
+
+Trust Chains
+============
+
+Building upon the understanding of security mechanisms to establish load-time
+integrity of an entity, it is possible to chain together load-time integrity
+assessments to establish the integrity of the whole system. This process is
+known as transitive trust and provides the concept of building a chain of
+load-time integrity assessments, commonly referred to as a trust chain. These
+assessments may be used to adjudicate the load-time integrity of the whole
+system. This trust chain is started by a trusted entity that does the first
+assessment. This first entity is referred to as the Root of Trust(RoT) with the
+entities name being derived from the mechanism used for the assessment, i.e.
+RoT for Verification (RTV) and RoT for Measurement (RTM).
+
+A trust chain is itself a mechanism, specifically a mechanism of mechanisms,
+and therefore it too has a Strength of Mechanism. The factors that contribute
+to the strength of a trust chain are,
+
+ - The strength of the chain's RoT
+ - The strength of each member of the trust chain
+ - The length, i.e. the number of members, of the chain
+
+Therefore, to provide the strongest trust chains, they should start with a
+strong RoT and should consist of members being of low complexity and minimizing
+the number of members participating as possible. In a more colloquial sense, a
+trust chain is only as strong as its weakest link, thus more links increase the
+probability of a weak link.
+
+Dynamic Launch Components
+=========================
+
+The TCG architecture for dynamic launch is composed of a component series that
+are used to set up and then carry out the launch. These components work
+together to construct an RTM trust chain that is rooted in the dynamic launch
+and thus commonly referred to as the Dynamic Root of Trust for Measurement
+(DRTM) chain.
+
+What follows is a brief explanation of each component in execution order. A
+subset of these components are what establishes the dynamic launch's trust
+chain.
+
+Dynamic Configuration Environment Preamble
+------------------------------------------
+
+The Dynamic Configuration Environment (DCE) Preamble is responsible for setting
+up the system environment in preparation for a dynamic launch. The DCE Preamble
+is not a part of the DRTM trust chain.
+
+Dynamic Launch Event
+--------------------
+
+The dynamic launch event is the event, typically a CPU instruction, that
+triggers the system's dynamic launch mechanism to begin the launch. The dynamic
+launch mechanism is also the RoT for the DRTM trust chain.
+
+Dynamic Configuration Environment
+---------------------------------
+
+The dynamic launch mechanism may have resulted in a reset of a portion of the
+system. To bring the system back to an adequate state for system software, the
+dynamic launch will hand over control to the DCE. Prior to handing over this
+control, the dynamic launch, will measure the DCE. Once the DCE is complete it
+will proceed to measure and then execute the Dynamic Launch Measured
+Environment (DLME).
+
+Dynamic Launch Measured Environment
+-----------------------------------
+
+The DLME is the first system kernel to have control of the system, but may not
+be the last. Depending on the usage and configuration, the DLME may be the
+final/target operating system, or it may be a bootloader that will load the
+final/target operating system.
+
+Why DRTM
+========
+
+It is a fact that DRTM increases the load-time integrity of the system by
+providing a trust chain that has an immutable hardware RoT, uses a limited
+number of small, special purpose code to establish the trust chain that starts
+the target operating system. As mentioned in the Trust Chain section, these are
+the main three factors in driving up the strength of a trust chain. As has been
+seen with the BootHole exploit, which in fact did not affect the integrity of
+DRTM solutions, the sophistication of attacks targeting system launch is at an
+all-time high. There is no reason a system should not employ every integrity
+measure hardware makes available. This is the crux of a defense-in-depth
+approach to system security. In the past, the now closed SMI gap was often
+pointed to as invalidating DRTM, which in fact was nothing but a straw man
+argument. As has continued to be demonstrated, if/when SMM is corrupted it can
+always circumvent all load-time integrity, SRTM and DRTM, because it is a
+run-time integrity problem. Regardless, Intel and AMD have both deployed
+runtime integrity for SMI and SMM which is tied directly to DRTM such that this
+perceived deficiency is now non-existent, and the world is moving forward with
+an expectation that DRTM must be present.
+
+Glossary
+========
+
+.. glossary::
+ integrity
+ Guarding against improper information modification or destruction, and
+ includes ensuring information non-repudiation and authenticity.
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
+
+ mechanism
+ A process or system that is used to produce a particular result.
+
+ - NIST Special Publication 800-160 (VOLUME 1 ) - https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-160v1.pdf
+
+ risk
+ A measure of the extent to which an entity is threatened by a potential
+ circumstance or event, and typically a function of: (i) the adverse impacts
+ that would arise if the circumstance or event occurs; and (ii) the
+ likelihood of occurrence.
+
+ - NIST SP 800-30 Rev. 1 - https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-30r1.pdf
+
+ security mechanism
+ A device or function designed to provide one or more security services
+ usually rated in terms of strength of service and assurance of the design.
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
+
+ Strength of Mechanism
+ A scale for measuring the relative strength of a security mechanism
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
+
+ transitive trust
+ Also known as "Inductive Trust", in this process a Root of Trust gives a
+ trustworthy description of a second group of functions. Based on this
+ description, an interested entity can determine the trust it is to place in
+ this second group of functions. If the interested entity determines that
+ the trust level of the second group of functions is acceptable, the trust
+ boundary is extended from the Root of Trust to include the second group of
+ functions. In this case, the process can be iterated. The second group of
+ functions can give a trustworthy description of the third group of
+ functions, etc. Transitive trust is used to provide a trustworthy
+ description of platform characteristics, and also to prove that
+ non-migratable keys are in fact non-migratable.
+
+ - TCG Glossary - https://trustedcomputinggroup.org/wp-content/uploads/TCG-Glossary-V1.1-Rev-1.0.pdf
+
+ trust
+ The confidence one element has in another that the second element will
+ behave as expected`
+
+ - NISTIR 8320A - https://nvlpubs.nist.gov/nistpubs/ir/2021/NIST.IR.8320A.pdf
+
+ trust anchor
+ An authoritative entity for which trust is assumed.
+
+ - NIST SP 800-57 Part 1 Rev. 5 - https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf
+
+ trusted
+ An element that another element relies upon to fulfill critical
+ requirements on its behalf.
+
+ - NISTIR 8320A - https://nvlpubs.nist.gov/nistpubs/ir/2021/NIST.IR.8320A.pdf
+
+ trusted computing base (TCB)
+ Totality of protection mechanisms within a computer system, including
+ hardware, firmware, and software, the combination responsible for enforcing
+ a security policy.
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
+
+ trusted computer system
+ A system that has the necessary security functions and assurance that the
+ security policy will be enforced and that can process a range of
+ information sensitivities (i.e. classified, controlled unclassified
+ information (CUI), or unclassified public information) simultaneously.
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
+
+ trustworthiness
+ The attribute of a person or enterprise that provides confidence to others
+ of the qualifications, capabilities, and reliability of that entity to
+ perform specific tasks and fulfill assigned responsibilities.
+
+ - NIST CNSSI No. 4009 - https://www.cnss.gov/CNSS/issuances/Instructions.cfm
diff --git a/Documentation/security/launch-integrity/secure_launch_details.rst b/Documentation/security/launch-integrity/secure_launch_details.rst
new file mode 100644
index 000000000000..0031f556d510
--- /dev/null
+++ b/Documentation/security/launch-integrity/secure_launch_details.rst
@@ -0,0 +1,587 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright © 2019-2023 Daniel P. Smith <dpsmith@apertussolutions.com>
+
+===================================
+Secure Launch Config and Interfaces
+===================================
+
+:Author: Daniel P. Smith
+:Date: October 2023
+
+Configuration
+=============
+
+The settings to enable Secure Launch using Kconfig are under::
+
+ "Processor type and features" --> "Secure Launch support"
+
+A kernel with this option enabled can still be booted using other supported
+methods.
+
+To reduce the Trusted Computing Base (TCB) of the MLE [1]_, the build
+configuration should be pared down as narrowly as one's use case allows. The
+fewer drivers (less active hardware) and features reduces the attack surface.
+As an example in the extreme, the MLE could only have local disk access with no
+other hardware supports, except optional network access for remote attestation.
+
+It is also desirable, if possible, to embed the initrd used with the MLE kernel
+image to reduce complexity.
+
+The following are a few important configuration necessities to always consider:
+
+KASLR Configuration
+-------------------
+
+Due to Secure Launch hardware implementation details and how KASLR functions,
+Secure Launch is not able to interoperate with KASLR at this time. Attempts to
+enable KASLR in a kernel started using Secure Launch may result in crashes and
+other instabilities at boot. Even in cases where Secure Launch and KASLR work
+together, it is still recommended that KASLR be disabled to avoid introducing
+security concerns with unprotected kernel memory.
+
+If possible, a kernel being used as an MLE should be built with KASLR disabled::
+
+ "Processor type and features" -->
+ "Build a relocatable kernel" -->
+ "Randomize the address of the kernel image (KASLR) [ ]"
+
+This action unsets the Kconfig value CONFIG_RANDOMIZE_BASE.
+
+If it is not possible to disable at build time, then it is recommended to force
+KASLR to be disabled using the kernel command line when doing a Secure Launch.
+The kernel parameter is as follows::
+
+ nokaslr
+
+.. note::
+ Should KASLR be made capable of reading/using only the protected page
+ regions set up by the memory protection mechanisms used by the hardware
+ DRTM capability, then it would become possible to use KASLR with Secure
+ Launch.
+
+IOMMU Configuration
+-------------------
+
+When doing a Secure Launch, the IOMMU should always be enabled and the drivers
+loaded. However, IOMMU passthrough mode should never be used. This leaves the
+MLE completely exposed to DMA after the PMR's [2]_ are disabled. The current
+default mode is to use IOMMU in lazy translated mode, but strict translated
+mode is the preferred IOMMU mode and this should be selected in the build
+configuration::
+
+ "Device Drivers" -->
+ "IOMMU Hardware Support" -->
+ "IOMMU default domain type" -->
+ "(X) Translated - Strict"
+
+In addition, the Intel IOMMU should be on by default. The following sets this as the
+default in the build configuration::
+
+ "Device Drivers" -->
+ "IOMMU Hardware Support" -->
+ "Support for Intel IOMMU using DMA Remapping Devices [*]"
+
+and::
+
+ "Device Drivers" -->
+ "IOMMU Hardware Support" -->
+ "Support for Intel IOMMU using DMA Remapping Devices [*]" -->
+ "Enable Intel DMA Remapping Devices by default [*]"
+
+It is recommended that no other command line options should be set to override
+the defaults above. If there is a desire to run an alternate configuration,
+then that configuration should be evaluated for what benefits are attempting to
+be gained against the risks for DMA attacks for which the kernel is likely
+going to be exposed.
+
+Secure Launch Resource Table
+============================
+
+The Secure Launch Resource Table (SLRT) is a platform-agnostic, standard format
+for providing information for the pre-launch environment and to pass
+information to the post-launch environment. The table is populated by one or
+more bootloaders in the boot chain and used by Secure Launch on how to set up
+the environment during post-launch. The details for the SLRT are documented
+in the TrenchBoot Secure Launch Specification [3]_.
+
+Intel TXT Interface
+===================
+
+The primary interfaces between the various components in TXT are the TXT MMIO
+registers and the TXT heap. The MMIO register banks are described in Appendix B
+of the TXT MLE [1]_ Development Guide.
+
+The TXT heap is described in Appendix C of the TXT MLE [1]_ Development
+Guide. Most of the TXT heap is predefined in the specification. The heap is
+initialized by firmware and the pre-launch environment and is subsequently used
+by the SINIT ACM. One section, called the OS to MLE Data Table, is reserved for
+software to define. This table is set up per the recommendation detailed in
+Appendix B of the TrenchBoot Secure Launch Specification::
+
+ /*
+ * Secure Launch defined OS/MLE TXT Heap table
+ */
+ struct txt_os_mle_data {
+ u32 version;
+ u32 boot_params_addr;
+ u64 slrt;
+ u64 txt_info;
+ u32 ap_wake_block;
+ u32 ap_wake_block_size;
+ u8 mle_scratch[64];
+ } __packed;
+
+Description of structure:
+
+===================== ========================================================================
+Field Use
+===================== ========================================================================
+version Structure version, current value 1
+boot_params_addr Physical base address of the Linux boot parameters
+slrt Physical address of the Secure Launch Resource Table
+txt_info Pointer into the SLRT for easily locating TXT specific table
+ap_wake_block Physical address of the block of memory for parking APs after a launch
+ap_wake_block_size Size of the AP wake block
+mle_scratch Scratch area used post-launch by the MLE kernel. Fields:
+
+ - SL_SCRATCH_AP_EBX area to share %ebx base pointer among CPUs
+ - SL_SCRATCH_AP_JMP_OFFSET offset to abs. ljmp fixup location for APs
+===================== ========================================================================
+
+Error Codes
+-----------
+
+The TXT specification defines the layout for TXT 32 bit error code values.
+The bit encodings indicate where the error originated (e.g. with the CPU,
+in the SINIT ACM, in software). The error is written to a sticky TXT
+register that persists across resets called TXT.ERRORCODE (see the TXT
+MLE Development Guide). The errors defined by the Secure Launch feature are
+those generated in the MLE software. They have the format::
+
+ 0xc0008XXX
+
+The low 12 bits are free for defining the following Secure Launch specific
+error codes.
+
+====== ================
+Name: SL_ERROR_GENERIC
+Value: 0xc0008001
+====== ================
+
+Description:
+
+Generic catch all error. Currently unused.
+
+====== =================
+Name: SL_ERROR_TPM_INIT
+Value: 0xc0008002
+====== =================
+
+Description:
+
+The Secure Launch code failed to get access to the TPM hardware interface.
+This is most likely due to misconfigured hardware or kernel. Ensure the TPM
+chip is enabled, and the kernel TPM support is built in (it should not be built
+as a module).
+
+====== ==========================
+Name: SL_ERROR_TPM_INVALID_LOG20
+Value: 0xc0008003
+====== ==========================
+
+Description:
+
+The Secure Launch code failed to find a valid event log descriptor for a
+version 2.0 TPM or the event log descriptor is malformed. Usually this
+indicates there are incompatible versions of the pre-launch environment and the
+MLE kernel. The pre-launch environment and the kernel share a structure in the
+TXT heap and if this structure (the OS-MLE table) is mismatched, this error is
+often seen. This TXT heap area is set up by the pre-launch environment, so the
+issue may originate there. It could also be the sign of an attempted attack.
+
+====== ===========================
+Name: SL_ERROR_TPM_LOGGING_FAILED
+Value: 0xc0008004
+====== ===========================
+
+Description:
+
+There was a failed attempt to write a TPM event to the event log early in the
+Secure Launch process. This is likely the result of a malformed TPM event log
+buffer. Formatting of the event log buffer information is done by the
+pre-launch environment, so the issue most likely originates there.
+
+====== ============================
+Name: SL_ERROR_REGION_STRADDLE_4GB
+Value: 0xc0008005
+====== ============================
+
+Description:
+
+During early validation, a buffer or region was found to straddle the 4GB
+boundary. Because of the way TXT does DMA memory protection, this is an unsafe
+configuration and is flagged as an error. This is most likely a configuration
+issue in the pre-launch environment. It could also be the sign of an attempted
+attack.
+
+====== ===================
+Name: SL_ERROR_TPM_EXTEND
+Value: 0xc0008006
+====== ===================
+
+Description:
+
+There was a failed attempt to extend a TPM PCR in the Secure Launch platform
+module. This is most likely to due to misconfigured hardware or kernel. Ensure
+the TPM chip is enabled, and the kernel TPM support is built in (it should not
+be built as a module).
+
+====== ======================
+Name: SL_ERROR_MTRR_INV_VCNT
+Value: 0xc0008007
+====== ======================
+
+Description:
+
+During early Secure Launch validation, an invalid variable MTRR count was
+found. The pre-launch environment passes a number of MSR values to the MLE to
+restore including the MTRRs. The values are restored by the Secure Launch early
+entry point code. After measuring the values supplied by the pre-launch
+environment, a discrepancy was found, validating the values. It could be the
+sign of an attempted attack.
+
+====== ==========================
+Name: SL_ERROR_MTRR_INV_DEF_TYPE
+Value: 0xc0008008
+====== ==========================
+
+Description:
+
+During early Secure Launch validation, an invalid default MTRR type was found.
+See SL_ERROR_MTRR_INV_VCNT for more details.
+
+====== ======================
+Name: SL_ERROR_MTRR_INV_BASE
+Value: 0xc0008009
+====== ======================
+
+Description:
+
+During early Secure Launch validation, an invalid variable MTRR base value was
+found. See SL_ERROR_MTRR_INV_VCNT for more details.
+
+====== ======================
+Name: SL_ERROR_MTRR_INV_MASK
+Value: 0xc000800a
+====== ======================
+
+Description:
+
+During early Secure Launch validation, an invalid variable MTRR mask value was
+found. See SL_ERROR_MTRR_INV_VCNT for more details.
+
+====== ========================
+Name: SL_ERROR_MSR_INV_MISC_EN
+Value: 0xc000800b
+====== ========================
+
+Description:
+
+During early Secure Launch validation, an invalid miscellaneous enable MSR
+value was found. See SL_ERROR_MTRR_INV_VCNT for more details.
+
+====== =========================
+Name: SL_ERROR_INV_AP_INTERRUPT
+Value: 0xc000800c
+====== =========================
+
+Description:
+
+The application processors (APs) wait to be woken up by the SMP initialization
+code. The only interrupt that they expect is an NMI; all other interrupts
+should be masked. If an AP gets some other interrupt other than an NMI, it will
+cause this error. This error is very unlikely to occur.
+
+====== =========================
+Name: SL_ERROR_INTEGER_OVERFLOW
+Value: 0xc000800d
+====== =========================
+
+Description:
+
+A buffer base and size passed to the MLE caused an integer overflow when
+added together. This is most likely a configuration issue in the pre-launch
+environment. It could also be the sign of an attempted attack.
+
+====== ==================
+Name: SL_ERROR_HEAP_WALK
+Value: 0xc000800e
+====== ==================
+
+Description:
+
+An error occurred in TXT heap walking code. The underlying issue is a failure to
+early_memremap() portions of the heap, most likely due to a resource shortage.
+
+====== =================
+Name: SL_ERROR_HEAP_MAP
+Value: 0xc000800f
+====== =================
+
+Description:
+
+This error is essentially the same as SL_ERROR_HEAP_WALK but occurred during the
+actual early_memremap() operation.
+
+====== =========================
+Name: SL_ERROR_REGION_ABOVE_4GB
+Value: 0xc0008010
+====== =========================
+
+Description:
+
+A memory region used by the MLE is above 4GB. In general this is not a problem
+because memory > 4Gb can be protected from DMA. There are certain buffers that
+should never be above 4Gb, and one of these caused the violation. This is most
+likely a configuration issue in the pre-launch environment. It could also be
+the sign of an attempted attack.
+
+====== ==========================
+Name: SL_ERROR_HEAP_INVALID_DMAR
+Value: 0xc0008011
+====== ==========================
+
+Description:
+
+The backup copy of the ACPI DMAR table which is supposed to be located in the
+TXT heap could not be found. This is due to a bug in the platform's ACM module
+or in firmware.
+
+====== =======================
+Name: SL_ERROR_HEAP_DMAR_SIZE
+Value: 0xc0008012
+====== =======================
+
+Description:
+
+The backup copy of the ACPI DMAR table in the TXT heap is to large to be stored
+for later usage. This error is very unlikely to occur since the area reserved
+for the copy is far larger than the DMAR should be.
+
+====== ======================
+Name: SL_ERROR_HEAP_DMAR_MAP
+Value: 0xc0008013
+====== ======================
+
+Description:
+
+The backup copy of the ACPI DMAR table in the TXT heap could not be mapped. The
+underlying issue is a failure to early_memremap() the DMAR table, most likely
+due to a resource shortage.
+
+====== ====================
+Name: SL_ERROR_HI_PMR_BASE
+Value: 0xc0008014
+====== ====================
+
+Description:
+
+On a system with more than 4G of RAM, the high PMR [2]_ base address should be
+set to 4G. This error is due to that not being the case. This PMR value is set
+by the pre-launch environment, so the issue most likely originates there. It
+could also be the sign of an attempted attack.
+
+====== ====================
+Name: SL_ERROR_HI_PMR_SIZE
+Value: 0xc0008015
+====== ====================
+
+Description:
+
+On a system with more than 4G of RAM, the high PMR [2]_ size should be set to
+cover all RAM > 4G. This error is due to that not being the case. This PMR
+value is set by the pre-launch environment, so the issue most likely originates
+there. It could also be the sign of an attempted attack.
+
+====== ====================
+Name: SL_ERROR_LO_PMR_BASE
+Value: 0xc0008016
+====== ====================
+
+Description:
+
+The low PMR [2]_ base should always be set to address zero. This error is due
+to that not being the case. This PMR value is set by the pre-launch environment
+so the issue most likely originates there. It could also be the sign of an
+attempted attack.
+
+====== ====================
+Name: SL_ERROR_LO_PMR_MLE
+Value: 0xc0008017
+====== ====================
+
+Description:
+
+This error indicates the MLE image is not covered by the low PMR [2]_ range.
+The PMR values are set by the pre-launch environment, so the issue most likely
+originates there. It could also be the sign of an attempted attack.
+
+====== =======================
+Name: SL_ERROR_INITRD_TOO_BIG
+Value: 0xc0008018
+====== =======================
+
+Description:
+
+The external initrd provided is larger than 4Gb. This is not a valid
+configuration for a Secure Launch due to managing DMA protection.
+
+====== =========================
+Name: SL_ERROR_HEAP_ZERO_OFFSET
+Value: 0xc0008019
+====== =========================
+
+Description:
+
+During a TXT heap walk, an invalid/zero next table offset value was found. This
+indicates the TXT heap is malformed. The TXT heap is initialized by the
+pre-launch environment, so the issue most likely originates there. It could
+also be a sign of an attempted attack. In addition, ACM is also responsible for
+manipulating parts of the TXT heap, so the issue could be due to a bug in the
+platform's ACM module.
+
+====== =============================
+Name: SL_ERROR_WAKE_BLOCK_TOO_SMALL
+Value: 0xc000801a
+====== =============================
+
+Description:
+
+The AP wake block buffer passed to the MLE via the OS-MLE TXT heap table is not
+large enough. This value is set by the pre-launch environment, so the issue
+most likely originates there. It also could be the sign of an attempted attack.
+
+====== ===========================
+Name: SL_ERROR_MLE_BUFFER_OVERLAP
+Value: 0xc000801b
+====== ===========================
+
+Description:
+
+One of the buffers passed to the MLE via the OS-MLE TXT heap table overlaps
+with the MLE image in memory. This value is set by the pre-launch environment
+so the issue most likely originates there. It could also be the sign of an
+attempted attack.
+
+====== ==========================
+Name: SL_ERROR_BUFFER_BEYOND_PMR
+Value: 0xc000801c
+====== ==========================
+
+Description:
+
+One of the buffers passed to the MLE via the OS-MLE TXT heap table is not
+protected by a PMR. This value is set by the pre-launch environment, so the
+issue most likely originates there. It could also be the sign of an attempted
+attack.
+
+====== =============================
+Name: SL_ERROR_OS_SINIT_BAD_VERSION
+Value: 0xc000801d
+====== =============================
+
+Description:
+
+The version of the OS-SINIT TXT heap table is bad. It must be 6 or greater.
+This value is set by the pre-launch environment, so the issue most likely
+originates there. It could also be the sign of an attempted attack. It is also
+possible though very unlikely that the platform is so old that the ACM being
+used requires an unsupported version.
+
+====== =====================
+Name: SL_ERROR_EVENTLOG_MAP
+Value: 0xc000801e
+====== =====================
+
+Description:
+
+An error occurred in the Secure Launch module while mapping the TPM event log.
+The underlying issue is memremap() failure, most likely due to a resource
+shortage.
+
+====== ========================
+Name: SL_ERROR_TPM_NUMBER_ALGS
+Value: 0xc000801f
+====== ========================
+
+Description:
+
+The TPM 2.0 event log reports an unsupported number of hashing algorithms.
+Secure launch currently only supports a maximum of two: SHA1 and SHA256.
+
+====== ===========================
+Name: SL_ERROR_TPM_UNKNOWN_DIGEST
+Value: 0xc0008020
+====== ===========================
+
+Description:
+
+The TPM 2.0 event log reports an unsupported hashing algorithm. Secure launch
+currently only supports two algorithms: SHA1 and SHA256.
+
+====== ==========================
+Name: SL_ERROR_TPM_INVALID_EVENT
+Value: 0xc0008021
+====== ==========================
+
+Description:
+
+An invalid/malformed event was found in the TPM event log while reading it.
+Since only trusted entities are supposed to be writing the event log, this
+would indicate either a bug or a possible attack.
+
+====== =====================
+Name: SL_ERROR_INVALID_SLRT
+Value: 0xc0008022
+====== =====================
+
+Description:
+
+The Secure Launch Resource Table is invalid or malformed and is unusable. This
+implies the pre-launch code did not properly set up the SLRT.
+
+====== ===========================
+Name: SL_ERROR_SLRT_MISSING_ENTRY
+Value: 0xc0008023
+====== ===========================
+
+Description:
+
+The Secure Launch Resource Table is missing a required entry within it. This
+implies the pre-launch code did not properly set up the SLRT.
+
+====== =================
+Name: SL_ERROR_SLRT_MAP
+Value: 0xc0008024
+====== =================
+
+Description:
+
+An error occurred in the Secure Launch module while mapping the Secure Launch
+Resource table. The underlying issue is memremap() failure, most likely due to
+a resource shortage.
+
+.. [1]
+ MLE: Measured Launch Environment is the binary runtime that is measured and
+ then run by the TXT SINIT ACM. The TXT MLE Development Guide describes the
+ requirements for the MLE in detail.
+
+.. [2]
+ PMR: Intel VTd has a feature in the IOMMU called Protected Memory Registers.
+ There are two of these registers and they allow all DMA to be blocked
+ to large areas of memory. The low PMR can cover all memory below 4Gb on 2Mb
+ boundaries. The high PMR can cover all RAM on the system, again on 2Mb
+ boundaries. This feature is used during a Secure Launch by TXT.
+
+.. [3]
+ Secure Launch Specification: https://trenchboot.org/specifications/Secure_Launch/
diff --git a/Documentation/security/launch-integrity/secure_launch_overview.rst b/Documentation/security/launch-integrity/secure_launch_overview.rst
new file mode 100644
index 000000000000..fa3e08780673
--- /dev/null
+++ b/Documentation/security/launch-integrity/secure_launch_overview.rst
@@ -0,0 +1,227 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright © 2019-2023 Daniel P. Smith <dpsmith@apertussolutions.com>
+
+======================
+Secure Launch Overview
+======================
+
+:Author: Daniel P. Smith
+:Date: October 2023
+
+Overview
+========
+
+Prior to the start of the TrenchBoot project, the only active Open Source
+project supporting dynamic launch was Intel's tboot project to support their
+implementation of dynamic launch known as Intel Trusted eXecution Technology
+(TXT). The approach taken by tboot was to provide an exokernel that could
+handle the launch protocol implemented by Intel's special loader, the SINIT
+Authenticated Code Module (ACM [2]_) and remained in memory to manage the SMX
+CPU mode that a dynamic launch would put a system. While it is not precluded
+from being used for doing a late launch, tboot's primary use case was to be
+used as an early launch solution. As a result, the TrenchBoot project started
+the development of Secure Launch kernel feature to provide a more generalized
+approach. The focus of the effort is twofold, the first is to make the Linux
+kernel directly aware of the launch protocol used by Intel, AMD/Hygon, Arm, and
+potentially OpenPOWER. The second is to make the Linux kernel be able to
+initiate a dynamic launch. It is through this approach that the Secure Launch
+kernel feature creates a basis for the Linux kernel to be used in a variety of
+dynamic launch use cases.
+
+.. note::
+ A quick note on terminology. The larger open source project itself is
+ called TrenchBoot, which is hosted on GitHub (links below). The kernel
+ feature enabling the use of the x86 technology is referred to as "Secure
+ Launch" within the kernel code.
+
+Goals
+=====
+
+The first use case that the TrenchBoot project focused on was the ability for
+the Linux kernel to be started by a dynamic launch, in particular as part of an
+early launch sequence. In this case, the dynamic launch will be initiated by
+any bootloader with associated support added to it, for example the first
+targeted bootloader in this case was GRUB2. An integral part of establishing a
+measurement-based launch integrity involves measuring everything that is
+intended to be executed (kernel image, initrd, etc.) and everything that will
+configure that kernel to execute (command line, boot params, etc.). Then
+storing those measurements in a protected manner. Both the Intel and AMD
+dynamic launch implementations leverage the Trusted Platform Module (TPM) to
+store those measurements. The TPM itself has been designed such that a dynamic
+launch unlocks a specific set of Platform Configuration Registers (PCR) for
+holding measurement taken during the dynamic launch. These are referred to as
+the DRTM PCRs, PCRs 17-22. Further details on this process can be found in the
+documentation for the GETSEC instruction provided by Intel's TXT and the SKINIT
+instruction provided by AMD's AMD-V. The documentation on these technologies
+can be readily found online; see the `Resources`_ section below for references.
+
+.. note::
+ Currently, only Intel TXT is supported in this first release of the Secure
+ Launch feature. AMD/Hygon SKINIT and Arm support will be added in a
+ subsequent release.
+
+To enable the kernel to be launched by GETSEC a stub, the Secure Launch stub,
+must be built into the setup section of the compressed kernel to handle the
+specific state that the dynamic launch process leaves the BSP. Also, the Secure
+Launch stub must measure everything that is going to be used as early as
+possible. This stub code and subsequent code must also deal with the specific
+state that the dynamic launch leaves the APs as well.
+
+Design Decisions
+================
+
+A number of design decisions were made during the development of the Secure
+Launch feature. The two primary guiding decisions were:
+
+ - Keeping the Secure Launch code as separate from the rest of the kernel
+ as possible.
+ - Modifying the existing boot path of the kernel as little as possible.
+
+The following illustrate how the implementation followed these design
+decisions:
+
+ - All the entry point code necessary to properly configure the system post
+ launch is found in st_stub.S in the compressed kernel image. This code
+ validates the state of the system, restores necessary system operating
+ configurations and properly handles post launch CPU states.
+ - After the sl_stub.S is complete, it jumps directly to the unmodified
+ startup_32 kernel entry point.
+ - A single call is made to a function sl_main() prior to the main kernel
+ decompression step. This code performs further validation and takes the
+ needed DRTM measurements.
+ - After the call to sl_main(), the main kernel is decompressed and boots as
+ it normally would.
+ - Final setup for the Secure Launch kernel is done in a separate Secure
+ Launch module that is loaded via a late initcall. This code is responsible
+ for extending the measurements taken earlier into the TPM DRTM PCRs and
+ setting up the securityfs interface to allow access to the TPM event log and
+ public TXT registers.
+ - On the reboot and kexec paths, calls are made to a function to finalize the
+ state of the Secure Launch kernel.
+
+The one place where Secure Launch code is mixed directly in with kernel code is
+in the SMP boot code. This is due to the unique state that the dynamic launch
+leaves the APs in. On Intel, this involves using a method other than the
+standard INIT-SIPI sequence.
+
+A final note is that originally the extending of the PCRs was completed in the
+Secure Launch stub when the measurements were taken. An alternative solution
+had to be implemented due to the TPM maintainers objecting to the PCR
+extensions being done with a minimal interface to the TPM that was an
+independent implementation of the mainline kernel driver. Since the mainline
+driver relies heavily on kernel interfaces not available in the compressed
+kernel, it was not possible to reuse the mainline TPM driver. This resulted in
+the decision to move the extension operations to the Secure Launch module in
+the mainline kernel, where the TPM driver would be available.
+
+Basic Boot Flow
+===============
+
+Outlined here is a summary of the boot flow for Secure Launch. A more detailed
+review of Secure Launch process can be found in the Secure Launch
+Specification, a link is located in the `Resources`_ section.
+
+Pre-launch: *Phase where the environment is prepared and configured to initiate
+the secure launch by the boot chain.*
+
+ - The SLRT is initialized and dl_stub is placed in memory.
+ - Load the kernel, initrd and ACM [2]_ into memory.
+ - Set up the TXT heap and page tables describing the MLE [1]_ per the
+ specification.
+ - If non-UEFI platform, dl_stub is called.
+ - If UEFI platforms, SLRT registered with UEFI and efi-stub called.
+ - Upon completion, efi-stub will call EBS followed by dl_stub.
+ - The dl_stub will prepare the CPU and the TPM for the launch.
+ - The secure launch is then initiated with the GETSET[SENTER] instruction.
+
+Post-launch: *Phase where control is passed from the ACM to the MLE and the secure
+kernel begins execution.*
+
+ - Entry from the dynamic launch jumps to the SL stub.
+ - SL stub fixes up the world on the BSP.
+ - For TXT, SL stub wakes the APs, fixes up their worlds.
+ - For TXT, APs are left halted using MONITOR/MWAIT intructions.
+ - SL stub jumps to startup_32.
+ - SL main does validation of buffers and memory locations. It sets
+ the boot parameter loadflag value SLAUNCH_FLAG to inform the main
+ kernel that a Secure Launch was done.
+ - SL main locates the TPM event log and writes the measurements of
+ configuration and module information into it.
+ - Kernel boot proceeds normally from this point.
+ - During early setup, slaunch_setup() runs to finish some validation
+ and setup tasks.
+ - The SMP bring up code is modified to wake the waiting APs via the monitor
+ address.
+ - APs vector to rmpiggy and start up normally from that point.
+ - SL platform module is registered as a late initcall module. It reads
+ the TPM event log and extends the measurements taken into the TPM PCRs.
+ - SL platform module initializes the securityfs interface to allow
+ access to the TPM event log and TXT public registers.
+ - Kernel boot finishes booting normally
+ - SEXIT support to leave SMX mode is present on the kexec path and
+ the various reboot paths (poweroff, reset, halt).
+
+PCR Usage
+=========
+
+The TCG DRTM architecture there are three PCRs defined for usage, PCR.Details
+(PCR17), PCR.Authorities (PCR18), and PCR.DLME_Authority (PCR19). For a deeper
+understanding of Detail and Authorities it is recommended to review the TCG
+DRTM architecture.
+
+To determine PCR usage, Linux Secure Launch follows the TrenchBoot Secure
+Launch Specification of using a measurement policy stored in the SLRT. The
+policy details what should be measured and the PCR in which to store the
+measurement. The measurement policy provides the ability to select the
+PCR.DLME_Detail (PCR20) PCR as the location for the DRTM components measured by
+the kernel, e.g. external initrd image. This can then be combined with storing
+the user authority in the PCR.DLME_Authority PCR to seal/attest to different
+variations of platform details/authorities and user details/authorities. An
+example of how this can be achieved was presented in the FOSDEM - 2021 talk
+"Secure Upgrades with DRTM".
+
+Resources
+=========
+
+The TrenchBoot project:
+
+https://trenchboot.org
+
+Secure Launch Specification:
+
+https://trenchboot.org/specifications/Secure_Launch/
+
+Trusted Computing Group's D-RTM Architecture:
+
+https://trustedcomputinggroup.org/wp-content/uploads/TCG_D-RTM_Architecture_v1-0_Published_06172013.pdf
+
+TXT documentation in the Intel TXT MLE Development Guide:
+
+https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
+
+TXT instructions documentation in the Intel SDM Instruction Set volume:
+
+https://software.intel.com/en-us/articles/intel-sdm
+
+AMD SKINIT documentation in the System Programming manual:
+
+https://www.amd.com/system/files/TechDocs/24593.pdf
+
+GRUB Secure Launch support:
+
+https://github.com/TrenchBoot/grub/tree/grub-sl-fc-38-dlstub
+
+FOSDEM 2021: Secure Upgrades with DRTM
+
+https://archive.fosdem.org/2021/schedule/event/firmware_suwd/
+
+.. [1]
+ MLE: Measured Launch Environment is the binary runtime that is measured and
+ then run by the TXT SINIT ACM. The TXT MLE Development Guide describes the
+ requirements for the MLE in detail.
+
+.. [2]
+ ACM: Intel's Authenticated Code Module. This is the 32b bit binary blob that
+ is run securely by the GETSEC[SENTER] during a measured launch. It is described
+ in the Intel documentation on TXT and versions for various chipsets are
+ signed and distributed by Intel.
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 03/19] x86: Secure Launch Kconfig
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
2024-05-31 1:03 ` [PATCH v9 01/19] x86/boot: Place kernel_info at a fixed offset Ross Philipson
2024-05-31 1:03 ` [PATCH v9 02/19] Documentation/x86: Secure Launch kernel documentation Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 04/19] x86: Secure Launch Resource Table header file Ross Philipson
` (15 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Initial bits to bring in Secure Launch functionality. Add Kconfig
options for compiling in/out the Secure Launch code.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/Kconfig | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index bc47bc9841ff..ee8e0cbc9a3e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2067,6 +2067,17 @@ config EFI_RUNTIME_MAP
See also Documentation/ABI/testing/sysfs-firmware-efi-runtime-map.
+config SECURE_LAUNCH
+ bool "Secure Launch support"
+ depends on X86_64 && X86_X2APIC && TCG_TPM && CRYPTO_LIB_SHA1 && CRYPTO_LIB_SHA256
+ help
+ The Secure Launch feature allows a kernel to be loaded
+ directly through an Intel TXT measured launch. Intel TXT
+ establishes a Dynamic Root of Trust for Measurement (DRTM)
+ where the CPU measures the kernel image. This feature then
+ continues the measurement chain over kernel configuration
+ information and init images.
+
source "kernel/Kconfig.hz"
config ARCH_SUPPORTS_KEXEC
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (2 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 03/19] x86: Secure Launch Kconfig Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 18:21 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 05/19] x86: Secure Launch main " Ross Philipson
` (14 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Introduce the Secure Launch Resource Table which forms the formal
interface between the pre and post launch code.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
include/linux/slr_table.h | 271 ++++++++++++++++++++++++++++++++++++++
1 file changed, 271 insertions(+)
create mode 100644 include/linux/slr_table.h
diff --git a/include/linux/slr_table.h b/include/linux/slr_table.h
new file mode 100644
index 000000000000..213d8ac16f0f
--- /dev/null
+++ b/include/linux/slr_table.h
@@ -0,0 +1,271 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Secure Launch Resource Table
+ *
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ */
+
+#ifndef _LINUX_SLR_TABLE_H
+#define _LINUX_SLR_TABLE_H
+
+/* Put this in efi.h if it becomes a standard */
+#define SLR_TABLE_GUID EFI_GUID(0x877a9b2a, 0x0385, 0x45d1, 0xa0, 0x34, 0x9d, 0xac, 0x9c, 0x9e, 0x56, 0x5f)
+
+/* SLR table header values */
+#define SLR_TABLE_MAGIC 0x4452544d
+#define SLR_TABLE_REVISION 1
+
+/* Current revisions for the policy and UEFI config */
+#define SLR_POLICY_REVISION 1
+#define SLR_UEFI_CONFIG_REVISION 1
+
+/* SLR defined architectures */
+#define SLR_INTEL_TXT 1
+#define SLR_AMD_SKINIT 2
+
+/* SLR defined bootloaders */
+#define SLR_BOOTLOADER_INVALID 0
+#define SLR_BOOTLOADER_GRUB 1
+
+/* Log formats */
+#define SLR_DRTM_TPM12_LOG 1
+#define SLR_DRTM_TPM20_LOG 2
+
+/* DRTM Policy Entry Flags */
+#define SLR_POLICY_FLAG_MEASURED 0x1
+#define SLR_POLICY_IMPLICIT_SIZE 0x2
+
+/* Array Lengths */
+#define TPM_EVENT_INFO_LENGTH 32
+#define TXT_VARIABLE_MTRRS_LENGTH 32
+
+/* Tags */
+#define SLR_ENTRY_INVALID 0x0000
+#define SLR_ENTRY_DL_INFO 0x0001
+#define SLR_ENTRY_LOG_INFO 0x0002
+#define SLR_ENTRY_ENTRY_POLICY 0x0003
+#define SLR_ENTRY_INTEL_INFO 0x0004
+#define SLR_ENTRY_AMD_INFO 0x0005
+#define SLR_ENTRY_ARM_INFO 0x0006
+#define SLR_ENTRY_UEFI_INFO 0x0007
+#define SLR_ENTRY_UEFI_CONFIG 0x0008
+#define SLR_ENTRY_END 0xffff
+
+/* Entity Types */
+#define SLR_ET_UNSPECIFIED 0x0000
+#define SLR_ET_SLRT 0x0001
+#define SLR_ET_BOOT_PARAMS 0x0002
+#define SLR_ET_SETUP_DATA 0x0003
+#define SLR_ET_CMDLINE 0x0004
+#define SLR_ET_UEFI_MEMMAP 0x0005
+#define SLR_ET_RAMDISK 0x0006
+#define SLR_ET_TXT_OS2MLE 0x0010
+#define SLR_ET_UNUSED 0xffff
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Primary Secure Launch Resource Table Header
+ */
+struct slr_table {
+ u32 magic;
+ u16 revision;
+ u16 architecture;
+ u32 size;
+ u32 max_size;
+ /* table entries */
+} __packed;
+
+/*
+ * Common SLRT Table Header
+ */
+struct slr_entry_hdr {
+ u16 tag;
+ u16 size;
+} __packed;
+
+/*
+ * Boot loader context
+ */
+struct slr_bl_context {
+ u16 bootloader;
+ u16 reserved[3];
+ u64 context;
+} __packed;
+
+/*
+ * Dynamic Launch Callback Function type
+ */
+typedef void (*dl_handler_func)(struct slr_bl_context *bl_context);
+
+/*
+ * DRTM Dynamic Launch Configuration
+ */
+struct slr_entry_dl_info {
+ struct slr_entry_hdr hdr;
+ u32 dce_size;
+ u64 dce_base;
+ u64 dlme_size;
+ u64 dlme_base;
+ u64 dlme_entry;
+ struct slr_bl_context bl_context;
+ u64 dl_handler;
+} __packed;
+
+/*
+ * TPM Log Information
+ */
+struct slr_entry_log_info {
+ struct slr_entry_hdr hdr;
+ u16 format;
+ u16 reserved[3];
+ u32 size;
+ u64 addr;
+} __packed;
+
+/*
+ * DRTM Measurement Entry
+ */
+struct slr_policy_entry {
+ u16 pcr;
+ u16 entity_type;
+ u16 flags;
+ u16 reserved;
+ u64 size;
+ u64 entity;
+ char evt_info[TPM_EVENT_INFO_LENGTH];
+} __packed;
+
+/*
+ * DRTM Measurement Policy
+ */
+struct slr_entry_policy {
+ struct slr_entry_hdr hdr;
+ u16 revision;
+ u16 nr_entries;
+ struct slr_policy_entry policy_entries[];
+} __packed;
+
+/*
+ * Secure Launch defined MTRR saving structures
+ */
+struct slr_txt_mtrr_pair {
+ u64 mtrr_physbase;
+ u64 mtrr_physmask;
+} __packed;
+
+struct slr_txt_mtrr_state {
+ u64 default_mem_type;
+ u64 mtrr_vcnt;
+ struct slr_txt_mtrr_pair mtrr_pair[TXT_VARIABLE_MTRRS_LENGTH];
+} __packed;
+
+/*
+ * Intel TXT Info table
+ */
+struct slr_entry_intel_info {
+ struct slr_entry_hdr hdr;
+ u16 reserved[2];
+ u64 txt_heap;
+ u64 saved_misc_enable_msr;
+ struct slr_txt_mtrr_state saved_bsp_mtrrs;
+} __packed;
+
+/*
+ * UEFI config measurement entry
+ */
+struct slr_uefi_cfg_entry {
+ u16 pcr;
+ u16 reserved;
+ u32 size;
+ u64 cfg; /* address or value */
+ char evt_info[TPM_EVENT_INFO_LENGTH];
+} __packed;
+
+/*
+ * UEFI config measurements
+ */
+struct slr_entry_uefi_config {
+ struct slr_entry_hdr hdr;
+ u16 revision;
+ u16 nr_entries;
+ struct slr_uefi_cfg_entry uefi_cfg_entries[];
+} __packed;
+
+static inline void *slr_end_of_entries(struct slr_table *table)
+{
+ return (void *)table + table->size;
+}
+
+static inline void *
+slr_next_entry(struct slr_table *table,
+ struct slr_entry_hdr *curr)
+{
+ struct slr_entry_hdr *next = (struct slr_entry_hdr *)
+ ((u8 *)curr + curr->size);
+
+ if ((void *)next >= slr_end_of_entries(table))
+ return NULL;
+ if (next->tag == SLR_ENTRY_END)
+ return NULL;
+
+ return next;
+}
+
+static inline void *
+slr_next_entry_by_tag(struct slr_table *table,
+ struct slr_entry_hdr *entry,
+ u16 tag)
+{
+ if (!entry) /* Start from the beginning */
+ entry = (struct slr_entry_hdr *)(((u8 *)table) + sizeof(*table));
+
+ for ( ; ; ) {
+ if (entry->tag == tag)
+ return entry;
+
+ entry = slr_next_entry(table, entry);
+ if (!entry)
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static inline int
+slr_add_entry(struct slr_table *table,
+ struct slr_entry_hdr *entry)
+{
+ struct slr_entry_hdr *end;
+
+ if ((table->size + entry->size) > table->max_size)
+ return -1;
+
+ memcpy((u8 *)table + table->size - sizeof(*end), entry, entry->size);
+ table->size += entry->size;
+
+ end = (struct slr_entry_hdr *)((u8 *)table + table->size - sizeof(*end));
+ end->tag = SLR_ENTRY_END;
+ end->size = sizeof(*end);
+
+ return 0;
+}
+
+static inline void
+slr_init_table(struct slr_table *slrt, u16 architecture, u32 max_size)
+{
+ struct slr_entry_hdr *end;
+
+ slrt->magic = SLR_TABLE_MAGIC;
+ slrt->revision = SLR_TABLE_REVISION;
+ slrt->architecture = architecture;
+ slrt->size = sizeof(*slrt) + sizeof(*end);
+ slrt->max_size = max_size;
+ end = (struct slr_entry_hdr *)((u8 *)slrt + sizeof(*slrt));
+ end->tag = SLR_ENTRY_END;
+ end->size = sizeof(*end);
+}
+
+#endif /* !__ASSEMBLY */
+
+#endif /* _LINUX_SLR_TABLE_H */
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-05-31 1:03 ` [PATCH v9 04/19] x86: Secure Launch Resource Table header file Ross Philipson
@ 2024-06-04 18:21 ` Jarkko Sakkinen
2024-06-04 20:31 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 18:21 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> Introduce the Secure Launch Resource Table which forms the formal
> interface between the pre and post launch code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
If a uarch specific, I'd appreciate Intel SDM reference here so that I
can look it up and compare. Like in section granularity.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-04 18:21 ` Jarkko Sakkinen
@ 2024-06-04 20:31 ` ross.philipson
2024-06-04 22:36 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 20:31 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> Introduce the Secure Launch Resource Table which forms the formal
>> interface between the pre and post launch code.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> If a uarch specific, I'd appreciate Intel SDM reference here so that I
> can look it up and compare. Like in section granularity.
This table is meant to not be architecture specific though it can
contain architecture specific sub-entities. E.g. there is a TXT specific
table and in the future there will be an AMD and ARM one (and hopefully
some others). I hope that addresses what you are pointing out or maybe I
don't fully understand what you mean here...
Thanks
Ross
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-04 20:31 ` ross.philipson
@ 2024-06-04 22:36 ` Jarkko Sakkinen
2024-06-04 23:00 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:36 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
> > On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >> Introduce the Secure Launch Resource Table which forms the formal
> >> interface between the pre and post launch code.
> >>
> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >
> > If a uarch specific, I'd appreciate Intel SDM reference here so that I
> > can look it up and compare. Like in section granularity.
>
> This table is meant to not be architecture specific though it can
> contain architecture specific sub-entities. E.g. there is a TXT specific
> table and in the future there will be an AMD and ARM one (and hopefully
> some others). I hope that addresses what you are pointing out or maybe I
> don't fully understand what you mean here...
At least Intel SDM has a definition of any possible architecture
specific data structure. It is handy to also have this available
in inline comment for any possible such structure pointing out the
section where it is defined.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-04 22:36 ` Jarkko Sakkinen
@ 2024-06-04 23:00 ` ross.philipson
2024-06-05 0:22 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 23:00 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
> On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
>> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
>>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>>>> Introduce the Secure Launch Resource Table which forms the formal
>>>> interface between the pre and post launch code.
>>>>
>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>
>>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
>>> can look it up and compare. Like in section granularity.
>>
>> This table is meant to not be architecture specific though it can
>> contain architecture specific sub-entities. E.g. there is a TXT specific
>> table and in the future there will be an AMD and ARM one (and hopefully
>> some others). I hope that addresses what you are pointing out or maybe I
>> don't fully understand what you mean here...
>
> At least Intel SDM has a definition of any possible architecture
> specific data structure. It is handy to also have this available
> in inline comment for any possible such structure pointing out the
> section where it is defined.
The TXT specific structure is not defined in the SDM or the TXT dev
guide. Part of it is driven by requirements in the TXT dev guide but
that guide does not contain implementation details.
That said, if you would like links to relevant documents in the comments
before arch specific structures, I can add them.
Ross
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-04 23:00 ` ross.philipson
@ 2024-06-05 0:22 ` Jarkko Sakkinen
2024-06-05 0:27 ` Jarkko Sakkinen
2024-06-05 2:33 ` ross.philipson
0 siblings, 2 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-05 0:22 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 2:00 AM EEST, wrote:
> On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
> > On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
> >> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
> >>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >>>> Introduce the Secure Launch Resource Table which forms the formal
> >>>> interface between the pre and post launch code.
> >>>>
> >>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >>>
> >>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
> >>> can look it up and compare. Like in section granularity.
> >>
> >> This table is meant to not be architecture specific though it can
> >> contain architecture specific sub-entities. E.g. there is a TXT specific
> >> table and in the future there will be an AMD and ARM one (and hopefully
> >> some others). I hope that addresses what you are pointing out or maybe I
> >> don't fully understand what you mean here...
> >
> > At least Intel SDM has a definition of any possible architecture
> > specific data structure. It is handy to also have this available
> > in inline comment for any possible such structure pointing out the
> > section where it is defined.
>
> The TXT specific structure is not defined in the SDM or the TXT dev
> guide. Part of it is driven by requirements in the TXT dev guide but
> that guide does not contain implementation details.
>
> That said, if you would like links to relevant documents in the comments
> before arch specific structures, I can add them.
Vol. 2D 7-40, in the description of GETSEC[WAKEUP] there is in fact a
description of MLE JOINT structure at least:
1. GDT limit (offset 0)
2. GDT base (offset 4)
3. Segment selector initializer (offset 8)
4. EIP (offset 12)
So is this only exercised in protect mode, and not in long mode? Just
wondering whether I should make a bug report on this for SDM or not.
Especially this puzzles me, given that x86s won't have protected
mode in the first place...
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-05 0:22 ` Jarkko Sakkinen
@ 2024-06-05 0:27 ` Jarkko Sakkinen
2024-06-05 2:33 ` ross.philipson
1 sibling, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-05 0:27 UTC (permalink / raw)
To: Jarkko Sakkinen, ross.philipson, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 3:22 AM EEST, Jarkko Sakkinen wrote:
> On Wed Jun 5, 2024 at 2:00 AM EEST, wrote:
> > On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
> > > On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
> > >> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
> > >>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> > >>>> Introduce the Secure Launch Resource Table which forms the formal
> > >>>> interface between the pre and post launch code.
> > >>>>
> > >>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> > >>>
> > >>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
> > >>> can look it up and compare. Like in section granularity.
> > >>
> > >> This table is meant to not be architecture specific though it can
> > >> contain architecture specific sub-entities. E.g. there is a TXT specific
> > >> table and in the future there will be an AMD and ARM one (and hopefully
> > >> some others). I hope that addresses what you are pointing out or maybe I
> > >> don't fully understand what you mean here...
> > >
> > > At least Intel SDM has a definition of any possible architecture
> > > specific data structure. It is handy to also have this available
> > > in inline comment for any possible such structure pointing out the
> > > section where it is defined.
> >
> > The TXT specific structure is not defined in the SDM or the TXT dev
> > guide. Part of it is driven by requirements in the TXT dev guide but
> > that guide does not contain implementation details.
> >
> > That said, if you would like links to relevant documents in the comments
> > before arch specific structures, I can add them.
>
> Vol. 2D 7-40, in the description of GETSEC[WAKEUP] there is in fact a
> description of MLE JOINT structure at least:
>
> 1. GDT limit (offset 0)
> 2. GDT base (offset 4)
> 3. Segment selector initializer (offset 8)
> 4. EIP (offset 12)
>
> So is this only exercised in protect mode, and not in long mode? Just
> wondering whether I should make a bug report on this for SDM or not.
>
> Especially this puzzles me, given that x86s won't have protected
> mode in the first place...
That raises a relevant question: will this ever work in x86s? SDM does
not really support that it would but it could be also just outdated
information.
I'm neither sure how or will AMD align with x86s.
Just point out a glitch...
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-05 0:22 ` Jarkko Sakkinen
2024-06-05 0:27 ` Jarkko Sakkinen
@ 2024-06-05 2:33 ` ross.philipson
2024-06-05 4:04 ` Jarkko Sakkinen
1 sibling, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-05 2:33 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 5:22 PM, Jarkko Sakkinen wrote:
> On Wed Jun 5, 2024 at 2:00 AM EEST, wrote:
>> On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
>>> On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
>>>> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
>>>>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>>>>>> Introduce the Secure Launch Resource Table which forms the formal
>>>>>> interface between the pre and post launch code.
>>>>>>
>>>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>>>
>>>>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
>>>>> can look it up and compare. Like in section granularity.
>>>>
>>>> This table is meant to not be architecture specific though it can
>>>> contain architecture specific sub-entities. E.g. there is a TXT specific
>>>> table and in the future there will be an AMD and ARM one (and hopefully
>>>> some others). I hope that addresses what you are pointing out or maybe I
>>>> don't fully understand what you mean here...
>>>
>>> At least Intel SDM has a definition of any possible architecture
>>> specific data structure. It is handy to also have this available
>>> in inline comment for any possible such structure pointing out the
>>> section where it is defined.
>>
>> The TXT specific structure is not defined in the SDM or the TXT dev
>> guide. Part of it is driven by requirements in the TXT dev guide but
>> that guide does not contain implementation details.
>>
>> That said, if you would like links to relevant documents in the comments
>> before arch specific structures, I can add them.
>
> Vol. 2D 7-40, in the description of GETSEC[WAKEUP] there is in fact a
> description of MLE JOINT structure at least:
>
> 1. GDT limit (offset 0)
> 2. GDT base (offset 4)
> 3. Segment selector initializer (offset 8)
> 4. EIP (offset 12)
>
> So is this only exercised in protect mode, and not in long mode? Just
> wondering whether I should make a bug report on this for SDM or not.
I believe you can issue the SENTER instruction in long mode, compat mode
or protected mode. On the other side thought, you will pop out of the
TXT initialization in protected mode. The SDM outlines what registers
will hold what values and what is valid and not valid. The APs will also
vector through the join structure mentioned above to the location
specified in protected mode using the GDT information you provide.
>
> Especially this puzzles me, given that x86s won't have protected
> mode in the first place...
My guess is the simplified x86 architecture will not support TXT. It is
not supported on a number of CPUs/chipsets as it stands today. Just a
guess but we know only vPro systems support TXT today.
Thanks
Ross
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-05 2:33 ` ross.philipson
@ 2024-06-05 4:04 ` Jarkko Sakkinen
2024-06-05 19:03 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-05 4:04 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 5:33 AM EEST, wrote:
> On 6/4/24 5:22 PM, Jarkko Sakkinen wrote:
> > On Wed Jun 5, 2024 at 2:00 AM EEST, wrote:
> >> On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
> >>> On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
> >>>> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
> >>>>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >>>>>> Introduce the Secure Launch Resource Table which forms the formal
> >>>>>> interface between the pre and post launch code.
> >>>>>>
> >>>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >>>>>
> >>>>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
> >>>>> can look it up and compare. Like in section granularity.
> >>>>
> >>>> This table is meant to not be architecture specific though it can
> >>>> contain architecture specific sub-entities. E.g. there is a TXT specific
> >>>> table and in the future there will be an AMD and ARM one (and hopefully
> >>>> some others). I hope that addresses what you are pointing out or maybe I
> >>>> don't fully understand what you mean here...
> >>>
> >>> At least Intel SDM has a definition of any possible architecture
> >>> specific data structure. It is handy to also have this available
> >>> in inline comment for any possible such structure pointing out the
> >>> section where it is defined.
> >>
> >> The TXT specific structure is not defined in the SDM or the TXT dev
> >> guide. Part of it is driven by requirements in the TXT dev guide but
> >> that guide does not contain implementation details.
> >>
> >> That said, if you would like links to relevant documents in the comments
> >> before arch specific structures, I can add them.
> >
> > Vol. 2D 7-40, in the description of GETSEC[WAKEUP] there is in fact a
> > description of MLE JOINT structure at least:
> >
> > 1. GDT limit (offset 0)
> > 2. GDT base (offset 4)
> > 3. Segment selector initializer (offset 8)
> > 4. EIP (offset 12)
> >
> > So is this only exercised in protect mode, and not in long mode? Just
> > wondering whether I should make a bug report on this for SDM or not.
>
> I believe you can issue the SENTER instruction in long mode, compat mode
> or protected mode. On the other side thought, you will pop out of the
> TXT initialization in protected mode. The SDM outlines what registers
> will hold what values and what is valid and not valid. The APs will also
> vector through the join structure mentioned above to the location
> specified in protected mode using the GDT information you provide.
>
> >
> > Especially this puzzles me, given that x86s won't have protected
> > mode in the first place...
>
> My guess is the simplified x86 architecture will not support TXT. It is
> not supported on a number of CPUs/chipsets as it stands today. Just a
> guess but we know only vPro systems support TXT today.
I'm wondering could this bootstrap itself inside TDX or SNP, and that
way provide path forward? AFAIK, TDX can be nested straight of the bat
and SNP from 2nd generation EPYC's, which contain the feature.
I do buy the idea of attesting the host, not just the guests, even in
the "confidential world". That said, I'm not sure does it make sense
to add all this infrastructure for a technology with such a short
expiration date?
I would not want to say this at v9, and it is not really your fault
either, but for me this would make a lot more sense if the core of
Trenchboot was redesigned around these newer technologies with a
long-term future.
The idea itself is great!
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-05 4:04 ` Jarkko Sakkinen
@ 2024-06-05 19:03 ` ross.philipson
2024-06-06 6:02 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-05 19:03 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 9:04 PM, Jarkko Sakkinen wrote:
> On Wed Jun 5, 2024 at 5:33 AM EEST, wrote:
>> On 6/4/24 5:22 PM, Jarkko Sakkinen wrote:
>>> On Wed Jun 5, 2024 at 2:00 AM EEST, wrote:
>>>> On 6/4/24 3:36 PM, Jarkko Sakkinen wrote:
>>>>> On Tue Jun 4, 2024 at 11:31 PM EEST, wrote:
>>>>>> On 6/4/24 11:21 AM, Jarkko Sakkinen wrote:
>>>>>>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>>>>>>>> Introduce the Secure Launch Resource Table which forms the formal
>>>>>>>> interface between the pre and post launch code.
>>>>>>>>
>>>>>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>>>>>
>>>>>>> If a uarch specific, I'd appreciate Intel SDM reference here so that I
>>>>>>> can look it up and compare. Like in section granularity.
>>>>>>
>>>>>> This table is meant to not be architecture specific though it can
>>>>>> contain architecture specific sub-entities. E.g. there is a TXT specific
>>>>>> table and in the future there will be an AMD and ARM one (and hopefully
>>>>>> some others). I hope that addresses what you are pointing out or maybe I
>>>>>> don't fully understand what you mean here...
>>>>>
>>>>> At least Intel SDM has a definition of any possible architecture
>>>>> specific data structure. It is handy to also have this available
>>>>> in inline comment for any possible such structure pointing out the
>>>>> section where it is defined.
>>>>
>>>> The TXT specific structure is not defined in the SDM or the TXT dev
>>>> guide. Part of it is driven by requirements in the TXT dev guide but
>>>> that guide does not contain implementation details.
>>>>
>>>> That said, if you would like links to relevant documents in the comments
>>>> before arch specific structures, I can add them.
>>>
>>> Vol. 2D 7-40, in the description of GETSEC[WAKEUP] there is in fact a
>>> description of MLE JOINT structure at least:
>>>
>>> 1. GDT limit (offset 0)
>>> 2. GDT base (offset 4)
>>> 3. Segment selector initializer (offset 8)
>>> 4. EIP (offset 12)
>>>
>>> So is this only exercised in protect mode, and not in long mode? Just
>>> wondering whether I should make a bug report on this for SDM or not.
>>
>> I believe you can issue the SENTER instruction in long mode, compat mode
>> or protected mode. On the other side thought, you will pop out of the
>> TXT initialization in protected mode. The SDM outlines what registers
>> will hold what values and what is valid and not valid. The APs will also
>> vector through the join structure mentioned above to the location
>> specified in protected mode using the GDT information you provide.
>>
>>>
>>> Especially this puzzles me, given that x86s won't have protected
>>> mode in the first place...
>>
>> My guess is the simplified x86 architecture will not support TXT. It is
>> not supported on a number of CPUs/chipsets as it stands today. Just a
>> guess but we know only vPro systems support TXT today.
>
> I'm wondering could this bootstrap itself inside TDX or SNP, and that
> way provide path forward? AFAIK, TDX can be nested straight of the bat
> and SNP from 2nd generation EPYC's, which contain the feature.
>
> I do buy the idea of attesting the host, not just the guests, even in
> the "confidential world". That said, I'm not sure does it make sense
> to add all this infrastructure for a technology with such a short
> expiration date?
>
> I would not want to say this at v9, and it is not really your fault
> either, but for me this would make a lot more sense if the core of
> Trenchboot was redesigned around these newer technologies with a
> long-term future.
So I did not mean to imply that DRTM support on various
platforms/architectures has a short expiration date. In fact we are
actively working on DRTM support through the TrenchBoot project on
several platforms/architectures. Just a quick rundown here:
Intel: Plenty of Intel platforms are vPro with TXT. It is really just
the lower end systems that don't have it available (like Core i3). And
my guess was wrong about x86s. You can find the spec on the page in the
following link. There is an entire subsection on SMX support on x86s and
the changes to the various GETSEC instruction leaves that were made to
make it work there (see 3.15).
https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html
AMD: We are actively working on SKINIT DRTM support that will go into
TrenchBoot. There are changes coming soon to AMD SKINIT to make it more
robust and address some earlier issues. We hope to be able to start
sending AMD DRTM support up in the posts to LKML in the not too distant
future.
Arm: They have recently released their DRTM specification and at least
one Arm vendor is close to releasing firmware that will support DRTM.
Again we are actively working in this area on the TrenchBoot project.
https://developer.arm.com/documentation/den0113/latest/
One final thought I had. The technologies you mentioned above seem to be
to be complementary to DRTM as opposed to being a replacement for it, at
least to me but I am not an expert on them.
Perhaps Daniel Smith would like to expand on what I have said here.
Thanks
Ross
>
> The idea itself is great!
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-05 19:03 ` ross.philipson
@ 2024-06-06 6:02 ` Jarkko Sakkinen
2024-06-06 16:49 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-06 6:02 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 10:03 PM EEST, wrote:
> So I did not mean to imply that DRTM support on various
> platforms/architectures has a short expiration date. In fact we are
> actively working on DRTM support through the TrenchBoot project on
> several platforms/architectures. Just a quick rundown here:
>
> Intel: Plenty of Intel platforms are vPro with TXT. It is really just
> the lower end systems that don't have it available (like Core i3). And
> my guess was wrong about x86s. You can find the spec on the page in the
> following link. There is an entire subsection on SMX support on x86s and
> the changes to the various GETSEC instruction leaves that were made to
> make it work there (see 3.15).
>
> https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html
Happend to bump into same PDF specification and exactly the seeked
information is "3.15 SMX Changes". So just write this down to some
patch that starts adding SMX things.
Link: https://cdrdv2.intel.com/v1/dl/getContent/776648
So link and document, and other stuff above is not relevant from
upstream context, only potential maintenance burden :-)
For any architectures dig a similar fact:
1. Is not dead.
2. Will be there also in future.
Make any architecture existentially relevant for and not too much
coloring in the text that is easy to check.
It is nearing 5k lines so you should be really good with measured
facts too (not just launch) :-)
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-06 6:02 ` Jarkko Sakkinen
@ 2024-06-06 16:49 ` ross.philipson
2024-06-20 0:18 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-06 16:49 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/5/24 11:02 PM, Jarkko Sakkinen wrote:
> On Wed Jun 5, 2024 at 10:03 PM EEST, wrote:
>> So I did not mean to imply that DRTM support on various
>> platforms/architectures has a short expiration date. In fact we are
>> actively working on DRTM support through the TrenchBoot project on
>> several platforms/architectures. Just a quick rundown here:
>>
>> Intel: Plenty of Intel platforms are vPro with TXT. It is really just
>> the lower end systems that don't have it available (like Core i3). And
>> my guess was wrong about x86s. You can find the spec on the page in the
>> following link. There is an entire subsection on SMX support on x86s and
>> the changes to the various GETSEC instruction leaves that were made to
>> make it work there (see 3.15).
>>
>> https://urldefense.com/v3/__https://www.intel.com/content/www/us/en/developer/articles/technical/envisioning-future-simplified-architecture.html__;!!ACWV5N9M2RV99hQ!Lt-srkRLHstA9PPCB-NWogvHP-9mfh2bHjkml-lARY79BhYlWJjhrHb6RyCN_WdGstcABq1FdqPUKn5dCdw$
>
> Happend to bump into same PDF specification and exactly the seeked
> information is "3.15 SMX Changes". So just write this down to some
> patch that starts adding SMX things.
>
> Link: https://urldefense.com/v3/__https://cdrdv2.intel.com/v1/dl/getContent/776648__;!!ACWV5N9M2RV99hQ!Lt-srkRLHstA9PPCB-NWogvHP-9mfh2bHjkml-lARY79BhYlWJjhrHb6RyCN_WdGstcABq1FdqPUuZy8Sfk$
>
> So link and document, and other stuff above is not relevant from
> upstream context, only potential maintenance burden :-)
I am not 100% sure what you mean exactly here...
>
> For any architectures dig a similar fact:
>
> 1. Is not dead.
> 2. Will be there also in future.
>
> Make any architecture existentially relevant for and not too much
> coloring in the text that is easy to check.
>
> It is nearing 5k lines so you should be really good with measured
> facts too (not just launch) :-)
... but overall I get your meaning. We will spend time on this sort of
documentation for the v10 release.
Thanks for the feedback,
Ross
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-06 16:49 ` ross.philipson
@ 2024-06-20 0:18 ` Jarkko Sakkinen
2024-06-20 16:55 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-20 0:18 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Thu Jun 6, 2024 at 7:49 PM EEST, wrote:
> > For any architectures dig a similar fact:
> >
> > 1. Is not dead.
> > 2. Will be there also in future.
> >
> > Make any architecture existentially relevant for and not too much
> > coloring in the text that is easy to check.
> >
> > It is nearing 5k lines so you should be really good with measured
> > facts too (not just launch) :-)
>
> ... but overall I get your meaning. We will spend time on this sort of
> documentation for the v10 release.
Yeah, I mean we live in the universe of 3 letter acronyms so
it is better to summarize the existential part, especially
in a ~5 KSLOC patch set ;-)
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 04/19] x86: Secure Launch Resource Table header file
2024-06-20 0:18 ` Jarkko Sakkinen
@ 2024-06-20 16:55 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-20 16:55 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On 6/19/24 5:18 PM, Jarkko Sakkinen wrote:
> On Thu Jun 6, 2024 at 7:49 PM EEST, wrote:
>>> For any architectures dig a similar fact:
>>>
>>> 1. Is not dead.
>>> 2. Will be there also in future.
>>>
>>> Make any architecture existentially relevant for and not too much
>>> coloring in the text that is easy to check.
>>>
>>> It is nearing 5k lines so you should be really good with measured
>>> facts too (not just launch) :-)
>>
>> ... but overall I get your meaning. We will spend time on this sort of
>> documentation for the v10 release.
>
> Yeah, I mean we live in the universe of 3 letter acronyms so
> it is better to summarize the existential part, especially
> in a ~5 KSLOC patch set ;-)
Indeed, thanks.
Ross
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 05/19] x86: Secure Launch main header file
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (3 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 04/19] x86: Secure Launch Resource Table header file Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 18:24 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements Ross Philipson
` (13 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Introduce the main Secure Launch header file used in the early SL stub
and the early setup code.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
include/linux/slaunch.h | 542 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 542 insertions(+)
create mode 100644 include/linux/slaunch.h
diff --git a/include/linux/slaunch.h b/include/linux/slaunch.h
new file mode 100644
index 000000000000..90a7f22ddbdd
--- /dev/null
+++ b/include/linux/slaunch.h
@@ -0,0 +1,542 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Main Secure Launch header file.
+ *
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ */
+
+#ifndef _LINUX_SLAUNCH_H
+#define _LINUX_SLAUNCH_H
+
+/*
+ * Secure Launch Defined State Flags
+ */
+#define SL_FLAG_ACTIVE 0x00000001
+#define SL_FLAG_ARCH_SKINIT 0x00000002
+#define SL_FLAG_ARCH_TXT 0x00000004
+
+/*
+ * Secure Launch CPU Type
+ */
+#define SL_CPU_AMD 1
+#define SL_CPU_INTEL 2
+
+#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
+
+#define __SL32_CS 0x0008
+#define __SL32_DS 0x0010
+
+/*
+ * Intel Safer Mode Extensions (SMX)
+ *
+ * Intel SMX provides a programming interface to establish a Measured Launched
+ * Environment (MLE). The measurement and protection mechanisms supported by the
+ * capabilities of an Intel Trusted Execution Technology (TXT) platform. SMX is
+ * the processor’s programming interface in an Intel TXT platform.
+ *
+ * See Intel SDM Volume 2 - 6.1 "Safer Mode Extensions Reference"
+ */
+
+/*
+ * SMX GETSEC Leaf Functions
+ */
+#define SMX_X86_GETSEC_SEXIT 5
+#define SMX_X86_GETSEC_SMCTRL 7
+#define SMX_X86_GETSEC_WAKEUP 8
+
+/*
+ * Intel Trusted Execution Technology MMIO Registers Banks
+ */
+#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000
+#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000
+#define TXT_NR_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \
+ TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT)
+
+/*
+ * Intel Trusted Execution Technology (TXT) Registers
+ */
+#define TXT_CR_STS 0x0000
+#define TXT_CR_ESTS 0x0008
+#define TXT_CR_ERRORCODE 0x0030
+#define TXT_CR_CMD_RESET 0x0038
+#define TXT_CR_CMD_CLOSE_PRIVATE 0x0048
+#define TXT_CR_DIDVID 0x0110
+#define TXT_CR_VER_EMIF 0x0200
+#define TXT_CR_CMD_UNLOCK_MEM_CONFIG 0x0218
+#define TXT_CR_SINIT_BASE 0x0270
+#define TXT_CR_SINIT_SIZE 0x0278
+#define TXT_CR_MLE_JOIN 0x0290
+#define TXT_CR_HEAP_BASE 0x0300
+#define TXT_CR_HEAP_SIZE 0x0308
+#define TXT_CR_SCRATCHPAD 0x0378
+#define TXT_CR_CMD_OPEN_LOCALITY1 0x0380
+#define TXT_CR_CMD_CLOSE_LOCALITY1 0x0388
+#define TXT_CR_CMD_OPEN_LOCALITY2 0x0390
+#define TXT_CR_CMD_CLOSE_LOCALITY2 0x0398
+#define TXT_CR_CMD_SECRETS 0x08e0
+#define TXT_CR_CMD_NO_SECRETS 0x08e8
+#define TXT_CR_E2STS 0x08f0
+
+/* TXT default register value */
+#define TXT_REGVALUE_ONE 0x1ULL
+
+/* TXTCR_STS status bits */
+#define TXT_SENTER_DONE_STS BIT(0)
+#define TXT_SEXIT_DONE_STS BIT(1)
+
+/*
+ * SINIT/MLE Capabilities Field Bit Definitions
+ */
+#define TXT_SINIT_MLE_CAP_WAKE_GETSEC 0
+#define TXT_SINIT_MLE_CAP_WAKE_MONITOR 1
+
+/*
+ * OS/MLE Secure Launch Specific Definitions
+ */
+#define TXT_OS_MLE_STRUCT_VERSION 1
+#define TXT_OS_MLE_MAX_VARIABLE_MTRRS 32
+
+/*
+ * TXT Heap Table Enumeration
+ */
+#define TXT_BIOS_DATA_TABLE 1
+#define TXT_OS_MLE_DATA_TABLE 2
+#define TXT_OS_SINIT_DATA_TABLE 3
+#define TXT_SINIT_MLE_DATA_TABLE 4
+#define TXT_SINIT_TABLE_MAX TXT_SINIT_MLE_DATA_TABLE
+
+/*
+ * Secure Launch Defined Error Codes used in MLE-initiated TXT resets.
+ *
+ * TXT Specification
+ * Appendix I ACM Error Codes
+ */
+#define SL_ERROR_GENERIC 0xc0008001
+#define SL_ERROR_TPM_INIT 0xc0008002
+#define SL_ERROR_TPM_INVALID_LOG20 0xc0008003
+#define SL_ERROR_TPM_LOGGING_FAILED 0xc0008004
+#define SL_ERROR_REGION_STRADDLE_4GB 0xc0008005
+#define SL_ERROR_TPM_EXTEND 0xc0008006
+#define SL_ERROR_MTRR_INV_VCNT 0xc0008007
+#define SL_ERROR_MTRR_INV_DEF_TYPE 0xc0008008
+#define SL_ERROR_MTRR_INV_BASE 0xc0008009
+#define SL_ERROR_MTRR_INV_MASK 0xc000800a
+#define SL_ERROR_MSR_INV_MISC_EN 0xc000800b
+#define SL_ERROR_INV_AP_INTERRUPT 0xc000800c
+#define SL_ERROR_INTEGER_OVERFLOW 0xc000800d
+#define SL_ERROR_HEAP_WALK 0xc000800e
+#define SL_ERROR_HEAP_MAP 0xc000800f
+#define SL_ERROR_REGION_ABOVE_4GB 0xc0008010
+#define SL_ERROR_HEAP_INVALID_DMAR 0xc0008011
+#define SL_ERROR_HEAP_DMAR_SIZE 0xc0008012
+#define SL_ERROR_HEAP_DMAR_MAP 0xc0008013
+#define SL_ERROR_HI_PMR_BASE 0xc0008014
+#define SL_ERROR_HI_PMR_SIZE 0xc0008015
+#define SL_ERROR_LO_PMR_BASE 0xc0008016
+#define SL_ERROR_LO_PMR_MLE 0xc0008017
+#define SL_ERROR_INITRD_TOO_BIG 0xc0008018
+#define SL_ERROR_HEAP_ZERO_OFFSET 0xc0008019
+#define SL_ERROR_WAKE_BLOCK_TOO_SMALL 0xc000801a
+#define SL_ERROR_MLE_BUFFER_OVERLAP 0xc000801b
+#define SL_ERROR_BUFFER_BEYOND_PMR 0xc000801c
+#define SL_ERROR_OS_SINIT_BAD_VERSION 0xc000801d
+#define SL_ERROR_EVENTLOG_MAP 0xc000801e
+#define SL_ERROR_TPM_NUMBER_ALGS 0xc000801f
+#define SL_ERROR_TPM_UNKNOWN_DIGEST 0xc0008020
+#define SL_ERROR_TPM_INVALID_EVENT 0xc0008021
+#define SL_ERROR_INVALID_SLRT 0xc0008022
+#define SL_ERROR_SLRT_MISSING_ENTRY 0xc0008023
+#define SL_ERROR_SLRT_MAP 0xc0008024
+
+/*
+ * Secure Launch Defined Limits
+ */
+#define TXT_MAX_CPUS 512
+#define TXT_BOOT_STACK_SIZE 128
+
+/*
+ * Secure Launch event log entry type. The TXT specification defines the
+ * base event value as 0x400 for DRTM values.
+ */
+#define TXT_EVTYPE_BASE 0x400
+#define TXT_EVTYPE_SLAUNCH (TXT_EVTYPE_BASE + 0x102)
+#define TXT_EVTYPE_SLAUNCH_START (TXT_EVTYPE_BASE + 0x103)
+#define TXT_EVTYPE_SLAUNCH_END (TXT_EVTYPE_BASE + 0x104)
+
+/*
+ * Measured Launch PCRs
+ */
+#define SL_DEF_DLME_DETAIL_PCR17 17
+#define SL_DEF_DLME_AUTHORITY_PCR18 18
+#define SL_ALT_DLME_AUTHORITY_PCR19 19
+#define SL_ALT_DLME_DETAIL_PCR20 20
+
+/*
+ * MLE scratch area offsets
+ */
+#define SL_SCRATCH_AP_EBX 0
+#define SL_SCRATCH_AP_JMP_OFFSET 4
+#define SL_SCRATCH_AP_STACKS_OFFSET 8
+
+#ifndef __ASSEMBLY__
+
+#include <linux/io.h>
+#include <linux/tpm.h>
+#include <linux/tpm_eventlog.h>
+
+/*
+ * Secure Launch AP stack and monitor block
+ */
+struct sl_ap_stack_and_monitor {
+ u32 monitor;
+ u32 cache_pad[15];
+ u32 stack_pad[15];
+ u32 apicid;
+} __packed;
+
+/*
+ * Secure Launch AP wakeup information fetched in SMP boot code.
+ */
+struct sl_ap_wake_info {
+ u32 ap_wake_block;
+ u32 ap_wake_block_size;
+ u32 ap_jmp_offset;
+ u32 ap_stacks_offset;
+};
+
+/*
+ * TXT heap extended data elements.
+ */
+struct txt_heap_ext_data_element {
+ u32 type;
+ u32 size;
+ /* Data */
+} __packed;
+
+#define TXT_HEAP_EXTDATA_TYPE_END 0
+
+struct txt_heap_end_element {
+ u32 type;
+ u32 size;
+} __packed;
+
+#define TXT_HEAP_EXTDATA_TYPE_TPM_EVENT_LOG_PTR 5
+
+struct txt_heap_event_log_element {
+ u64 event_log_phys_addr;
+} __packed;
+
+#define TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1 8
+
+struct txt_heap_event_log_pointer2_1_element {
+ u64 phys_addr;
+ u32 allocated_event_container_size;
+ u32 first_record_offset;
+ u32 next_record_offset;
+} __packed;
+
+/*
+ * Secure Launch defined OS/MLE TXT Heap table
+ */
+struct txt_os_mle_data {
+ u32 version;
+ u32 boot_params_addr;
+ u64 slrt;
+ u64 txt_info;
+ u32 ap_wake_block;
+ u32 ap_wake_block_size;
+ u8 mle_scratch[64];
+} __packed;
+
+/*
+ * TXT specification defined BIOS data TXT Heap table
+ */
+struct txt_bios_data {
+ u32 version; /* Currently 5 for TPM 1.2 and 6 for TPM 2.0 */
+ u32 bios_sinit_size;
+ u64 reserved1;
+ u64 reserved2;
+ u32 num_logical_procs;
+ /* Versions >= 5 with updates in version 6 */
+ u32 sinit_flags;
+ u32 mle_flags;
+ /* Versions >= 4 */
+ /* Ext Data Elements */
+} __packed;
+
+/*
+ * TXT specification defined OS/SINIT TXT Heap table
+ */
+struct txt_os_sinit_data {
+ u32 version; /* Currently 6 for TPM 1.2 and 7 for TPM 2.0 */
+ u32 flags;
+ u64 mle_ptab;
+ u64 mle_size;
+ u64 mle_hdr_base;
+ u64 vtd_pmr_lo_base;
+ u64 vtd_pmr_lo_size;
+ u64 vtd_pmr_hi_base;
+ u64 vtd_pmr_hi_size;
+ u64 lcp_po_base;
+ u64 lcp_po_size;
+ u32 capabilities;
+ /* Version = 5 */
+ u64 efi_rsdt_ptr;
+ /* Versions >= 6 */
+ /* Ext Data Elements */
+} __packed;
+
+/*
+ * TXT specification defined SINIT/MLE TXT Heap table
+ */
+struct txt_sinit_mle_data {
+ u32 version; /* Current values are 6 through 9 */
+ /* Versions <= 8 */
+ u8 bios_acm_id[20];
+ u32 edx_senter_flags;
+ u64 mseg_valid;
+ u8 sinit_hash[20];
+ u8 mle_hash[20];
+ u8 stm_hash[20];
+ u8 lcp_policy_hash[20];
+ u32 lcp_policy_control;
+ /* Versions >= 7 */
+ u32 rlp_wakeup_addr;
+ u32 reserved;
+ u32 num_of_sinit_mdrs;
+ u32 sinit_mdrs_table_offset;
+ u32 sinit_vtd_dmar_table_size;
+ u32 sinit_vtd_dmar_table_offset;
+ /* Versions >= 8 */
+ u32 processor_scrtm_status;
+ /* Versions >= 9 */
+ /* Ext Data Elements */
+} __packed;
+
+/*
+ * TXT data reporting structure for memory types
+ */
+struct txt_sinit_memory_descriptor_record {
+ u64 address;
+ u64 length;
+ u8 type;
+ u8 reserved[7];
+} __packed;
+
+/*
+ * TXT data structure used by a responsive local processor (RLP) to start
+ * execution in response to a GETSEC[WAKEUP].
+ */
+struct smx_rlp_mle_join {
+ u32 rlp_gdt_limit;
+ u32 rlp_gdt_base;
+ u32 rlp_seg_sel; /* cs (ds, es, ss are seg_sel+8) */
+ u32 rlp_entry_point; /* phys addr */
+} __packed;
+
+/*
+ * TPM event log structures defined in both the TXT specification and
+ * the TCG documentation.
+ */
+#define TPM12_EVTLOG_SIGNATURE "TXT Event Container"
+
+struct tpm12_event_log_header {
+ char signature[20];
+ char reserved[12];
+ u8 container_ver_major;
+ u8 container_ver_minor;
+ u8 pcr_event_ver_major;
+ u8 pcr_event_ver_minor;
+ u32 container_size;
+ u32 pcr_events_offset;
+ u32 next_event_offset;
+ /* PCREvents[] */
+} __packed;
+
+/*
+ * Functions to extract data from the Intel TXT Heap Memory. The layout
+ * of the heap is as follows:
+ * +----------------------------+
+ * | Size Bios Data table (u64) |
+ * +----------------------------+
+ * | Bios Data table |
+ * +----------------------------+
+ * | Size OS MLE table (u64) |
+ * +----------------------------+
+ * | OS MLE table |
+ * +--------------------------- +
+ * | Size OS SINIT table (u64) |
+ * +----------------------------+
+ * | OS SINIT table |
+ * +----------------------------+
+ * | Size SINIT MLE table (u64) |
+ * +----------------------------+
+ * | SINIT MLE table |
+ * +----------------------------+
+ *
+ * NOTE: the table size fields include the 8 byte size field itself.
+ */
+static inline u64 txt_bios_data_size(void *heap)
+{
+ return *((u64 *)heap);
+}
+
+static inline void *txt_bios_data_start(void *heap)
+{
+ return heap + sizeof(u64);
+}
+
+static inline u64 txt_os_mle_data_size(void *heap)
+{
+ return *((u64 *)(heap + txt_bios_data_size(heap)));
+}
+
+static inline void *txt_os_mle_data_start(void *heap)
+{
+ return heap + txt_bios_data_size(heap) + sizeof(u64);
+}
+
+static inline u64 txt_os_sinit_data_size(void *heap)
+{
+ return *((u64 *)(heap + txt_bios_data_size(heap) +
+ txt_os_mle_data_size(heap)));
+}
+
+static inline void *txt_os_sinit_data_start(void *heap)
+{
+ return heap + txt_bios_data_size(heap) +
+ txt_os_mle_data_size(heap) + sizeof(u64);
+}
+
+static inline u64 txt_sinit_mle_data_size(void *heap)
+{
+ return *((u64 *)(heap + txt_bios_data_size(heap) +
+ txt_os_mle_data_size(heap) +
+ txt_os_sinit_data_size(heap)));
+}
+
+static inline void *txt_sinit_mle_data_start(void *heap)
+{
+ return heap + txt_bios_data_size(heap) +
+ txt_os_mle_data_size(heap) +
+ txt_os_sinit_data_size(heap) + sizeof(u64);
+}
+
+/*
+ * TPM event logging functions.
+ */
+static inline struct txt_heap_event_log_pointer2_1_element*
+tpm20_find_log2_1_element(struct txt_os_sinit_data *os_sinit_data)
+{
+ struct txt_heap_ext_data_element *ext_elem;
+
+ /* The extended element array as at the end of this table */
+ ext_elem = (struct txt_heap_ext_data_element *)
+ ((u8 *)os_sinit_data + sizeof(struct txt_os_sinit_data));
+
+ while (ext_elem->type != TXT_HEAP_EXTDATA_TYPE_END) {
+ if (ext_elem->type ==
+ TXT_HEAP_EXTDATA_TYPE_EVENT_LOG_POINTER2_1) {
+ return (struct txt_heap_event_log_pointer2_1_element *)
+ ((u8 *)ext_elem +
+ sizeof(struct txt_heap_ext_data_element));
+ }
+ ext_elem =
+ (struct txt_heap_ext_data_element *)
+ ((u8 *)ext_elem + ext_elem->size);
+ }
+
+ return NULL;
+}
+
+static inline int tpm12_log_event(void *evtlog_base, u32 evtlog_size,
+ u32 event_size, void *event)
+{
+ struct tpm12_event_log_header *evtlog =
+ (struct tpm12_event_log_header *)evtlog_base;
+
+ if (memcmp(evtlog->signature, TPM12_EVTLOG_SIGNATURE,
+ sizeof(TPM12_EVTLOG_SIGNATURE)))
+ return -EINVAL;
+
+ if (evtlog->container_size > evtlog_size)
+ return -EINVAL;
+
+ if (evtlog->next_event_offset + event_size > evtlog->container_size)
+ return -E2BIG;
+
+ memcpy(evtlog_base + evtlog->next_event_offset, event, event_size);
+ evtlog->next_event_offset += event_size;
+
+ return 0;
+}
+
+static inline int tpm20_log_event(struct txt_heap_event_log_pointer2_1_element *elem,
+ void *evtlog_base, u32 evtlog_size,
+ u32 event_size, void *event)
+{
+ struct tcg_pcr_event *header =
+ (struct tcg_pcr_event *)evtlog_base;
+
+ /* Has to be at least big enough for the signature */
+ if (header->event_size < sizeof(TCG_SPECID_SIG))
+ return -EINVAL;
+
+ if (memcmp((u8 *)header + sizeof(struct tcg_pcr_event),
+ TCG_SPECID_SIG, sizeof(TCG_SPECID_SIG)))
+ return -EINVAL;
+
+ if (elem->allocated_event_container_size > evtlog_size)
+ return -EINVAL;
+
+ if (elem->next_record_offset + event_size >
+ elem->allocated_event_container_size)
+ return -E2BIG;
+
+ memcpy(evtlog_base + elem->next_record_offset, event, event_size);
+ elem->next_record_offset += event_size;
+
+ return 0;
+}
+
+/*
+ * External functions avalailable in mainline kernel.
+ */
+void slaunch_setup_txt(void);
+void slaunch_fixup_jump_vector(void);
+u32 slaunch_get_flags(void);
+struct sl_ap_wake_info *slaunch_get_ap_wake_info(void);
+struct acpi_table_header *slaunch_get_dmar_table(struct acpi_table_header *dmar);
+void __noreturn slaunch_txt_reset(void __iomem *txt,
+ const char *msg, u64 error);
+extern void slaunch_finalize(int do_sexit);
+
+#endif /* !__ASSEMBLY */
+
+#else
+
+static inline void slaunch_setup_txt(void)
+{
+}
+
+static inline void slaunch_fixup_jump_vector(void)
+{
+}
+
+static inline u32 slaunch_get_flags(void)
+{
+ return 0;
+}
+
+static inline struct acpi_table_header *slaunch_get_dmar_table(struct acpi_table_header *dmar)
+{
+ return dmar;
+}
+
+static inline void slaunch_finalize(int do_sexit)
+{
+}
+
+#endif /* !IS_ENABLED(CONFIG_SECURE_LAUNCH) */
+
+#endif /* _LINUX_SLAUNCH_H */
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 05/19] x86: Secure Launch main header file
2024-05-31 1:03 ` [PATCH v9 05/19] x86: Secure Launch main " Ross Philipson
@ 2024-06-04 18:24 ` Jarkko Sakkinen
2024-06-04 20:52 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 18:24 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> Introduce the main Secure Launch header file used in the early SL stub
> and the early setup code.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Right and anything AMD specific should also have legit references. I
actually always compare to the spec when I review, so not just
nitpicking really.
I'm actually bit confused, is this usable both Intel and AMD in the
current state? Might be just that have not had time follow this for some
time.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 05/19] x86: Secure Launch main header file
2024-06-04 18:24 ` Jarkko Sakkinen
@ 2024-06-04 20:52 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 20:52 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 11:24 AM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> Introduce the main Secure Launch header file used in the early SL stub
>> and the early setup code.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> Right and anything AMD specific should also have legit references. I
> actually always compare to the spec when I review, so not just
> nitpicking really.
>
> I'm actually bit confused, is this usable both Intel and AMD in the
> current state? Might be just that have not had time follow this for some
> time.
This header file mostly has TXT/Intel specific definitions in it right
now but that is just because TXT is the first target architecture. I am
working on the AMD side of things as we speak and yes, AMD specific
definitions will go in here and later ARM specific definitions too.
If you would like to see say a comment block with links to relevant
specifications in this header file, that can be done and they will be
added as new support is added.
Thanks
Ross
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (4 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 05/19] x86: Secure Launch main " Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 2:16 ` Eric Biggers
2024-06-04 18:52 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 07/19] x86: Add early SHA-256 " Ross Philipson
` (12 subsequent siblings)
18 siblings, 2 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
For better or worse, Secure Launch needs SHA-1 and SHA-256. The
choice of hashes used lie with the platform firmware, not with
software, and is often outside of the users control.
Even if we'd prefer to use SHA-256-only, if firmware elected to start us
with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
to safely use SHA-256 for everything else.
The SHA-1 code here has its origins in the code from the main kernel:
commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
A modified version of this code was introduced to the lib/crypto/sha1.c
to bring it in line with the SHA-256 code and allow it to be pulled into the
setup kernel in the same manner as SHA-256 is.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/boot/compressed/Makefile | 2 +
arch/x86/boot/compressed/early_sha1.c | 12 ++++
include/crypto/sha1.h | 1 +
lib/crypto/sha1.c | 81 +++++++++++++++++++++++++++
4 files changed, 96 insertions(+)
create mode 100644 arch/x86/boot/compressed/early_sha1.c
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index e9522c6893be..3307ebef4e1b 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
+vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o
+
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c
new file mode 100644
index 000000000000..8a9b904a73ab
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha1.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Apertus Solutions, LLC.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/string.h>
+#include <asm/boot.h>
+#include <asm/unaligned.h>
+
+#include "../../../../lib/crypto/sha1.c"
diff --git a/include/crypto/sha1.h b/include/crypto/sha1.h
index 044ecea60ac8..d715dd5332e1 100644
--- a/include/crypto/sha1.h
+++ b/include/crypto/sha1.h
@@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
#define SHA1_WORKSPACE_WORDS 16
void sha1_init(__u32 *buf);
void sha1_transform(__u32 *digest, const char *data, __u32 *W);
+void sha1(const u8 *data, unsigned int len, u8 *out);
#endif /* _CRYPTO_SHA1_H */
diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
index 1aebe7be9401..10152125b338 100644
--- a/lib/crypto/sha1.c
+++ b/lib/crypto/sha1.c
@@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
}
EXPORT_SYMBOL(sha1_init);
+static void __sha1_transform(u32 *digest, const char *data)
+{
+ u32 ws[SHA1_WORKSPACE_WORDS];
+
+ sha1_transform(digest, data, ws);
+
+ memzero_explicit(ws, sizeof(ws));
+}
+
+static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
+{
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+
+ sctx->count += len;
+
+ if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
+ int blocks;
+
+ if (partial) {
+ int p = SHA1_BLOCK_SIZE - partial;
+
+ memcpy(sctx->buffer + partial, data, p);
+ data += p;
+ len -= p;
+
+ __sha1_transform(sctx->state, sctx->buffer);
+ }
+
+ blocks = len / SHA1_BLOCK_SIZE;
+ len %= SHA1_BLOCK_SIZE;
+
+ if (blocks) {
+ while (blocks--) {
+ __sha1_transform(sctx->state, data);
+ data += SHA1_BLOCK_SIZE;
+ }
+ }
+ partial = 0;
+ }
+
+ if (len)
+ memcpy(sctx->buffer + partial, data, len);
+}
+
+static void sha1_final(struct sha1_state *sctx, u8 *out)
+{
+ const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
+ unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
+ __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
+ __be32 *digest = (__be32 *)out;
+ int i;
+
+ sctx->buffer[partial++] = 0x80;
+ if (partial > bit_offset) {
+ memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
+ partial = 0;
+
+ __sha1_transform(sctx->state, sctx->buffer);
+ }
+
+ memset(sctx->buffer + partial, 0x0, bit_offset - partial);
+ *bits = cpu_to_be64(sctx->count << 3);
+ __sha1_transform(sctx->state, sctx->buffer);
+
+ for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
+ put_unaligned_be32(sctx->state[i], digest++);
+
+ *sctx = (struct sha1_state){};
+}
+
+void sha1(const u8 *data, unsigned int len, u8 *out)
+{
+ struct sha1_state sctx = {0};
+
+ sha1_init(sctx.state);
+ sctx.count = 0;
+ sha1_update(&sctx, data, len);
+ sha1_final(&sctx, out);
+}
+EXPORT_SYMBOL(sha1);
+
MODULE_LICENSE("GPL");
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 1:03 ` [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements Ross Philipson
@ 2024-05-31 2:16 ` Eric Biggers
2024-05-31 13:54 ` Eric W. Biederman
` (2 more replies)
2024-06-04 18:52 ` Jarkko Sakkinen
1 sibling, 3 replies; 113+ messages in thread
From: Eric Biggers @ 2024-05-31 2:16 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
> choice of hashes used lie with the platform firmware, not with
> software, and is often outside of the users control.
>
> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> to safely use SHA-256 for everything else.
>
> The SHA-1 code here has its origins in the code from the main kernel:
>
> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>
> A modified version of this code was introduced to the lib/crypto/sha1.c
> to bring it in line with the SHA-256 code and allow it to be pulled into the
> setup kernel in the same manner as SHA-256 is.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Thanks. This explanation doesn't seem to have made it into the actual code or
documentation. Can you please get it into a more permanent location?
Also, can you point to where the "deliberately cap the SHA-1 PCRs" thing happens
in the code?
That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
that the case? Sure, maybe there are situations where you *have* to use SHA-1,
but why would you not at least *prefer* SHA-256?
> /*
> * An implementation of SHA-1's compression function. Don't use in new code!
> * You shouldn't be using SHA-1, and even if you *have* to use SHA-1, this isn't
> * the correct way to hash something with SHA-1 (use crypto_shash instead).
> */
> #define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / 4)
> #define SHA1_WORKSPACE_WORDS 16
> void sha1_init(__u32 *buf);
> void sha1_transform(__u32 *digest, const char *data, __u32 *W);
>+void sha1(const u8 *data, unsigned int len, u8 *out);
Also, the comment above needs to be updated.
- Eric
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 2:16 ` Eric Biggers
@ 2024-05-31 13:54 ` Eric W. Biederman
2024-08-15 17:38 ` Daniel P. Smith
2024-05-31 16:18 ` ross.philipson
2024-08-27 18:14 ` Eric Biggers
2 siblings, 1 reply; 113+ messages in thread
From: Eric W. Biederman @ 2024-05-31 13:54 UTC (permalink / raw)
To: Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp,
hpa, dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe,
jarkko, jgg, luto, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
Eric Biggers <ebiggers@kernel.org> writes:
> On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
>> choice of hashes used lie with the platform firmware, not with
>> software, and is often outside of the users control.
>>
>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>> to safely use SHA-256 for everything else.
>>
>> The SHA-1 code here has its origins in the code from the main kernel:
>>
>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>>
>> A modified version of this code was introduced to the lib/crypto/sha1.c
>> to bring it in line with the SHA-256 code and allow it to be pulled into the
>> setup kernel in the same manner as SHA-256 is.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> Thanks. This explanation doesn't seem to have made it into the actual code or
> documentation. Can you please get it into a more permanent location?
>
> Also, can you point to where the "deliberately cap the SHA-1 PCRs" thing happens
> in the code?
>
> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
> but why would you not at least *prefer* SHA-256?
Yes. Please prefer to use SHA-256.
Have you considered implementing I think it is SHA1-DC (as git has) that
is compatible with SHA1 but blocks the known class of attacks where
sha1 is actively broken at this point?
No offense to your Trenchboot project but my gut says that anything new
relying on SHA-1 is probably a bad joke at this point.
Firmware can most definitely be upgraded and if the goal is a more
secure boot the usual backwards compatibility concerns for supporting
old firmware really don't apply.
Perhaps hide all of the SHA-1 stuff behind CONFIG_TRENCHBOOT_PROTOTYPE
or something like that to make it clear that SHA-1 is not appropriate
for any kind of production deployment and is only good for prototyping
your implementation until properly implemented firmware comes along.
Eric
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 13:54 ` Eric W. Biederman
@ 2024-08-15 17:38 ` Daniel P. Smith
2024-08-15 19:10 ` Thomas Gleixner
0 siblings, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-08-15 17:38 UTC (permalink / raw)
To: Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 5/31/24 09:54, Eric W. Biederman wrote:
> Eric Biggers <ebiggers@kernel.org> writes:
>
>> On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
>>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>>
>>> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
>>> choice of hashes used lie with the platform firmware, not with
>>> software, and is often outside of the users control.
>>>
>>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>>> to safely use SHA-256 for everything else.
>>>
>>> The SHA-1 code here has its origins in the code from the main kernel:
>>>
>>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>>>
>>> A modified version of this code was introduced to the lib/crypto/sha1.c
>>> to bring it in line with the SHA-256 code and allow it to be pulled into the
>>> setup kernel in the same manner as SHA-256 is.
>>>
>>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>
>> Thanks. This explanation doesn't seem to have made it into the actual code or
>> documentation. Can you please get it into a more permanent location?
>>
>> Also, can you point to where the "deliberately cap the SHA-1 PCRs" thing happens
>> in the code?
>>
>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
>> but why would you not at least *prefer* SHA-256?
>
> Yes. Please prefer to use SHA-256.
>
> Have you considered implementing I think it is SHA1-DC (as git has) that
> is compatible with SHA1 but blocks the known class of attacks where
> sha1 is actively broken at this point?
We are using the kernel's implementation, addressing what the kernel
provides is beyond our efforts. Perhaps someone who is interested in
improving the kernel's SHA1 could submit a patch implementing/replacing
it with SHA1-DC, as I am sure the maintainers would welcome the help.
v/r,
dps
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-15 17:38 ` Daniel P. Smith
@ 2024-08-15 19:10 ` Thomas Gleixner
2024-08-16 10:42 ` Jarkko Sakkinen
` (3 more replies)
0 siblings, 4 replies; 113+ messages in thread
From: Thomas Gleixner @ 2024-08-15 19:10 UTC (permalink / raw)
To: Daniel P. Smith, Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
> On 5/31/24 09:54, Eric W. Biederman wrote:
>> Eric Biggers <ebiggers@kernel.org> writes:
>>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
>>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
>>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
>>> but why would you not at least *prefer* SHA-256?
>>
>> Yes. Please prefer to use SHA-256.
>>
>> Have you considered implementing I think it is SHA1-DC (as git has) that
>> is compatible with SHA1 but blocks the known class of attacks where
>> sha1 is actively broken at this point?
>
> We are using the kernel's implementation, addressing what the kernel
> provides is beyond our efforts. Perhaps someone who is interested in
> improving the kernel's SHA1 could submit a patch implementing/replacing
> it with SHA1-DC, as I am sure the maintainers would welcome the help.
Well, someone who is interested to get his "secure" code merged should
have a vested interested to have a non-broken SHA1 implementation if
there is a sensible requirement to use SHA1 in that new "secure" code,
no?
Just for the record. The related maintainers can rightfully decide to
reject known broken "secure" code on a purely technical argument.
Thanks,
tglx
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-15 19:10 ` Thomas Gleixner
@ 2024-08-16 10:42 ` Jarkko Sakkinen
2024-08-16 11:01 ` Andrew Cooper
` (2 subsequent siblings)
3 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-08-16 10:42 UTC (permalink / raw)
To: Thomas Gleixner, Daniel P. Smith, Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jgg, luto,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Thu Aug 15, 2024 at 10:10 PM EEST, Thomas Gleixner wrote:
> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
> > On 5/31/24 09:54, Eric W. Biederman wrote:
> >> Eric Biggers <ebiggers@kernel.org> writes:
> >>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
> >>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
> >>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
> >>> but why would you not at least *prefer* SHA-256?
> >>
> >> Yes. Please prefer to use SHA-256.
> >>
> >> Have you considered implementing I think it is SHA1-DC (as git has) that
> >> is compatible with SHA1 but blocks the known class of attacks where
> >> sha1 is actively broken at this point?
> >
> > We are using the kernel's implementation, addressing what the kernel
> > provides is beyond our efforts. Perhaps someone who is interested in
> > improving the kernel's SHA1 could submit a patch implementing/replacing
> > it with SHA1-DC, as I am sure the maintainers would welcome the help.
Git also has a bit more wide than secure launch, and the timeline is
also completely different. Git maintains legacy, while has also
introduced SHA-256 support in 2018. This as a new feature in the kernel
stack.
The purpose of SHA1-DC has obviously been to extend the lifespan, not
fix SHA-1.
Linux will be better of not adding anything new related to SHA-1 or
TPM 1.2. They still have a maintenance cost and I think that time
would be better spent of for almost anything else (starting from
taking your trashes out or boiling coffee) ;-)
>
> Well, someone who is interested to get his "secure" code merged should
> have a vested interested to have a non-broken SHA1 implementation if
> there is a sensible requirement to use SHA1 in that new "secure" code,
> no?
>
> Just for the record. The related maintainers can rightfully decide to
> reject known broken "secure" code on a purely technical argument.
>
> Thanks,
>
> tglx
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-15 19:10 ` Thomas Gleixner
2024-08-16 10:42 ` Jarkko Sakkinen
@ 2024-08-16 11:01 ` Andrew Cooper
2024-08-16 11:22 ` Jarkko Sakkinen
2024-08-22 18:29 ` Daniel P. Smith
2024-08-29 3:17 ` Andy Lutomirski
3 siblings, 1 reply; 113+ messages in thread
From: Andrew Cooper @ 2024-08-16 11:01 UTC (permalink / raw)
To: Thomas Gleixner, Daniel P. Smith, Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, dwmw2, baolu.lu,
kanth.ghatraju, trenchboot-devel
On 15/08/2024 8:10 pm, Thomas Gleixner wrote:
> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
>> On 5/31/24 09:54, Eric W. Biederman wrote:
>>> Eric Biggers <ebiggers@kernel.org> writes:
>>>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
>>>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
>>>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
>>>> but why would you not at least *prefer* SHA-256?
>>> Yes. Please prefer to use SHA-256.
>>>
>>> Have you considered implementing I think it is SHA1-DC (as git has) that
>>> is compatible with SHA1 but blocks the known class of attacks where
>>> sha1 is actively broken at this point?
>> We are using the kernel's implementation, addressing what the kernel
>> provides is beyond our efforts. Perhaps someone who is interested in
>> improving the kernel's SHA1 could submit a patch implementing/replacing
>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
> Well, someone who is interested to get his "secure" code merged should
> have a vested interested to have a non-broken SHA1 implementation if
> there is a sensible requirement to use SHA1 in that new "secure" code,
> no?
No.
The use of SHA-1 is necessary even on modern systems to avoid a
vulnerability.
It is the platform, not Linux, which decides which TPM PCR banks are active.
Linux *must* have an algorithm for every active bank (which is the
platform's choice), even if the single thing it intends to do is cap the
bank and use better ones.
Capping a bank requires updating the TPM Log without corrupting it,
which requires a hash calculation of the correct type for the bank.
~Andrew
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-16 11:01 ` Andrew Cooper
@ 2024-08-16 11:22 ` Jarkko Sakkinen
2024-08-16 18:41 ` Matthew Garrett
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-08-16 11:22 UTC (permalink / raw)
To: Andrew Cooper, Thomas Gleixner, Daniel P. Smith,
Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jgg, luto,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
trenchboot-devel
On Fri Aug 16, 2024 at 2:01 PM EEST, Andrew Cooper wrote:
> On 15/08/2024 8:10 pm, Thomas Gleixner wrote:
> > On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
> >> On 5/31/24 09:54, Eric W. Biederman wrote:
> >>> Eric Biggers <ebiggers@kernel.org> writes:
> >>>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
> >>>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
> >>>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
> >>>> but why would you not at least *prefer* SHA-256?
> >>> Yes. Please prefer to use SHA-256.
> >>>
> >>> Have you considered implementing I think it is SHA1-DC (as git has) that
> >>> is compatible with SHA1 but blocks the known class of attacks where
> >>> sha1 is actively broken at this point?
> >> We are using the kernel's implementation, addressing what the kernel
> >> provides is beyond our efforts. Perhaps someone who is interested in
> >> improving the kernel's SHA1 could submit a patch implementing/replacing
> >> it with SHA1-DC, as I am sure the maintainers would welcome the help.
> > Well, someone who is interested to get his "secure" code merged should
> > have a vested interested to have a non-broken SHA1 implementation if
> > there is a sensible requirement to use SHA1 in that new "secure" code,
> > no?
>
> No.
>
> The use of SHA-1 is necessary even on modern systems to avoid a
> vulnerability.
>
> It is the platform, not Linux, which decides which TPM PCR banks are active.
>
> Linux *must* have an algorithm for every active bank (which is the
> platform's choice), even if the single thing it intends to do is cap the
> bank and use better ones.
For (any) non-legacy features we can choose, which choices we choose to
support, and which we do not. This is not an oppositive view just saying
how it is, and platforms set of choices is not a selling argument.
>
> Capping a bank requires updating the TPM Log without corrupting it,
> which requires a hash calculation of the correct type for the bank.
>
> ~Andrew
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-16 11:22 ` Jarkko Sakkinen
@ 2024-08-16 18:41 ` Matthew Garrett
2024-08-19 18:05 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: Matthew Garrett @ 2024-08-16 18:41 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andrew Cooper, Thomas Gleixner, Daniel P. Smith,
Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, trenchboot-devel
On Fri, Aug 16, 2024 at 02:22:04PM +0300, Jarkko Sakkinen wrote:
> For (any) non-legacy features we can choose, which choices we choose to
> support, and which we do not. This is not an oppositive view just saying
> how it is, and platforms set of choices is not a selling argument.
NIST still permits the use of SHA-1 until 2030, and the most significant
demonstrated weaknesses in it don't seem applicable to the use case
here. We certainly shouldn't encourage any new uses of it, and anyone
who's able to use SHA-2 should be doing that instead, but it feels like
people are arguing about not supporting hardware that exists in the real
world for vibes reasons rather than it being a realistically attackable
weakness (and if we really *are* that concerned about SHA-1, why are we
still supporting TPM 1.2 at all?)
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-16 18:41 ` Matthew Garrett
@ 2024-08-19 18:05 ` Jarkko Sakkinen
2024-08-19 18:24 ` Matthew Garrett
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-08-19 18:05 UTC (permalink / raw)
To: Matthew Garrett
Cc: Andrew Cooper, Thomas Gleixner, Daniel P. Smith,
Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, trenchboot-devel
On Fri Aug 16, 2024 at 9:41 PM EEST, Matthew Garrett wrote:
> On Fri, Aug 16, 2024 at 02:22:04PM +0300, Jarkko Sakkinen wrote:
>
> > For (any) non-legacy features we can choose, which choices we choose to
> > support, and which we do not. This is not an oppositive view just saying
> > how it is, and platforms set of choices is not a selling argument.
>
> NIST still permits the use of SHA-1 until 2030, and the most significant
> demonstrated weaknesses in it don't seem applicable to the use case
> here. We certainly shouldn't encourage any new uses of it, and anyone
> who's able to use SHA-2 should be doing that instead, but it feels like
> people are arguing about not supporting hardware that exists in the real
> world for vibes reasons rather than it being a realistically attackable
> weakness (and if we really *are* that concerned about SHA-1, why are we
> still supporting TPM 1.2 at all?)
We are life-supporting TPM 1.2 as long as necessary but neither the
support is extended nor new features will gain TPM 1.2 support. So
that is at least my policy for that feature.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-19 18:05 ` Jarkko Sakkinen
@ 2024-08-19 18:24 ` Matthew Garrett
2024-08-20 15:26 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: Matthew Garrett @ 2024-08-19 18:24 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Andrew Cooper, Thomas Gleixner, Daniel P. Smith,
Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, trenchboot-devel
On Mon, Aug 19, 2024 at 09:05:47PM +0300, Jarkko Sakkinen wrote:
> On Fri Aug 16, 2024 at 9:41 PM EEST, Matthew Garrett wrote:
> > On Fri, Aug 16, 2024 at 02:22:04PM +0300, Jarkko Sakkinen wrote:
> >
> > > For (any) non-legacy features we can choose, which choices we choose to
> > > support, and which we do not. This is not an oppositive view just saying
> > > how it is, and platforms set of choices is not a selling argument.
> >
> > NIST still permits the use of SHA-1 until 2030, and the most significant
> > demonstrated weaknesses in it don't seem applicable to the use case
> > here. We certainly shouldn't encourage any new uses of it, and anyone
> > who's able to use SHA-2 should be doing that instead, but it feels like
> > people are arguing about not supporting hardware that exists in the real
> > world for vibes reasons rather than it being a realistically attackable
> > weakness (and if we really *are* that concerned about SHA-1, why are we
> > still supporting TPM 1.2 at all?)
>
> We are life-supporting TPM 1.2 as long as necessary but neither the
> support is extended nor new features will gain TPM 1.2 support. So
> that is at least my policy for that feature.
But the fact that we support it and provide no warning labels is a
pretty clear indication that we're not actively trying to prevent people
from using SHA-1 in the general case. Why is this a different case?
Failing to support it actually opens an entire separate set of footgun
opportunities in terms of the SHA-1 banks now being out of sync with the
SHA-2 ones, so either way we're leaving people open to making poor
choices.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-19 18:24 ` Matthew Garrett
@ 2024-08-20 15:26 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-08-20 15:26 UTC (permalink / raw)
To: Matthew Garrett
Cc: Andrew Cooper, Thomas Gleixner, Daniel P. Smith,
Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, trenchboot-devel
On Mon Aug 19, 2024 at 9:24 PM EEST, Matthew Garrett wrote:
> On Mon, Aug 19, 2024 at 09:05:47PM +0300, Jarkko Sakkinen wrote:
> > On Fri Aug 16, 2024 at 9:41 PM EEST, Matthew Garrett wrote:
> > > On Fri, Aug 16, 2024 at 02:22:04PM +0300, Jarkko Sakkinen wrote:
> > >
> > > > For (any) non-legacy features we can choose, which choices we choose to
> > > > support, and which we do not. This is not an oppositive view just saying
> > > > how it is, and platforms set of choices is not a selling argument.
> > >
> > > NIST still permits the use of SHA-1 until 2030, and the most significant
> > > demonstrated weaknesses in it don't seem applicable to the use case
> > > here. We certainly shouldn't encourage any new uses of it, and anyone
> > > who's able to use SHA-2 should be doing that instead, but it feels like
> > > people are arguing about not supporting hardware that exists in the real
> > > world for vibes reasons rather than it being a realistically attackable
> > > weakness (and if we really *are* that concerned about SHA-1, why are we
> > > still supporting TPM 1.2 at all?)
> >
> > We are life-supporting TPM 1.2 as long as necessary but neither the
> > support is extended nor new features will gain TPM 1.2 support. So
> > that is at least my policy for that feature.
>
> But the fact that we support it and provide no warning labels is a
> pretty clear indication that we're not actively trying to prevent people
> from using SHA-1 in the general case. Why is this a different case?
> Failing to support it actually opens an entire separate set of footgun
> opportunities in terms of the SHA-1 banks now being out of sync with the
> SHA-2 ones, so either way we're leaving people open to making poor
> choices.
This is a fair and enclosing argument. I get where you are coming from
now. Please as material for the commit message.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-15 19:10 ` Thomas Gleixner
2024-08-16 10:42 ` Jarkko Sakkinen
2024-08-16 11:01 ` Andrew Cooper
@ 2024-08-22 18:29 ` Daniel P. Smith
2024-08-29 3:17 ` Andy Lutomirski
3 siblings, 0 replies; 113+ messages in thread
From: Daniel P. Smith @ 2024-08-22 18:29 UTC (permalink / raw)
To: Thomas Gleixner, Eric W. Biederman, Eric Biggers
Cc: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 8/15/24 15:10, Thomas Gleixner wrote:
> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
>> On 5/31/24 09:54, Eric W. Biederman wrote:
>>> Eric Biggers <ebiggers@kernel.org> writes:
>>>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
>>>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
>>>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
>>>> but why would you not at least *prefer* SHA-256?
>>>
>>> Yes. Please prefer to use SHA-256.
>>>
>>> Have you considered implementing I think it is SHA1-DC (as git has) that
>>> is compatible with SHA1 but blocks the known class of attacks where
>>> sha1 is actively broken at this point?
>>
>> We are using the kernel's implementation, addressing what the kernel
>> provides is beyond our efforts. Perhaps someone who is interested in
>> improving the kernel's SHA1 could submit a patch implementing/replacing
>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
>
> Well, someone who is interested to get his "secure" code merged should
> have a vested interested to have a non-broken SHA1 implementation if
> there is a sensible requirement to use SHA1 in that new "secure" code,
> no?
>
> Just for the record. The related maintainers can rightfully decide to
> reject known broken "secure" code on a purely technical argument.
>
> Thanks,
>
> tglx
>
There is one simple question, does allowing the Secure Launch code to
record SHA1 measurements make the system insecure, and the answer is
absolutely not.
The role of the Secure Launch code base in the context of the larger
launch process is to function as observer. Within this role, its only
responsibility is continuing the trust chain(s) that were started by the
CPU/Hardware. It does so by measuring the components and configuration
it is responsible for loading and applying, i.e. in TCG parlance, it is
continuing the construction of the transitive trust for the system. In
this aspect, the only degradation of security that can affect the
kernel's role is whether all the necessary entities are safely measured
and not what algorithms are used.
If the system integrator, whether that be the OEM, your employer, the
distro maintainer, the system administrator, or the end user, configures
the DL preamble to only use SHA1 or used older hardware that has a
TPM1.2, then they are accepting the risk it creates in their solution.
In fact, a greater threat to the security of the launch is the
misconfiguration of the IOMMU, which risks the kernel's ability to
safely make measurements, as compared to the use of SHA1. Yet it was
insisted in past reviews that we allow the user to specify an incorrect
IOMMU policy.
In the end, the "security" of an RTM solution is how and what
measurements are used to assess the health of a system. Thus bringing it
back to the opening question, if SHA1 measurements are made but not
used, i.e. the attestation enforcement only uses SHA2, then it has zero
impact on the security of the system.
Another fact to consider is that the current Intel's TXT MLE
specification dictates SHA1 as a valid configuration. Secure Launch's
use of SHA1 is therefore to comply with Intel's specification for TXT.
And like the IOMMU situation, having the option available allows the
user to determine how they ultimately want to integrate Secure Launch
into their integrity management. And because Secure Launch will only
attempt SHA1 if it was in the TXT configuration, when either Intel
removes SHA1 from the MLE specification or firmware manufactures begin
disabling the SHA1 banks, this will obviously mean that Secure Launch
will not produce SHA1 measurements.
On a side note, with my remote attestation hat on, the SHA1 measurements
can in fact be extremely useful. If an attestation was made containing
both SHA1 and SHA2 chains, and the SHA1 of an event was correct but the
SHA2 was not, either a natural collision happened or someone maliciously
caused a collision. The former has an extremely low probability, while
the latter is highly probable.
Thus, with this information alone, it is possible to make the reasonable
determination the device is compromised. Whereas if both hashes are
mismatched, without any additional information it is equally probable of
either misconfiguration or compromise. And to state the obvious, with
only SHA2, further information is needed to distinguish between
misconfiguration and compromise.
V/r,
Daniel P. Smith
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-15 19:10 ` Thomas Gleixner
` (2 preceding siblings ...)
2024-08-22 18:29 ` Daniel P. Smith
@ 2024-08-29 3:17 ` Andy Lutomirski
2024-08-29 3:25 ` Matthew Garrett
2024-09-05 1:01 ` Daniel P. Smith
3 siblings, 2 replies; 113+ messages in thread
From: Andy Lutomirski @ 2024-08-29 3:17 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Daniel P. Smith, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jarkko, jgg, nivedita, herbert,
davem, corbet, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Thu, Aug 15, 2024 at 12:10 PM Thomas Gleixner <tglx@linutronix.de> wrote:
>
> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
> > On 5/31/24 09:54, Eric W. Biederman wrote:
> >> Eric Biggers <ebiggers@kernel.org> writes:
> >>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
> >>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
> >>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
> >>> but why would you not at least *prefer* SHA-256?
> >>
> >> Yes. Please prefer to use SHA-256.
> >>
> >> Have you considered implementing I think it is SHA1-DC (as git has) that
> >> is compatible with SHA1 but blocks the known class of attacks where
> >> sha1 is actively broken at this point?
> >
> > We are using the kernel's implementation, addressing what the kernel
> > provides is beyond our efforts. Perhaps someone who is interested in
> > improving the kernel's SHA1 could submit a patch implementing/replacing
> > it with SHA1-DC, as I am sure the maintainers would welcome the help.
>
> Well, someone who is interested to get his "secure" code merged should
> have a vested interested to have a non-broken SHA1 implementation if
> there is a sensible requirement to use SHA1 in that new "secure" code,
> no?
>
> Just for the record. The related maintainers can rightfully decide to
> reject known broken "secure" code on a purely technical argument.
>
Wait, hold on a second.
SHA1-DC isn't SHA1. It's a different hash function that is mostly
compatible with SHA1, is different on some inputs, and is maybe more
secure. But the _whole point_ of using SHA1 in the TPM code (well,
this really should be the whole point for new applications) is to
correctly cap the SHA1 PCRs so we can correctly _turn them off_ in the
best way without breaking compatibility with everything that might
read the event log. I think that anyone suggesting using SHA1-DC for
this purpose should give some actual analysis as to why they think
it's an improvement, let alone even valid.
Ross et al, can you confirm that your code actually, at least by
default and with a monstrous warning to anyone who tries to change the
default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
all stop hassling the people trying to develop this series about the
fact that they're doing their best with the obnoxious system that the
TPM designers gave them?
Thanks,
Andy
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-29 3:17 ` Andy Lutomirski
@ 2024-08-29 3:25 ` Matthew Garrett
2024-08-29 17:26 ` Andy Lutomirski
2024-09-05 1:01 ` Daniel P. Smith
1 sibling, 1 reply; 113+ messages in thread
From: Matthew Garrett @ 2024-08-29 3:25 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Thomas Gleixner, Daniel P. Smith, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, James.Bottomley, peterhuewe, jarkko, jgg,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Wed, Aug 28, 2024 at 08:17:05PM -0700, Andy Lutomirski wrote:
> Ross et al, can you confirm that your code actually, at least by
> default and with a monstrous warning to anyone who tries to change the
> default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
> all stop hassling the people trying to develop this series about the
> fact that they're doing their best with the obnoxious system that the
> TPM designers gave them?
Presumably this would be dependent upon non-SHA1 banks being enabled?
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-29 3:25 ` Matthew Garrett
@ 2024-08-29 17:26 ` Andy Lutomirski
0 siblings, 0 replies; 113+ messages in thread
From: Andy Lutomirski @ 2024-08-29 17:26 UTC (permalink / raw)
To: Matthew Garrett
Cc: Thomas Gleixner, Daniel P. Smith, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, James.Bottomley, peterhuewe, jarkko, jgg,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Wed, Aug 28, 2024 at 8:25 PM Matthew Garrett <mjg59@srcf.ucam.org> wrote:
>
> On Wed, Aug 28, 2024 at 08:17:05PM -0700, Andy Lutomirski wrote:
>
> > Ross et al, can you confirm that your code actually, at least by
> > default and with a monstrous warning to anyone who tries to change the
> > default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
> > all stop hassling the people trying to develop this series about the
> > fact that they're doing their best with the obnoxious system that the
> > TPM designers gave them?
>
> Presumably this would be dependent upon non-SHA1 banks being enabled?
Of course. It's also not immediately obvious to me what layer of the
stack should be responsible for capping SHA1 PCRs. Should it be the
kernel? Userspace?
It seems like a whole lot of people, for better or for worse, want to
minimize the amount of code that even knows how to compute SHA1
hashes. I'm not personally convinced I agree with this strategy, but
it is what it is. And maybe people would be happier if the default
behavior of the kernel is to notice that SHA256 is available and then
cap SHA1 before even asking user code's permission.
--Andy
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-29 3:17 ` Andy Lutomirski
2024-08-29 3:25 ` Matthew Garrett
@ 2024-09-05 1:01 ` Daniel P. Smith
2024-09-13 0:34 ` Daniel P. Smith
1 sibling, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-09-05 1:01 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner
Cc: Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59, James.Bottomley,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
Hi Luto.
On 8/28/24 23:17, Andy Lutomirski wrote:
> On Thu, Aug 15, 2024 at 12:10 PM Thomas Gleixner <tglx@linutronix.de> wrote:
>>
>> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
>>> On 5/31/24 09:54, Eric W. Biederman wrote:
>>>> Eric Biggers <ebiggers@kernel.org> writes:
>>>>> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
>>>>> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
>>>>> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
>>>>> but why would you not at least *prefer* SHA-256?
>>>>
>>>> Yes. Please prefer to use SHA-256.
>>>>
>>>> Have you considered implementing I think it is SHA1-DC (as git has) that
>>>> is compatible with SHA1 but blocks the known class of attacks where
>>>> sha1 is actively broken at this point?
>>>
>>> We are using the kernel's implementation, addressing what the kernel
>>> provides is beyond our efforts. Perhaps someone who is interested in
>>> improving the kernel's SHA1 could submit a patch implementing/replacing
>>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
>>
>> Well, someone who is interested to get his "secure" code merged should
>> have a vested interested to have a non-broken SHA1 implementation if
>> there is a sensible requirement to use SHA1 in that new "secure" code,
>> no?
>>
>> Just for the record. The related maintainers can rightfully decide to
>> reject known broken "secure" code on a purely technical argument.
>>
>
> Wait, hold on a second.
>
> SHA1-DC isn't SHA1. It's a different hash function that is mostly
> compatible with SHA1, is different on some inputs, and is maybe more
> secure. But the _whole point_ of using SHA1 in the TPM code (well,
> this really should be the whole point for new applications) is to
> correctly cap the SHA1 PCRs so we can correctly _turn them off_ in the
> best way without breaking compatibility with everything that might
> read the event log. I think that anyone suggesting using SHA1-DC for
> this purpose should give some actual analysis as to why they think
> it's an improvement, let alone even valid.
I would say at a minimum it is to provide a means to cap the PCRs.
Devices with TPM1.2 are still prevalent in the wild for which members of
the TrenchBoot community support, and there are still valid (and secure)
verification uses for SHA1 that I outlined in my previous response.
> Ross et al, can you confirm that your code actually, at least by
> default and with a monstrous warning to anyone who tries to change the
> default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
> all stop hassling the people trying to develop this series about the
> fact that they're doing their best with the obnoxious system that the
> TPM designers gave them?
Our goal is to keep control in the hands of the user, not making
unilateral decisions on their behalf. In the currently deployed
solutions it is left to the initrd (user) to cap the PCRs. After some
thinking, we can still ensure user control and give an option to cap the
PCRs earlier. We hope to post a v11 later this week or early next week
that introduces a new policy field to the existing measurement policy
framework. Will add/update the kernel docs with respect to the policy
expansion. We are also looking the best way we might add a warning to
the kernel log if the SHA1 bank is used beyond capping the PCRs.
Hopefully this answers the outstanding comments on the SHA1 thread.
v/r,
dps
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-09-05 1:01 ` Daniel P. Smith
@ 2024-09-13 0:34 ` Daniel P. Smith
2024-09-14 3:57 ` Andy Lutomirski
0 siblings, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-09-13 0:34 UTC (permalink / raw)
To: Andy Lutomirski, Thomas Gleixner
Cc: Eric W. Biederman, Eric Biggers, Ross Philipson, linux-kernel,
x86, linux-integrity, linux-doc, linux-crypto, kexec, linux-efi,
iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59, James.Bottomley,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
Hey again,
On 9/4/24 21:01, Daniel P. Smith wrote:
> Hi Luto.
>
> On 8/28/24 23:17, Andy Lutomirski wrote:
>> On Thu, Aug 15, 2024 at 12:10 PM Thomas Gleixner <tglx@linutronix.de>
>> wrote:
>>>
>>> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
>>>> On 5/31/24 09:54, Eric W. Biederman wrote:
>>>>> Eric Biggers <ebiggers@kernel.org> writes:
>>>>>> That paragraph is also phrased as a hypothetical, "Even if we'd
>>>>>> prefer to use
>>>>>> SHA-256-only". That implies that you do not, in fact, prefer
>>>>>> SHA-256 only. Is
>>>>>> that the case? Sure, maybe there are situations where you *have*
>>>>>> to use SHA-1,
>>>>>> but why would you not at least *prefer* SHA-256?
>>>>>
>>>>> Yes. Please prefer to use SHA-256.
>>>>>
>>>>> Have you considered implementing I think it is SHA1-DC (as git has)
>>>>> that
>>>>> is compatible with SHA1 but blocks the known class of attacks where
>>>>> sha1 is actively broken at this point?
>>>>
>>>> We are using the kernel's implementation, addressing what the kernel
>>>> provides is beyond our efforts. Perhaps someone who is interested in
>>>> improving the kernel's SHA1 could submit a patch implementing/replacing
>>>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
>>>
>>> Well, someone who is interested to get his "secure" code merged should
>>> have a vested interested to have a non-broken SHA1 implementation if
>>> there is a sensible requirement to use SHA1 in that new "secure" code,
>>> no?
>>>
>>> Just for the record. The related maintainers can rightfully decide to
>>> reject known broken "secure" code on a purely technical argument.
>>>
>>
>> Wait, hold on a second.
>>
>> SHA1-DC isn't SHA1. It's a different hash function that is mostly
>> compatible with SHA1, is different on some inputs, and is maybe more
>> secure. But the _whole point_ of using SHA1 in the TPM code (well,
>> this really should be the whole point for new applications) is to
>> correctly cap the SHA1 PCRs so we can correctly _turn them off_ in the
>> best way without breaking compatibility with everything that might
>> read the event log. I think that anyone suggesting using SHA1-DC for
>> this purpose should give some actual analysis as to why they think
>> it's an improvement, let alone even valid.
>
> I would say at a minimum it is to provide a means to cap the PCRs.
> Devices with TPM1.2 are still prevalent in the wild for which members of
> the TrenchBoot community support, and there are still valid (and secure)
> verification uses for SHA1 that I outlined in my previous response.
>
>> Ross et al, can you confirm that your code actually, at least by
>> default and with a monstrous warning to anyone who tries to change the
>> default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
>> all stop hassling the people trying to develop this series about the
>> fact that they're doing their best with the obnoxious system that the
>> TPM designers gave them?
>
> Our goal is to keep control in the hands of the user, not making
> unilateral decisions on their behalf. In the currently deployed
> solutions it is left to the initrd (user) to cap the PCRs. After some
> thinking, we can still ensure user control and give an option to cap the
> PCRs earlier. We hope to post a v11 later this week or early next week
> that introduces a new policy field to the existing measurement policy
> framework. Will add/update the kernel docs with respect to the policy
> expansion. We are also looking the best way we might add a warning to
> the kernel log if the SHA1 bank is used beyond capping the PCRs.
As the attempt was made to lay in the policy logic, it started to become
convoluted and unnecessarily complicated. Thus creating more risk with
all the bookkeeping and yet sha1 hashes still have to be sent, the null
hash in this case, since the TPM driver will reject extends that do not
have hashes for all active banks. At this point, we have opted to keep
the logic simple and add a section to our documentation advising of the
potential risk should one choose to incorporate SHA1 in their
attestations of the platform.
v/r,
dps
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-09-13 0:34 ` Daniel P. Smith
@ 2024-09-14 3:57 ` Andy Lutomirski
2024-09-21 18:36 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: Andy Lutomirski @ 2024-09-14 3:57 UTC (permalink / raw)
To: Daniel P. Smith
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jarkko, jgg, nivedita, herbert,
davem, corbet, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Thu, Sep 12, 2024 at 5:34 PM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
>
> Hey again,
>
> On 9/4/24 21:01, Daniel P. Smith wrote:
> > Hi Luto.
> >
> > On 8/28/24 23:17, Andy Lutomirski wrote:
> >> On Thu, Aug 15, 2024 at 12:10 PM Thomas Gleixner <tglx@linutronix.de>
> >> wrote:
> >>>
> >>> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
> >>>> On 5/31/24 09:54, Eric W. Biederman wrote:
> >>>>> Eric Biggers <ebiggers@kernel.org> writes:
> >>>>>> That paragraph is also phrased as a hypothetical, "Even if we'd
> >>>>>> prefer to use
> >>>>>> SHA-256-only". That implies that you do not, in fact, prefer
> >>>>>> SHA-256 only. Is
> >>>>>> that the case? Sure, maybe there are situations where you *have*
> >>>>>> to use SHA-1,
> >>>>>> but why would you not at least *prefer* SHA-256?
> >>>>>
> >>>>> Yes. Please prefer to use SHA-256.
> >>>>>
> >>>>> Have you considered implementing I think it is SHA1-DC (as git has)
> >>>>> that
> >>>>> is compatible with SHA1 but blocks the known class of attacks where
> >>>>> sha1 is actively broken at this point?
> >>>>
> >>>> We are using the kernel's implementation, addressing what the kernel
> >>>> provides is beyond our efforts. Perhaps someone who is interested in
> >>>> improving the kernel's SHA1 could submit a patch implementing/replacing
> >>>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
> >>>
> >>> Well, someone who is interested to get his "secure" code merged should
> >>> have a vested interested to have a non-broken SHA1 implementation if
> >>> there is a sensible requirement to use SHA1 in that new "secure" code,
> >>> no?
> >>>
> >>> Just for the record. The related maintainers can rightfully decide to
> >>> reject known broken "secure" code on a purely technical argument.
> >>>
> >>
> >> Wait, hold on a second.
> >>
> >> SHA1-DC isn't SHA1. It's a different hash function that is mostly
> >> compatible with SHA1, is different on some inputs, and is maybe more
> >> secure. But the _whole point_ of using SHA1 in the TPM code (well,
> >> this really should be the whole point for new applications) is to
> >> correctly cap the SHA1 PCRs so we can correctly _turn them off_ in the
> >> best way without breaking compatibility with everything that might
> >> read the event log. I think that anyone suggesting using SHA1-DC for
> >> this purpose should give some actual analysis as to why they think
> >> it's an improvement, let alone even valid.
> >
> > I would say at a minimum it is to provide a means to cap the PCRs.
> > Devices with TPM1.2 are still prevalent in the wild for which members of
> > the TrenchBoot community support, and there are still valid (and secure)
> > verification uses for SHA1 that I outlined in my previous response.
> >
> >> Ross et al, can you confirm that your code actually, at least by
> >> default and with a monstrous warning to anyone who tries to change the
> >> default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
> >> all stop hassling the people trying to develop this series about the
> >> fact that they're doing their best with the obnoxious system that the
> >> TPM designers gave them?
> >
> > Our goal is to keep control in the hands of the user, not making
> > unilateral decisions on their behalf. In the currently deployed
> > solutions it is left to the initrd (user) to cap the PCRs. After some
> > thinking, we can still ensure user control and give an option to cap the
> > PCRs earlier. We hope to post a v11 later this week or early next week
> > that introduces a new policy field to the existing measurement policy
> > framework. Will add/update the kernel docs with respect to the policy
> > expansion. We are also looking the best way we might add a warning to
> > the kernel log if the SHA1 bank is used beyond capping the PCRs.
>
> As the attempt was made to lay in the policy logic, it started to become
> convoluted and unnecessarily complicated. Thus creating more risk with
> all the bookkeeping and yet sha1 hashes still have to be sent, the null
> hash in this case, since the TPM driver will reject extends that do not
> have hashes for all active banks. At this point, we have opted to keep
> the logic simple and add a section to our documentation advising of the
> potential risk should one choose to incorporate SHA1 in their
> attestations of the platform.
>
I've read the TPM standard a bit, but it's been awhile, and it's too
complicated anyway. So, can you remind me (and probably 3/4 of the
other people on this thread, too):
What, exactly, is your patchset doing that requires hashing at all?
(I assume it's extending a PCR and generating an event log entry.).
What, exactly, does it mean to "cap" a PCR? How is this different
from what your patchset does?
With that answered, it will hopefully be easy to see that you're
making the right call :)
--Andy
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-09-14 3:57 ` Andy Lutomirski
@ 2024-09-21 18:36 ` Daniel P. Smith
2024-09-21 22:40 ` Andy Lutomirski
0 siblings, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-09-21 18:36 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jarkko, jgg, nivedita, herbert,
davem, corbet, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On 9/13/24 23:57, Andy Lutomirski wrote:
> On Thu, Sep 12, 2024 at 5:34 PM Daniel P. Smith
> <dpsmith@apertussolutions.com> wrote:
>>
>> Hey again,
>>
>> On 9/4/24 21:01, Daniel P. Smith wrote:
>>> Hi Luto.
>>>
>>> On 8/28/24 23:17, Andy Lutomirski wrote:
>>>> On Thu, Aug 15, 2024 at 12:10 PM Thomas Gleixner <tglx@linutronix.de>
>>>> wrote:
>>>>>
>>>>> On Thu, Aug 15 2024 at 13:38, Daniel P. Smith wrote:
>>>>>> On 5/31/24 09:54, Eric W. Biederman wrote:
>>>>>>> Eric Biggers <ebiggers@kernel.org> writes:
>>>>>>>> That paragraph is also phrased as a hypothetical, "Even if we'd
>>>>>>>> prefer to use
>>>>>>>> SHA-256-only". That implies that you do not, in fact, prefer
>>>>>>>> SHA-256 only. Is
>>>>>>>> that the case? Sure, maybe there are situations where you *have*
>>>>>>>> to use SHA-1,
>>>>>>>> but why would you not at least *prefer* SHA-256?
>>>>>>>
>>>>>>> Yes. Please prefer to use SHA-256.
>>>>>>>
>>>>>>> Have you considered implementing I think it is SHA1-DC (as git has)
>>>>>>> that
>>>>>>> is compatible with SHA1 but blocks the known class of attacks where
>>>>>>> sha1 is actively broken at this point?
>>>>>>
>>>>>> We are using the kernel's implementation, addressing what the kernel
>>>>>> provides is beyond our efforts. Perhaps someone who is interested in
>>>>>> improving the kernel's SHA1 could submit a patch implementing/replacing
>>>>>> it with SHA1-DC, as I am sure the maintainers would welcome the help.
>>>>>
>>>>> Well, someone who is interested to get his "secure" code merged should
>>>>> have a vested interested to have a non-broken SHA1 implementation if
>>>>> there is a sensible requirement to use SHA1 in that new "secure" code,
>>>>> no?
>>>>>
>>>>> Just for the record. The related maintainers can rightfully decide to
>>>>> reject known broken "secure" code on a purely technical argument.
>>>>>
>>>>
>>>> Wait, hold on a second.
>>>>
>>>> SHA1-DC isn't SHA1. It's a different hash function that is mostly
>>>> compatible with SHA1, is different on some inputs, and is maybe more
>>>> secure. But the _whole point_ of using SHA1 in the TPM code (well,
>>>> this really should be the whole point for new applications) is to
>>>> correctly cap the SHA1 PCRs so we can correctly _turn them off_ in the
>>>> best way without breaking compatibility with everything that might
>>>> read the event log. I think that anyone suggesting using SHA1-DC for
>>>> this purpose should give some actual analysis as to why they think
>>>> it's an improvement, let alone even valid.
>>>
>>> I would say at a minimum it is to provide a means to cap the PCRs.
>>> Devices with TPM1.2 are still prevalent in the wild for which members of
>>> the TrenchBoot community support, and there are still valid (and secure)
>>> verification uses for SHA1 that I outlined in my previous response.
>>>
>>>> Ross et al, can you confirm that your code actually, at least by
>>>> default and with a monstrous warning to anyone who tries to change the
>>>> default, caps SHA1 PCRs if SHA256 is available? And then can we maybe
>>>> all stop hassling the people trying to develop this series about the
>>>> fact that they're doing their best with the obnoxious system that the
>>>> TPM designers gave them?
>>>
>>> Our goal is to keep control in the hands of the user, not making
>>> unilateral decisions on their behalf. In the currently deployed
>>> solutions it is left to the initrd (user) to cap the PCRs. After some
>>> thinking, we can still ensure user control and give an option to cap the
>>> PCRs earlier. We hope to post a v11 later this week or early next week
>>> that introduces a new policy field to the existing measurement policy
>>> framework. Will add/update the kernel docs with respect to the policy
>>> expansion. We are also looking the best way we might add a warning to
>>> the kernel log if the SHA1 bank is used beyond capping the PCRs.
>>
>> As the attempt was made to lay in the policy logic, it started to become
>> convoluted and unnecessarily complicated. Thus creating more risk with
>> all the bookkeeping and yet sha1 hashes still have to be sent, the null
>> hash in this case, since the TPM driver will reject extends that do not
>> have hashes for all active banks. At this point, we have opted to keep
>> the logic simple and add a section to our documentation advising of the
>> potential risk should one choose to incorporate SHA1 in their
>> attestations of the platform.
>>
>
> I've read the TPM standard a bit, but it's been awhile, and it's too
> complicated anyway. So, can you remind me (and probably 3/4 of the
> other people on this thread, too):
Sure, but honestly if you were to ask me in person, I would have given
you the explanation as provided in the Secure Launch Overview in the
documentation patch.
> What, exactly, is your patchset doing that requires hashing at all?
> (I assume it's extending a PCR and generating an event log entry.).
> What, exactly, does it mean to "cap" a PCR? How is this different
> from what your patchset does?
The SINIT ACM is provided a structure that basically says, here is an
address and size of what it will execute next. It will use that
information to take its transitive trust measurement of the kernel
before handing control to the Linux kernel. The Secure Launch code is
responsible for ensuring everything that can influences its execution to
be measured and stored into the TPM for attestations to be made at a
latter time. The most important part is the transitive trust measurement
of the next part to be executed, the initramfs. Specifically, the Secure
Launch code must be able to handle the situation where the initramfs
independent of the kernel and loaded separately. Additionally, the
policy function provided for optional system state to also be measured
and recorded, as the attestation evaluator might want them.
At the end of the day, this capability is strictly a passive (mostly,
see note [1] below) solution with the responsibility to maintain the
DRTM trust chain by taking meaningful measurements. This includes the
next component in the trust chain and then hand execution to that next
component.
The TCG specs and good practices provide that a component in either SRTM
or DRTM trust chains should extend a non-event record to the tpm and/or
its log. This is to indicate the transition point from one component in
the trust chain to the next component. Under the client profile,
firmware is required to do this by extending an event of type
EV_SEPARATOR before "Ready to Boot".
I did not see the term actually defined in the client profile, but the
term "cap" refers to the specific action of hashing a value across a set
of PCRs. This is to reflect that certain events have occurred and will
result in a different but predictable change to the PCR value. Often
times this is to ensure that if there are TPM objects sealed to the
system with either that event having or have not occurred, they cannot
be unsealed. Thus, one has "capped" the PCRs as a means to close access
to the “acceptable” system state.
To close and reiterate, Secure Launch only responsibility is to send
measurements to the TPM. The TPM and TPM driver has an expectation that
every PCR extend event contains a hash for every active algorithm bank.
For Secure Launch, to send SHA1 measurements has zero impact on the
security of the system. Whether those measurements are used for TPM
integrity reporting and security policy enforcement by user space or an
enterprise is outside the scope of the Secure Launch capability and the
kernel.
[1] A future expansion of Secure Launch will be to enable usage of
Intel's Hardware Shield, link below, to provide runtime trustworthy
determination of SMM. The full extent of this capability can only be
achieved under a DRTM launch of the system with Intel TXT. When enabled,
this can be used to verify the SMM protections are in place and inform
the kernel's memory management which regions of memory are safe from SMM
tampering.
https://www.intel.com/content/dam/www/central-libraries/us/en/documents/drtm-based-computing-whitepaper.pdf
> With that answered, it will hopefully be easy to see that you're
> making the right call :)
>
> --Andy
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-09-21 18:36 ` Daniel P. Smith
@ 2024-09-21 22:40 ` Andy Lutomirski
2024-11-02 14:53 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: Andy Lutomirski @ 2024-09-21 22:40 UTC (permalink / raw)
To: Daniel P. Smith
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jarkko, jgg, nivedita, herbert,
davem, corbet, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Sat, Sep 21, 2024 at 11:37 AM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
>
> On 9/13/24 23:57, Andy Lutomirski wrote:
> > On Thu, Sep 12, 2024 at 5:34 PM Daniel P. Smith
> > <dpsmith@apertussolutions.com> wrote:
> >>
> > What, exactly, is your patchset doing that requires hashing at all?
> > (I assume it's extending a PCR and generating an event log entry.).
> > What, exactly, does it mean to "cap" a PCR? How is this different
> > from what your patchset does?
>
>
...
> I did not see the term actually defined in the client profile, but the
> term "cap" refers to the specific action of hashing a value across a set
> of PCRs. This is to reflect that certain events have occurred and will
> result in a different but predictable change to the PCR value. Often
> times this is to ensure that if there are TPM objects sealed to the
> system with either that event having or have not occurred, they cannot
> be unsealed. Thus, one has "capped" the PCRs as a means to close access
> to the “acceptable” system state.
Okay, so I read Ross's earlier email rather differently:
> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> to safely use SHA-256 for everything else.
I assumed that "deliberately cap" meant that there was an actual
feature where you write something to the event log (if applicable) and
extend the PCR in a special way that *turns that PCR off*. That is,
it does something such that later-loaded software *can't* use that PCR
to attest or unseal anything, etc.
But it sounds like you're saying that no such feature exists. And a
quick skim of the specs doesn't come up with anything. And the SHA1
banks may well be susceptible to a collision attack.
So what are the kernel's choices wrt the SHA-1 PCRs? It can:
a) Perform business as usual: extend them consistently with the
SHA-256 PCRs. This is sort of *fine*: the kernel code in question is
not relying on the security of SHA-1, but it is making it possible for
future code to (unwisely) rely on them. (Although, if the kernel is
loading a trustworthy initramfs, then there won't be a collision, and
there is no known second-preimage attack against SHA-1.)
b) Same as (a), but with countermeasures: do something to the effect
of *detecting* the attack a la SHA1-DC and panic if an attack is
detected. Maybe this is wise; maybe it's not.
c) Do not extend the SHA-1 PCRs and pretend they don't exist. This
seems likely to cause massive security problems, and having the kernel
try to defend its behavior by saying "we don't support SHA-1 -- this
is a problem downstream" seems unwise to me.
d) Extend them but in an unconventional way that makes using them
extra secure. For example, calculate SHA-256(next stage), then extend
with (next stage || "Linux thinks this is better" || SHA-256(next
stage). This makes the SHA-1 banks usable, and it seems like it will
probably defeat anything resembling a current attack. But maybe this
is silly. It would probably require doing the same thing to the
SHA-256 banks for the benefit of any software that checks whether the
SHA-1 and SHA-256 banks are consistent with each other.
e) Actually try to make the SHA-1 PCRs unusable. For example, extend
them with random numbers.
My inclination is that having some kind of Linux "policy" that SHA-1
is forbidden adds no actual security value. Option (a) honestly seems
fine. Nothing in the kernel *relies* on the SHA-1 hash being secure.
But option (b) also seems okay if someone is willing to put the effort
into implementing it and creating a proper test case.
But the description of all this could certainly do a better job of
explaining what's going on.
--Andy
> [1] A future expansion of Secure Launch will be to enable usage of
> Intel's Hardware Shield, link below, to provide runtime trustworthy
> determination of SMM. The full extent of this capability can only be
> achieved under a DRTM launch of the system with Intel TXT. When enabled,
> this can be used to verify the SMM protections are in place and inform
> the kernel's memory management which regions of memory are safe from SMM
> tampering.
>
> https://www.intel.com/content/dam/www/central-libraries/us/en/documents/drtm-based-computing-whitepaper.pdf
Wow. I skimmed this paper. What an overcomplicated solution to a
problem that doesn't deserve to exist in the first place.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-09-21 22:40 ` Andy Lutomirski
@ 2024-11-02 14:53 ` Daniel P. Smith
2024-11-02 16:04 ` James Bottomley
0 siblings, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-11-02 14:53 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jarkko, jgg, nivedita, herbert,
davem, corbet, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
Hi Luto,
My apologies, I missed this response and the active on v11 cause me to
get an inquiry why I hadn't responded.
On 9/21/24 18:40, Andy Lutomirski wrote:
> On Sat, Sep 21, 2024 at 11:37 AM Daniel P. Smith
> <dpsmith@apertussolutions.com> wrote:
>>
>> On 9/13/24 23:57, Andy Lutomirski wrote:
>>> On Thu, Sep 12, 2024 at 5:34 PM Daniel P. Smith
>>> <dpsmith@apertussolutions.com> wrote:
>>>>
>
>>> What, exactly, is your patchset doing that requires hashing at all?
>>> (I assume it's extending a PCR and generating an event log entry.).
>>> What, exactly, does it mean to "cap" a PCR? How is this different
>>> from what your patchset does?
>>
>>
>
> ...
>
>> I did not see the term actually defined in the client profile, but the
>> term "cap" refers to the specific action of hashing a value across a set
>> of PCRs. This is to reflect that certain events have occurred and will
>> result in a different but predictable change to the PCR value. Often
>> times this is to ensure that if there are TPM objects sealed to the
>> system with either that event having or have not occurred, they cannot
>> be unsealed. Thus, one has "capped" the PCRs as a means to close access
>> to the “acceptable” system state.
>
> Okay, so I read Ross's earlier email rather differently:
>
>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>> to safely use SHA-256 for everything else.
>
> I assumed that "deliberately cap" meant that there was an actual
> feature where you write something to the event log (if applicable) and
> extend the PCR in a special way that *turns that PCR off*. That is,
> it does something such that later-loaded software *can't* use that PCR
> to attest or unseal anything, etc.
>
> But it sounds like you're saying that no such feature exists. And a
> quick skim of the specs doesn't come up with anything. And the SHA1
> banks may well be susceptible to a collision attack.
Correct, the only entity that can disable PCR banks is the firmware.
When it initializes the TPM, it can disable banks/algorithms. After
that, when an extend operation is done, the TPM is expecting an entry
for all active PCR banks and the TPM itself does the extend hash that is
stored into the PCRs.
> So what are the kernel's choices wrt the SHA-1 PCRs? It can:
>
> a) Perform business as usual: extend them consistently with the
> SHA-256 PCRs. This is sort of *fine*: the kernel code in question is
> not relying on the security of SHA-1, but it is making it possible for
> future code to (unwisely) rely on them. (Although, if the kernel is
> loading a trustworthy initramfs, then there won't be a collision, and
> there is no known second-preimage attack against SHA-1.)
>
> b) Same as (a), but with countermeasures: do something to the effect
> of *detecting* the attack a la SHA1-DC and panic if an attack is
> detected. Maybe this is wise; maybe it's not.
>
> c) Do not extend the SHA-1 PCRs and pretend they don't exist. This
> seems likely to cause massive security problems, and having the kernel
> try to defend its behavior by saying "we don't support SHA-1 -- this
> is a problem downstream" seems unwise to me.
I will chime in here to say that you can't ignore them, but you can send
a fixed value, either well-known or junk, as the SHA1 value when doing
the extend operation as you suggest in (e).
> d) Extend them but in an unconventional way that makes using them
> extra secure. For example, calculate SHA-256(next stage), then extend
> with (next stage || "Linux thinks this is better" || SHA-256(next
> stage). This makes the SHA-1 banks usable, and it seems like it will
> probably defeat anything resembling a current attack. But maybe this
> is silly. It would probably require doing the same thing to the
> SHA-256 banks for the benefit of any software that checks whether the
> SHA-1 and SHA-256 banks are consistent with each other.
>
> e) Actually try to make the SHA-1 PCRs unusable. For example, extend
> them with random numbers.
>
> My inclination is that having some kind of Linux "policy" that SHA-1
> is forbidden adds no actual security value. Option (a) honestly seems
> fine. Nothing in the kernel *relies* on the SHA-1 hash being secure.
> But option (b) also seems okay if someone is willing to put the effort
> into implementing it and creating a proper test case.
Obviously, for the most part, we are in agreement. The one caveat is
that I don't think the effort to shore-up SHA1 provides a good return on
the costs it would incur. With no intent to disparage any one person,
there generally will be two groups that would use SHA1. The first would
be those limited by their platform and understand the risks. The second
would be those attempting to do a cryptographic-based security solution
that has either been living under a rock the last few years or has done
zero research into the capabilities they are using for their solution.
IMHO it is better to not inhibit the first group trying to save the
latter group as the latter are always doomed to failure.
> But the description of all this could certainly do a better job of
> explaining what's going on.
I would be glad to do so, and have tried several ways to explain it.
Even working with multiple people that understand the problem to draft a
better explanation. It would be greatly appreciated if you could provide
what points you think should be clarified to better help convey the
situation.
> --Andy
>
>> [1] A future expansion of Secure Launch will be to enable usage of
>> Intel's Hardware Shield, link below, to provide runtime trustworthy
>> determination of SMM. The full extent of this capability can only be
>> achieved under a DRTM launch of the system with Intel TXT. When enabled,
>> this can be used to verify the SMM protections are in place and inform
>> the kernel's memory management which regions of memory are safe from SMM
>> tampering.
>>
>> https://www.intel.com/content/dam/www/central-libraries/us/en/documents/drtm-based-computing-whitepaper.pdf
>
> Wow. I skimmed this paper. What an overcomplicated solution to a
> problem that doesn't deserve to exist in the first place.
While we could have a long discussion over the merits of SMM, the fact
we have to face is that it is here, and it is not going anywhere any
time soon. I honestly found AMD's SMM Containerization (Appendix D of
the AMD64 Architecture Programmer’s Manual - Volume 2) the better
approach, and it saddens me that it is completely disabled.
v/r,
dps
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-02 14:53 ` Daniel P. Smith
@ 2024-11-02 16:04 ` James Bottomley
2024-11-15 1:17 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: James Bottomley @ 2024-11-02 16:04 UTC (permalink / raw)
To: Daniel P. Smith, Andy Lutomirski
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Sat, 2024-11-02 at 10:53 -0400, Daniel P. Smith wrote:
> Hi Luto,
>
> My apologies, I missed this response and the active on v11 cause me
> to
> get an inquiry why I hadn't responded.
>
> On 9/21/24 18:40, Andy Lutomirski wrote:
[...]
> > I assumed that "deliberately cap" meant that there was an actual
> > feature where you write something to the event log (if applicable)
> > and extend the PCR in a special way that *turns that PCR off*.
> > That is, it does something such that later-loaded software *can't*
> > use that PCR to attest or unseal anything, etc.
> >
> > But it sounds like you're saying that no such feature exists. And
> > a quick skim of the specs doesn't come up with anything. And the
> > SHA1 banks may well be susceptible to a collision attack.
>
> Correct, the only entity that can disable PCR banks is the firmware.
No, that's not correct. Any user can use TPM_PCR_Allocate to activate
or deactivate individual banks. The caveat is the change is not
implemented until the next TPM reset (which should involve a reboot).
BIOS also gets to the TPM before the kernel does, so it can, in theory,
check what banks a TPM has and call TPM_PCR_Allocate to change them.
In practice, because this requires a reboot, this is usually only done
from the BIOS menus not on a direct boot ... so you can be reasonably
sure that whatever changes were made will stick.
> When it initializes the TPM, it can disable banks/algorithms. After
> that, when an extend operation is done, the TPM is expecting an entry
> for all active PCR banks and the TPM itself does the extend hash that
> is stored into the PCRs.
This, also, is not quite correct: an extend is allowed to specify banks
that don't exist (in which case nothing happens and no error is
reported) and miss banks that do (in which case no extend is done to
that bank). In the early days of TPM2, some BIOS implementations only
extended sha1 for instance, meaning the sha256 banks were all zero when
the kernel started.
Even today, if you activate a bank the BIOS doesn't know about, it
likely won't extend it. You can see this in VM boots with OVMF and
software TPMs having esoteric banks like SM3.
Regards,
James
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-02 16:04 ` James Bottomley
@ 2024-11-15 1:17 ` Daniel P. Smith
2024-11-18 18:43 ` Andy Lutomirski
0 siblings, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-11-15 1:17 UTC (permalink / raw)
To: James Bottomley, Andy Lutomirski
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 11/2/24 12:04, James Bottomley wrote:
> On Sat, 2024-11-02 at 10:53 -0400, Daniel P. Smith wrote:
>> Hi Luto,
>>
>> My apologies, I missed this response and the active on v11 cause me
>> to
>> get an inquiry why I hadn't responded.
>>
>> On 9/21/24 18:40, Andy Lutomirski wrote:
> [...]
>>> I assumed that "deliberately cap" meant that there was an actual
>>> feature where you write something to the event log (if applicable)
>>> and extend the PCR in a special way that *turns that PCR off*.
>>> That is, it does something such that later-loaded software *can't*
>>> use that PCR to attest or unseal anything, etc.
>>>
>>> But it sounds like you're saying that no such feature exists. And
>>> a quick skim of the specs doesn't come up with anything. And the
>>> SHA1 banks may well be susceptible to a collision attack.
>>
>> Correct, the only entity that can disable PCR banks is the firmware.
>
> No, that's not correct. Any user can use TPM_PCR_Allocate to activate
> or deactivate individual banks. The caveat is the change is not
> implemented until the next TPM reset (which should involve a reboot).
> BIOS also gets to the TPM before the kernel does, so it can, in theory,
> check what banks a TPM has and call TPM_PCR_Allocate to change them.
> In practice, because this requires a reboot, this is usually only done
> from the BIOS menus not on a direct boot ... so you can be reasonably
> sure that whatever changes were made will stick.
Okay, since there is a desire for exactness. Any system software can
send the TPM_PCR_Allocate command, specifying which PCRs should be
activated on next _TPM_init. There are restrictions such that if
DRTM_PCR is defined, then at least one bank must have a D-RTM PCR
allocation. In agreement with my statement, this is the mechanism used
by firmware to select the banks. Depending on the firmware
implementation, the firmware request will likely override the request
sent by the system software.
This brings us back to an earlier point, if one disables the SHA1 banks
in BIOS menu, then TXT will not use them and thus neither will Secure
Launch. Secure Launch will only use the algorithms used by the CPU and
the ACM.
>> When it initializes the TPM, it can disable banks/algorithms. After
>> that, when an extend operation is done, the TPM is expecting an entry
>> for all active PCR banks and the TPM itself does the extend hash that
>> is stored into the PCRs.
>
> This, also, is not quite correct: an extend is allowed to specify banks
> that don't exist (in which case nothing happens and no error is
> reported) and miss banks that do (in which case no extend is done to
> that bank). In the early days of TPM2, some BIOS implementations only
> extended sha1 for instance, meaning the sha256 banks were all zero when
> the kernel started.
>
> Even today, if you activate a bank the BIOS doesn't know about, it
> likely won't extend it. You can see this in VM boots with OVMF and
> software TPMs having esoteric banks like SM3.
Let me correct myself here and again be extremely precise. When an
extend operation is done, the TPM driver expects to receive an array of
digests that is the same size as the number of allocated/active banks.
Specifically, it loops from 0 to chip->nr_allocated_banks, filling
TPML_DIGEST_VALUES with an entry for all the active banks, to include
SHA1 if it is active. Coming back to my response to Luto, we can either
populate it with 0 or a well-known value for each extend we send.
Regardless of what the value is, the TPM will use its implementation of
SHA1 to calculate the resulting extend value.
Even with these clarifications, the conclusion does not change. If the
firmware enables SHA1, there is nothing that can be done to disable or
block its usage from the user. Linux Secure Launch sending measurements
to all the banks that the hardware used to start the DRTM chain does not
create a vulnerability in and of itself. The user is free to leverage
the SHA1 bank in any of the TPM's Integrity Collection suite of
operations, regardless of what Secure Launch sends for the SHA1 hash.
Whereas, neutering the solution of SHA1 breaks the ability for it to
support any hardware that has a TPM1.2, of which there are still many in
use.
V/r,
Daniel P. Smith
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-15 1:17 ` Daniel P. Smith
@ 2024-11-18 18:43 ` Andy Lutomirski
2024-11-18 18:50 ` Andy Lutomirski
2024-11-18 19:12 ` James Bottomley
0 siblings, 2 replies; 113+ messages in thread
From: Andy Lutomirski @ 2024-11-18 18:43 UTC (permalink / raw)
To: Daniel P. Smith
Cc: James Bottomley, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg, nivedita,
herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Thu, Nov 14, 2024 at 5:17 PM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
>
> On 11/2/24 12:04, James Bottomley wrote:
> > On Sat, 2024-11-02 at 10:53 -0400, Daniel P. Smith wrote:
> >> Hi Luto,
> >>
> >> My apologies, I missed this response and the active on v11 cause me
> >> to
> >> get an inquiry why I hadn't responded.
> >>
> >> On 9/21/24 18:40, Andy Lutomirski wrote:
> > [...]
> >>> I assumed that "deliberately cap" meant that there was an actual
> >>> feature where you write something to the event log (if applicable)
> >>> and extend the PCR in a special way that *turns that PCR off*.
> >>> That is, it does something such that later-loaded software *can't*
> >>> use that PCR to attest or unseal anything, etc.
> >>>
> >>> But it sounds like you're saying that no such feature exists. And
> >>> a quick skim of the specs doesn't come up with anything. And the
> >>> SHA1 banks may well be susceptible to a collision attack.
> >>
> >> Correct, the only entity that can disable PCR banks is the firmware.
> >
> > No, that's not correct. Any user can use TPM_PCR_Allocate to activate
> > or deactivate individual banks. The caveat is the change is not
> > implemented until the next TPM reset (which should involve a reboot).
> > BIOS also gets to the TPM before the kernel does, so it can, in theory,
> > check what banks a TPM has and call TPM_PCR_Allocate to change them.
> > In practice, because this requires a reboot, this is usually only done
> > from the BIOS menus not on a direct boot ... so you can be reasonably
> > sure that whatever changes were made will stick.
>
> Okay, since there is a desire for exactness. Any system software can
> send the TPM_PCR_Allocate command, specifying which PCRs should be
> activated on next _TPM_init. There are restrictions such that if
> DRTM_PCR is defined, then at least one bank must have a D-RTM PCR
> allocation. In agreement with my statement, this is the mechanism used
> by firmware to select the banks. Depending on the firmware
> implementation, the firmware request will likely override the request
> sent by the system software.
>
> This brings us back to an earlier point, if one disables the SHA1 banks
> in BIOS menu, then TXT will not use them and thus neither will Secure
> Launch. Secure Launch will only use the algorithms used by the CPU and
> the ACM.
>
> >> When it initializes the TPM, it can disable banks/algorithms. After
> >> that, when an extend operation is done, the TPM is expecting an entry
> >> for all active PCR banks and the TPM itself does the extend hash that
> >> is stored into the PCRs.
> >
> > This, also, is not quite correct: an extend is allowed to specify banks
> > that don't exist (in which case nothing happens and no error is
> > reported) and miss banks that do (in which case no extend is done to
> > that bank). In the early days of TPM2, some BIOS implementations only
> > extended sha1 for instance, meaning the sha256 banks were all zero when
> > the kernel started.
> >
> > Even today, if you activate a bank the BIOS doesn't know about, it
> > likely won't extend it. You can see this in VM boots with OVMF and
> > software TPMs having esoteric banks like SM3.
How is this not a security hole you could drive a truck through?
Indeed, looking at the docs, TPM2_PCR_Extend says "If no digest value
is specified for a bank, then the PCR in that bank is not modified."
>
> Let me correct myself here and again be extremely precise. When an
> extend operation is done, the TPM driver expects to receive an array of
> digests that is the same size as the number of allocated/active banks.
> Specifically, it loops from 0 to chip->nr_allocated_banks, filling
> TPML_DIGEST_VALUES with an entry for all the active banks, to include
> SHA1 if it is active. Coming back to my response to Luto, we can either
> populate it with 0 or a well-known value for each extend we send.
> Regardless of what the value is, the TPM will use its implementation of
> SHA1 to calculate the resulting extend value.
At least extending unknown/unsupported banks with 0 modifies the bank,
which gives software that might rely on that bank an indication that
something in the chain doesn't support the bank. But does actual
TPM-using software in the wild actually look up the event log and
notice that it contains a 0?
This sucks. How on Earth didn't the TPM2 spec do this instead of
having explicit handling for "a PCR got extended, and the code that
extended it didn't support a given bank, and therefore *the resulting
PCR value cannot be relied on*? It would have been *one single bit
per PCR, bank* indicating that the PCR's value is incomplete, along
with some basic logic that an incomplete PCR cannot magically become
complete, nor can it be used to authorize anything unless the
authorization policy explicitly allows it?
Anyway, other than the fact that everyone (presumably?) expects
software to be aware of SHA-1 and (mostly) SHA256, and presumably
users of SM3 already expect that a lot of things don't support it,
SHA1 doesn't seem very different from SM3 in the sense that (a) people
might not want to support it and (b) the actual behavior of a boot
chain component that doesn't support a cryptosystem is FUNDAMENTALLY
DANGEROUS.
Is there explicit guidance from TCG as to how this is supposed to work?
In any case, I have a strawman suggestion to resolve this issue much
better from Linux's perspective. It's a strawman because, while I
attempted to read the relevant part of the specs, the specs and the
ecosystem are a mess, so I could be wrong.
Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
exclusively use TPM2_PCR_Event. I would expect that passing, say, the
entire kernel image to TPM2_PCR_Event would be a big mistake, so
instead Linux should hash the relevant data with a reasonable
suggestion of hashes (which includes, mandatorily, SHA-384 and *does
not* include SHA-1, and may or may not be configurable at build time
to include things like SM3), concatenate them, and pass that to
TPM2_PCR_Event. And Linux should make the value that it passed to
TPM2_PCR_Event readily accessible to software using it, and should
also include some straightforward tooling to calculate it from a given
input so that software that wants to figure out what value to expect
in a PCR can easily do so.
And then software that wants to use a SHA-1 bank will work every bit
as well as it would if Linux actually implemented it, but Linux can
happily not implement it, and even users of oddball algorithms that
Linux has never heard of will get secure behavior.
(Why SHA-384? Because it's mandatory in the TPM Client profile, and
anyone who's happy with SHA-256 should also be willing to accept
SHA-384.)
>
> Even with these clarifications, the conclusion does not change. If the
> firmware enables SHA1, there is nothing that can be done to disable or
> block its usage from the user. Linux Secure Launch sending measurements
> to all the banks that the hardware used to start the DRTM chain does not
> create a vulnerability in and of itself. The user is free to leverage
> the SHA1 bank in any of the TPM's Integrity Collection suite of
> operations, regardless of what Secure Launch sends for the SHA1 hash.
> Whereas, neutering the solution of SHA1 breaks the ability for it to
> support any hardware that has a TPM1.2, of which there are still many in
> use.
>
> V/r,
> Daniel P. Smith
>
>
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-18 18:43 ` Andy Lutomirski
@ 2024-11-18 18:50 ` Andy Lutomirski
2024-11-18 19:12 ` James Bottomley
1 sibling, 0 replies; 113+ messages in thread
From: Andy Lutomirski @ 2024-11-18 18:50 UTC (permalink / raw)
To: Daniel P. Smith
Cc: James Bottomley, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg, nivedita,
herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Mon, Nov 18, 2024 at 10:43 AM Andy Lutomirski <luto@amacapital.net> wrote:
>
> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
> exclusively use TPM2_PCR_Event. I would expect that passing, say, the
> entire kernel image to TPM2_PCR_Event would be a big mistake, so
> instead Linux should hash the relevant data with a reasonable
> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
> not* include SHA-1, and may or may not be configurable at build time
> to include things like SM3), concatenate them, and pass that to
> TPM2_PCR_Event. And Linux should make the value that it passed to
> TPM2_PCR_Event readily accessible to software using it, and should
> also include some straightforward tooling to calculate it from a given
> input so that software that wants to figure out what value to expect
> in a PCR can easily do so.
Whoops, putting on my "knows a bit about crypto" hat for a second,
this is not great, as the algorithms aren't distinguished, and one
could hypothetically add a wildly insecure hash to the list that
breaks it. Instead it should be something like:
"SHA-384 48 bytes: [the SHA-384 data], someotherhash 71 bytes: [other
data], ..."
It might even be polite to include some human readable text that also
indicates what got hashed, e.g. "initramfs", so that anyone reading
the event log can see what got hashed. On that note, maybe making the
whole thing human readable and using base64 would be nice:
"initramfs\nsha384 [base64 data]\nblake3 [base64 data]\nsm3 [base64 data]"
Whatever format is used should be unambiguously parseable. And who
knows, maybe there's already some kind of industry standard for how
TPM-using software is expected to behave here.
>
> And then software that wants to use a SHA-1 bank will work every bit
> as well as it would if Linux actually implemented it, but Linux can
> happily not implement it, and even users of oddball algorithms that
> Linux has never heard of will get secure behavior.
>
> (Why SHA-384? Because it's mandatory in the TPM Client profile, and
> anyone who's happy with SHA-256 should also be willing to accept
> SHA-384.)
>
> >
> > Even with these clarifications, the conclusion does not change. If the
> > firmware enables SHA1, there is nothing that can be done to disable or
> > block its usage from the user. Linux Secure Launch sending measurements
> > to all the banks that the hardware used to start the DRTM chain does not
> > create a vulnerability in and of itself. The user is free to leverage
> > the SHA1 bank in any of the TPM's Integrity Collection suite of
> > operations, regardless of what Secure Launch sends for the SHA1 hash.
> > Whereas, neutering the solution of SHA1 breaks the ability for it to
> > support any hardware that has a TPM1.2, of which there are still many in
> > use.
> >
> > V/r,
> > Daniel P. Smith
> >
> >
>
>
> --
> Andy Lutomirski
> AMA Capital Management, LLC
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-18 18:43 ` Andy Lutomirski
2024-11-18 18:50 ` Andy Lutomirski
@ 2024-11-18 19:12 ` James Bottomley
2024-11-18 20:02 ` Andy Lutomirski
1 sibling, 1 reply; 113+ messages in thread
From: James Bottomley @ 2024-11-18 19:12 UTC (permalink / raw)
To: Andy Lutomirski, Daniel P. Smith
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
> exclusively use TPM2_PCR_Event. I would expect that passing, say,
> the entire kernel image to TPM2_PCR_Event would be a big mistake, so
> instead Linux should hash the relevant data with a reasonable
> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
> not* include SHA-1, and may or may not be configurable at build time
> to include things like SM3), concatenate them, and pass that to
> TPM2_PCR_Event. And Linux should make the value that it passed to
> TPM2_PCR_Event readily accessible to software using it, and should
> also include some straightforward tooling to calculate it from a
> given input so that software that wants to figure out what value to
> expect in a PCR can easily do so.
Just for clarity, this is about how the agile log format works. Each
event entry in the log contains a list of bank hashes and the extends
occur in log event order, so replaying a log should get you to exactly
the head PCR value of each bank. If a log doesn't understand a format,
like SM3, then an entry for it doesn't appear in the log and a replay
says nothing about the PCR value.
For some events, the hash is actually the hash of the event entry
itself and for others, the entry is just a hint and the hash is of
something else.
I think part of the confusion stems from the twofold issues of PCRs: at
their simplest they were expected to provide the end policy values
(this turns out to be problematic because there are quite a few ways,
that will produce different end PCR values, that a system could get to
the same state). If you don't trust a bank (or don't know about it),
you don't code it into a required policy statement and its value
becomes irrelevant. If, as most remote attestation systems do, you're
analysing log entries, then you can calculate end PCR points for all
banks mentioned in the log and you could ask the TPM to quote all of
them. In practice, you tend to pick a bank you prefer (sha256 usually)
and quote only that. Again, if a bank doesn't appear in the log,
you're not going to ask for a quote from it, so what it contains is
irrelevant to the analysis of the log.
The point being that in neither case would the fact that boot software
failed to extend a bank it didn't have a hash for result in some type
of compromise.
Note that one of the things you can do with the log (because the
entries are separable) is strip out all the hashes for a bank.
However, the remote is likely to refuse to accept the log if you, say,
strip the sha256 ones because you think a collision allows you to fake
a sha1 log because it would know you should have had sha256 entries as
well.
By the way, the only modern hash you can rely on a TPM2 having is
sha256. Most of the older ones don't have sha384. They all do have
sha1 for backwards compatibility with TPM1.2
James
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-18 19:12 ` James Bottomley
@ 2024-11-18 20:02 ` Andy Lutomirski
2024-11-21 20:11 ` ross.philipson
2024-12-12 19:56 ` Daniel P. Smith
0 siblings, 2 replies; 113+ messages in thread
From: Andy Lutomirski @ 2024-11-18 20:02 UTC (permalink / raw)
To: James Bottomley
Cc: Daniel P. Smith, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg, nivedita,
herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Mon, Nov 18, 2024 at 11:12 AM James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
> > Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
> > exclusively use TPM2_PCR_Event. I would expect that passing, say,
> > the entire kernel image to TPM2_PCR_Event would be a big mistake, so
> > instead Linux should hash the relevant data with a reasonable
> > suggestion of hashes (which includes, mandatorily, SHA-384 and *does
> > not* include SHA-1, and may or may not be configurable at build time
> > to include things like SM3), concatenate them, and pass that to
> > TPM2_PCR_Event. And Linux should make the value that it passed to
> > TPM2_PCR_Event readily accessible to software using it, and should
> > also include some straightforward tooling to calculate it from a
> > given input so that software that wants to figure out what value to
> > expect in a PCR can easily do so.
>
> Just for clarity, this is about how the agile log format works. Each
> event entry in the log contains a list of bank hashes and the extends
> occur in log event order, so replaying a log should get you to exactly
> the head PCR value of each bank. If a log doesn't understand a format,
> like SM3, then an entry for it doesn't appear in the log and a replay
> says nothing about the PCR value.
I have no idea what the "agile log format" is or what all the formats
in existence are. I found section 4.2.4 here:
https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_CEL_v1_r0p41_pub.pdf
It says:
This field contains the list of the digest values Extended. The Extend
method varies with TPM command, so there is
no uniform meaning of TPM Extend in this instance, and separate
descriptions are unavoidable. If using the
TPM2_PCR_Extend command, this field is the data sent to the TPM (i.e.,
not the resulting value of the PCR after the
TPM2_PCR_Extend command completes). If using the TPM2_PCR_Event
command, this field contains the digest
structure returned by the TPM2_PCR_Event command (that contains the
digest(s) submitted to each PCR bank as
the internal Extend operation). This field SHALL contain the
information from the TPML_DIGEST_VALUES used in
the Extend operation.
So we're logging the values with which we extend the PCRs. Once upon
a time, someone decided it was okay to skip extending a PCR bank:
https://google.github.io/security-research/pocs/bios/tpm-carte-blanche/writeup.html
and it was not a great idea.
There seem to be six (!) currently defined hashes: SHA1, SHA256,
SHA384, SHA512, SM2 and SM3. I haven't spotted anything promising not
to add more. It seems to be that Linux really really ought to:
(a) extend all banks. Not all banks that the maintainers like, and
not all banks that the maintainers knew about when having this
discussion. *All* banks. That means TPM2_PCR_Event(). (Or we refuse
to boot if there's a bank we don't like.)
(b) Make a best effort to notice if something is wrong with the TPM
and/or someone is MITMing us and messing with us. That means
computing the hash algorithms we actually support and checking whether
TPM2_PCR_Event() returns the right thing. I'm not seeing a specific
attack that seems likely that this prevents, but it does seem like
decent defense in depth, and if someone chooses to provision a machine
by reading its event log and then subsequently getting an attestation
that a future event log matches what was read, then avoiding letting
an attacker who temporarily controls the TPM connection from
corrupting the results seems wise. And I don't see anything at all
that we gain by removing a check that (TPM's reported SHA1 == what we
calculated) in the name of "not supporting SHA1") other than a few
hundred bytes of object code. (And yes, SHA1 is much more likely to
be supported than SM3, so it's not absurd to implement SHA1 and not
implement SM3.)
>
> For some events, the hash is actually the hash of the event entry
> itself and for others, the entry is just a hint and the hash is of
> something else.
>
> I think part of the confusion stems from the twofold issues of PCRs: at
> their simplest they were expected to provide the end policy values
> (this turns out to be problematic because there are quite a few ways,
> that will produce different end PCR values, that a system could get to
> the same state). If you don't trust a bank (or don't know about it),
> you don't code it into a required policy statement and its value
> becomes irrelevant.
I think that "you" refers to multiple entities, and this is a problem.
If the vendor of an attestation-dependent thing trusts SM3 but *Linux*
does not like SM3, then the vendor's software should not become wildly
insecure because Linux does not like SM3. And, as that 2004 CVE
shows, even two groups that are nominally associated with Microsoft
can disagree on which banks they like, causing a vulnerability.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-18 20:02 ` Andy Lutomirski
@ 2024-11-21 20:11 ` ross.philipson
2024-11-21 20:54 ` Andy Lutomirski
2024-12-12 19:56 ` Daniel P. Smith
1 sibling, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-11-21 20:11 UTC (permalink / raw)
To: Andy Lutomirski, James Bottomley
Cc: Daniel P. Smith, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 11/18/24 12:02 PM, Andy Lutomirski wrote:
> On Mon, Nov 18, 2024 at 11:12 AM James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
>>
>> On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
>>> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
>>> exclusively use TPM2_PCR_Event. I would expect that passing, say,
>>> the entire kernel image to TPM2_PCR_Event would be a big mistake, so
>>> instead Linux should hash the relevant data with a reasonable
>>> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
>>> not* include SHA-1, and may or may not be configurable at build time
>>> to include things like SM3), concatenate them, and pass that to
>>> TPM2_PCR_Event. And Linux should make the value that it passed to
>>> TPM2_PCR_Event readily accessible to software using it, and should
>>> also include some straightforward tooling to calculate it from a
>>> given input so that software that wants to figure out what value to
>>> expect in a PCR can easily do so.
>>
>> Just for clarity, this is about how the agile log format works. Each
>> event entry in the log contains a list of bank hashes and the extends
>> occur in log event order, so replaying a log should get you to exactly
>> the head PCR value of each bank. If a log doesn't understand a format,
>> like SM3, then an entry for it doesn't appear in the log and a replay
>> says nothing about the PCR value.
>
> I have no idea what the "agile log format" is or what all the formats
> in existence are. I found section 4.2.4 here:
>
> https://urldefense.com/v3/__https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_CEL_v1_r0p41_pub.pdf__;!!ACWV5N9M2RV99hQ!Iw9aAHcJMT6j3t_DSb7cOk8iWy8VJYkJOlGQ_gtLUz0XwPcIZclY4I8GZJ5VP4OScLjBaz3RX1QlGGBWWZw$
>
> It says:
>
> This field contains the list of the digest values Extended. The Extend
> method varies with TPM command, so there is
> no uniform meaning of TPM Extend in this instance, and separate
> descriptions are unavoidable. If using the
> TPM2_PCR_Extend command, this field is the data sent to the TPM (i.e.,
> not the resulting value of the PCR after the
> TPM2_PCR_Extend command completes). If using the TPM2_PCR_Event
> command, this field contains the digest
> structure returned by the TPM2_PCR_Event command (that contains the
> digest(s) submitted to each PCR bank as
> the internal Extend operation). This field SHALL contain the
> information from the TPML_DIGEST_VALUES used in
> the Extend operation.
>
> So we're logging the values with which we extend the PCRs. Once upon
> a time, someone decided it was okay to skip extending a PCR bank:
>
> https://urldefense.com/v3/__https://google.github.io/security-research/pocs/bios/tpm-carte-blanche/writeup.html__;!!ACWV5N9M2RV99hQ!Iw9aAHcJMT6j3t_DSb7cOk8iWy8VJYkJOlGQ_gtLUz0XwPcIZclY4I8GZJ5VP4OScLjBaz3RX1QlKxD4S1w$
>
> and it was not a great idea.
>
> There seem to be six (!) currently defined hashes: SHA1, SHA256,
> SHA384, SHA512, SM2 and SM3. I haven't spotted anything promising not
> to add more. It seems to be that Linux really really ought to:
>
> (a) extend all banks. Not all banks that the maintainers like, and
> not all banks that the maintainers knew about when having this
> discussion. *All* banks. That means TPM2_PCR_Event(). (Or we refuse
> to boot if there's a bank we don't like.)
>
> (b) Make a best effort to notice if something is wrong with the TPM
> and/or someone is MITMing us and messing with us. That means
> computing the hash algorithms we actually support and checking whether
> TPM2_PCR_Event() returns the right thing. I'm not seeing a specific
> attack that seems likely that this prevents, but it does seem like
> decent defense in depth, and if someone chooses to provision a machine
> by reading its event log and then subsequently getting an attestation
> that a future event log matches what was read, then avoiding letting
> an attacker who temporarily controls the TPM connection from
> corrupting the results seems wise. And I don't see anything at all
> that we gain by removing a check that (TPM's reported SHA1 == what we
> calculated) in the name of "not supporting SHA1") other than a few
> hundred bytes of object code. (And yes, SHA1 is much more likely to
> be supported than SM3, so it's not absurd to implement SHA1 and not
> implement SM3.)
>
>>
>> For some events, the hash is actually the hash of the event entry
>> itself and for others, the entry is just a hint and the hash is of
>> something else.
>>
>> I think part of the confusion stems from the twofold issues of PCRs: at
>> their simplest they were expected to provide the end policy values
>> (this turns out to be problematic because there are quite a few ways,
>> that will produce different end PCR values, that a system could get to
>> the same state). If you don't trust a bank (or don't know about it),
>> you don't code it into a required policy statement and its value
>> becomes irrelevant.
>
> I think that "you" refers to multiple entities, and this is a problem.
>
> If the vendor of an attestation-dependent thing trusts SM3 but *Linux*
> does not like SM3, then the vendor's software should not become wildly
> insecure because Linux does not like SM3. And, as that 2004 CVE
> shows, even two groups that are nominally associated with Microsoft
> can disagree on which banks they like, causing a vulnerability.
Thanks everyone for all the feedback and discussions on this. I
understand it is important and perhaps the Linux TPM code should be
modified to do the extend operations differently but this seems like it
is outside the scope of our Secure Launch feature patch set.
As far as our patch series goes, we have done the things that were asked
of us like documenting SHA-1 usage, fixing comments and commit message
and breaking up the original patch into two (one for SHA-1 and one for
SHA-256). It seems we should be able to submit our next version at this
point.
Thanks
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-21 20:11 ` ross.philipson
@ 2024-11-21 20:54 ` Andy Lutomirski
2024-11-21 22:42 ` Andy Lutomirski
0 siblings, 1 reply; 113+ messages in thread
From: Andy Lutomirski @ 2024-11-21 20:54 UTC (permalink / raw)
To: ross.philipson
Cc: James Bottomley, Daniel P. Smith, Thomas Gleixner,
Eric W. Biederman, Eric Biggers, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
mingo, bp, hpa, dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Thu, Nov 21, 2024 at 12:11 PM <ross.philipson@oracle.com> wrote:
>
> On 11/18/24 12:02 PM, Andy Lutomirski wrote:
> > If the vendor of an attestation-dependent thing trusts SM3 but *Linux*
> > does not like SM3, then the vendor's software should not become wildly
> > insecure because Linux does not like SM3. And, as that 2004 CVE
> > shows, even two groups that are nominally associated with Microsoft
> > can disagree on which banks they like, causing a vulnerability.
>
> Thanks everyone for all the feedback and discussions on this. I
> understand it is important and perhaps the Linux TPM code should be
> modified to do the extend operations differently but this seems like it
> is outside the scope of our Secure Launch feature patch set.
It's absolutely not outside the scope. Look, this is quoted verbatim
from your patchset (v11, but I don't think this has materially
changed):
+ /* Early SL code ensured there was a max count of 2 digests */
+ for (i = 0; i < event->count; i++) {
+ dptr = (u8 *)alg_id_field + sizeof(u16);
+
+ for (j = 0; j < tpm->nr_allocated_banks; j++) {
+ if (digests[j].alg_id != *alg_id_field)
+ continue;
^^^^^^^^^^^^^^^^^^^^^ excuse me?
+
+ switch (digests[j].alg_id) {
+ case TPM_ALG_SHA256:
+ memcpy(&digests[j].digest[0], dptr,
+ SHA256_DIGEST_SIZE);
+ alg_id_field = (u16 *)((u8 *)alg_id_field +
+ SHA256_DIGEST_SIZE + sizeof(u16));
+ break;
+ case TPM_ALG_SHA1:
+ memcpy(&digests[j].digest[0], dptr,
+ SHA1_DIGEST_SIZE);
+ alg_id_field = (u16 *)((u8 *)alg_id_field +
+ SHA1_DIGEST_SIZE + sizeof(u16));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ ret = tpm_pcr_extend(tpm, event->pcr_idx, digests);
+ if (ret) {
+ pr_err("Error extending TPM20 PCR, result: %d\n", ret);
+ slaunch_txt_reset(txt, "Failed to extend TPM20 PCR\n",
+ SL_ERROR_TPM_EXTEND);
+ }
I haven't even tried to see what happens if there are more than two
allocated banks, but regardless, that 'continue' statement is a
vulnerability, and it's introduced in the patchset. I'm not the
maintainer of this code, but I would NAK this.
I'm sure there's some reason that the TPM spec even makes code like
this possible, but it sure looks like the TPM2_PCR_Event operation
exists more or less to avoid this vulnerability. I think you should
either use it or you should explain, convincingly, why Linux should
add code that does not use it and thus has a vulnerability in certain,
entirely plausible, firmware configurations.
This is brand new code that is explicitly security code. I don't
think it's valid to spell "crud, we can't handle this case at all, and
failing to handle it is a security vulnerability" as "continue". If
*I* were writing this code, I would use TPM2_PCR_Event, which is
entirely immune to this particular failure as far as I can see.
--Andy
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-21 20:54 ` Andy Lutomirski
@ 2024-11-21 22:42 ` Andy Lutomirski
2024-11-22 23:37 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Andy Lutomirski @ 2024-11-21 22:42 UTC (permalink / raw)
To: ross.philipson
Cc: James Bottomley, Daniel P. Smith, Thomas Gleixner,
Eric W. Biederman, Eric Biggers, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
mingo, bp, hpa, dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Thu, Nov 21, 2024 at 12:54 PM Andy Lutomirski <luto@amacapital.net> wrote:
>
> On Thu, Nov 21, 2024 at 12:11 PM <ross.philipson@oracle.com> wrote:
> >
> > On 11/18/24 12:02 PM, Andy Lutomirski wrote:
>
> > > If the vendor of an attestation-dependent thing trusts SM3 but *Linux*
> > > does not like SM3, then the vendor's software should not become wildly
> > > insecure because Linux does not like SM3. And, as that 2004 CVE
> > > shows, even two groups that are nominally associated with Microsoft
> > > can disagree on which banks they like, causing a vulnerability.
> >
> > Thanks everyone for all the feedback and discussions on this. I
> > understand it is important and perhaps the Linux TPM code should be
> > modified to do the extend operations differently but this seems like it
> > is outside the scope of our Secure Launch feature patch set.
>
> It's absolutely not outside the scope. Look, this is quoted verbatim
> from your patchset (v11, but I don't think this has materially
> changed):
... I apologize -- I've misread the code. That code is still wrong, I
think, but for an entirely different reason:
>
> + /* Early SL code ensured there was a max count of 2 digests */
> + for (i = 0; i < event->count; i++) {
> + dptr = (u8 *)alg_id_field + sizeof(u16);
> +
> + for (j = 0; j < tpm->nr_allocated_banks; j++) {
> + if (digests[j].alg_id != *alg_id_field)
> + continue;
>
> ^^^^^^^^^^^^^^^^^^^^^ excuse me?
>
> +
> + switch (digests[j].alg_id) {
> + case TPM_ALG_SHA256:
> + memcpy(&digests[j].digest[0], dptr,
> + SHA256_DIGEST_SIZE);
> + alg_id_field = (u16 *)((u8 *)alg_id_field +
> + SHA256_DIGEST_SIZE + sizeof(u16));
> + break;
> + case TPM_ALG_SHA1:
> + memcpy(&digests[j].digest[0], dptr,
> + SHA1_DIGEST_SIZE);
> + alg_id_field = (u16 *)((u8 *)alg_id_field +
> + SHA1_DIGEST_SIZE + sizeof(u16));
> + break;
> + default:
> + break;
> + }
> + }
> + }
If we fall off the end of the loop, we never increase alg_id_field,
and subsequent iterations will malfunction. But we apparently will
write zeros (or fail?) if we have an unsupported algorithm, because we
are asking to extend all allocated banks. I think. This code is
gross. It's plausible that this whole sequence is impossible unless
something malicious is going on.
Also, and I'm sort of replying to the wrong patch here, how
trustworthy is the data that's used to populate tpm_algs in the stub?
I don't think the results will be very pretty if tpm_algs ends up
being incorrect.
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-21 22:42 ` Andy Lutomirski
@ 2024-11-22 23:37 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-11-22 23:37 UTC (permalink / raw)
To: Andy Lutomirski
Cc: James Bottomley, Daniel P. Smith, Thomas Gleixner,
Eric W. Biederman, Eric Biggers, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu,
mingo, bp, hpa, dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg,
nivedita, herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On 11/21/24 2:42 PM, Andy Lutomirski wrote:
> On Thu, Nov 21, 2024 at 12:54 PM Andy Lutomirski <luto@amacapital.net> wrote:
>>
>> On Thu, Nov 21, 2024 at 12:11 PM <ross.philipson@oracle.com> wrote:
>>>
>>> On 11/18/24 12:02 PM, Andy Lutomirski wrote:
>>
>>>> If the vendor of an attestation-dependent thing trusts SM3 but *Linux*
>>>> does not like SM3, then the vendor's software should not become wildly
>>>> insecure because Linux does not like SM3. And, as that 2004 CVE
>>>> shows, even two groups that are nominally associated with Microsoft
>>>> can disagree on which banks they like, causing a vulnerability.
>>>
>>> Thanks everyone for all the feedback and discussions on this. I
>>> understand it is important and perhaps the Linux TPM code should be
>>> modified to do the extend operations differently but this seems like it
>>> is outside the scope of our Secure Launch feature patch set.
>>
>> It's absolutely not outside the scope. Look, this is quoted verbatim
>> from your patchset (v11, but I don't think this has materially
>> changed):
>
Concerning my previous response, I realized that I did not fully
understand what you were suggesting/proposing so I am sorry about that.
You are correct that addressing this is within the scope of what we are
doing. I have reread all the emails again and I/we now understand what
you are saying.
We are now exploring how we might use TPM2_PCR_Event, whether it
introduces other issues with respect to how TXT/ACM might behave and
what would be needed to adopt this approach. More to come on that front.
I will mention that the TPM code in the Linux kernel does not currently
support the TPM2_PCR_Event command. The functionality needs to be added
and that needs buy in from the TPM maintainers (probably guidance too).
A bit more below to clarify a few things...
>
> ... I apologize -- I've misread the code. That code is still wrong, I
> think, but for an entirely different reason:
>
>>
>> + /* Early SL code ensured there was a max count of 2 digests */
>> + for (i = 0; i < event->count; i++) {
>> + dptr = (u8 *)alg_id_field + sizeof(u16);
>> +
>> + for (j = 0; j < tpm->nr_allocated_banks; j++) {
>> + if (digests[j].alg_id != *alg_id_field)
>> + continue;
>>
>> ^^^^^^^^^^^^^^^^^^^^^ excuse me?
>>
>> +
>> + switch (digests[j].alg_id) {
>> + case TPM_ALG_SHA256:
>> + memcpy(&digests[j].digest[0], dptr,
>> + SHA256_DIGEST_SIZE);
>> + alg_id_field = (u16 *)((u8 *)alg_id_field +
>> + SHA256_DIGEST_SIZE + sizeof(u16));
>> + break;
>> + case TPM_ALG_SHA1:
>> + memcpy(&digests[j].digest[0], dptr,
>> + SHA1_DIGEST_SIZE);
>> + alg_id_field = (u16 *)((u8 *)alg_id_field +
>> + SHA1_DIGEST_SIZE + sizeof(u16));
>> + break;
>> + default:
>> + break;
>> + }
>> + }
>> + }
>
> If we fall off the end of the loop, we never increase alg_id_field,
> and subsequent iterations will malfunction. But we apparently will
> write zeros (or fail?) if we have an unsupported algorithm, because we
> are asking to extend all allocated banks. I think. This code is
> gross. It's plausible that this whole sequence is impossible unless
> something malicious is going on.
Noted, there does look like there is an issue there. Thank you for the
analysis.
>
> Also, and I'm sort of replying to the wrong patch here, how
> trustworthy is the data that's used to populate tpm_algs in the stub?
> I don't think the results will be very pretty if tpm_algs ends up
> being incorrect.
We gather the list of algorithms used from the DRTM event log which the
TXT/ACM phase initializes and begins populating. One thing to note here
is that in the early setup kernel stub code, we would fail to boot if we
saw an algorithm we did not support so we would not reach a state where
we were simply ignoring an active bank as you mentioned in an earlier
reply. But I also understand your point about limiting the functionality
to just a subset of algorithms.
Thank you for your feedback,
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-11-18 20:02 ` Andy Lutomirski
2024-11-21 20:11 ` ross.philipson
@ 2024-12-12 19:56 ` Daniel P. Smith
2024-12-12 22:30 ` Andy Lutomirski
1 sibling, 1 reply; 113+ messages in thread
From: Daniel P. Smith @ 2024-12-12 19:56 UTC (permalink / raw)
To: Andy Lutomirski, James Bottomley
Cc: Thomas Gleixner, Eric W. Biederman, Eric Biggers, Ross Philipson,
linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, mingo, bp, hpa, dave.hansen, ardb, mjg59,
peterhuewe, jarkko, jgg, nivedita, herbert, davem, corbet, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
Hey Luto!
Let me try to address your concerns below.
On 11/18/24 15:02, Andy Lutomirski wrote:
> On Mon, Nov 18, 2024 at 11:12 AM James Bottomley
> <James.Bottomley@hansenpartnership.com> wrote:
>>
>> On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
>>> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
>>> exclusively use TPM2_PCR_Event. I would expect that passing, say,
>>> the entire kernel image to TPM2_PCR_Event would be a big mistake, so
>>> instead Linux should hash the relevant data with a reasonable
>>> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
>>> not* include SHA-1, and may or may not be configurable at build time
>>> to include things like SM3), concatenate them, and pass that to
>>> TPM2_PCR_Event. And Linux should make the value that it passed to
>>> TPM2_PCR_Event readily accessible to software using it, and should
>>> also include some straightforward tooling to calculate it from a
>>> given input so that software that wants to figure out what value to
>>> expect in a PCR can easily do so.
>>
>> Just for clarity, this is about how the agile log format works. Each
>> event entry in the log contains a list of bank hashes and the extends
>> occur in log event order, so replaying a log should get you to exactly
>> the head PCR value of each bank. If a log doesn't understand a format,
>> like SM3, then an entry for it doesn't appear in the log and a replay
>> says nothing about the PCR value.
>
> I have no idea what the "agile log format" is or what all the formats
> in existence are. I found section 4.2.4 here:
>
> https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_CEL_v1_r0p41_pub.pdf
>
> It says:
>
> This field contains the list of the digest values Extended. The Extend
> method varies with TPM command, so there is
> no uniform meaning of TPM Extend in this instance, and separate
> descriptions are unavoidable. If using the
> TPM2_PCR_Extend command, this field is the data sent to the TPM (i.e.,
> not the resulting value of the PCR after the
> TPM2_PCR_Extend command completes). If using the TPM2_PCR_Event
> command, this field contains the digest
> structure returned by the TPM2_PCR_Event command (that contains the
> digest(s) submitted to each PCR bank as
> the internal Extend operation). This field SHALL contain the
> information from the TPML_DIGEST_VALUES used in
> the Extend operation.
Let me start with providing background on the two measurement policies
that is implemented by Intel TXT (from Intel TXT Developers Guide):
- Maximum Agility PCR Extend Policy: ACM can support algorithm agile
commands TPM2_PCR_Event; TPM2_HashSequenceStart; TPM2_HashUpdate;
TPM2_EventSequenceComplete. When this policy is selected, ACM will use
the commands above if not all PCR algorithms are covered by embedded set
of algorithms and will extend all existing PCR banks. Side effect of
this policy is possible performance loss.
‒ Maximum Performance PCR Extend Policy: ACM can support several hash
algorithms via embedded SW. When this policy is selected, ACM will use
embedded SW to compute hashes and then will use TPM2_PCR_Extend commands
to extend them into PCRs. If PCRs utilizing hash algorithms not
supported by SW are discovered, they will be capped with “1” value. This
policy, when selected, will ensure maximum possible performance but has
side effect of possible capping of some of the PCRs.
Allow me to clarify/expand on the last statement in Maximum Agility.
There is almost certainly a performance loss as anything larger than
1024 bytes, for example the Linux kernel, the ACM will bit-banging the
bytes to the TPM using the TPM2_Hash* functions.
Before addressing the next point, I would also clarify how the D-CRTM
measurement taken by the CPU is done. It uses the _TPM_HASH_* functions,
Section 22.9 of TPM2 Commands specification, to store SHA256(SINIT ACM)
| EDX into all active PCR banks. For clarity, when this done, EDX holds
the 4-byte value of the SENTER parameters for which 0 is the only valid
value currently.
> So we're logging the values with which we extend the PCRs. Once upon
> a time, someone decided it was okay to skip extending a PCR bank:
>
> https://google.github.io/security-research/pocs/bios/tpm-carte-blanche/writeup.html
>
> and it was not a great idea.
Let's begin by why/how that attack occurs. The TPM Carte Blanche attack
took advantage of the fact that without BootGuard in place, the SRTM
measurements are done by the software/firmware, to include the
self-referential S-CRTM measurement. In particular, for the target
platform, it just so happens that it was possible to construct a
configuration where not a single hash would be sent to the SHA256 bank.
This allowed the attacker the ability to replay any set of measurements,
i.e. carte blanche control, into a completely empty PCR bank for which
the attestation service would accept quotes. The key to this attack
requires both, access to an empty PCR bank, and an attestation service
that will accept a quote with only the exploited bank present.
Let us return to my statements above, which will demonstrate why
TXT/DRTM completely invalidates the attack. First, as noted above, when
the CPU is processing the GETSEC[SENTER] instruction, it (the CPU) will
compute the D-CRTM as SHA256(SINIT ACM) | EDX, sending it to the TPM
using _TPM_HASH_* functions. The _TPM_HASH_* functions result in all PCR
banks to be extended with the D-CRTM value. If Maximum Performance PCR
Extend policy is in use, which is the default policy used by TrenchBoot,
any algorithm not supported by the ACM is capped by sending the value
"1" as the digest value for the extend. Therefore, after the TXT
sequence has completed and before control is given to the Linux kernel
by the ACM, all PCR banks will consist of either, the D-CRTM + all ACM
measurements, or the D-CRTM + TPM2_PCR_Extend(0x1). There will be no PCR
banks with empty DRTM PCRs, thus none of the banks would be usable for a
TPM Carte Blanche-style attack.
> There seem to be six (!) currently defined hashes: SHA1, SHA256,
> SHA384, SHA512, SM2 and SM3. I haven't spotted anything promising not
> to add more. It seems to be that Linux really really ought to:
>
> (a) extend all banks. Not all banks that the maintainers like, and
> not all banks that the maintainers knew about when having this
> discussion. *All* banks. That means TPM2_PCR_Event(). (Or we refuse
> to boot if there's a bank we don't like.)
>
> (b) Make a best effort to notice if something is wrong with the TPM
> and/or someone is MITMing us and messing with us. That means
> computing the hash algorithms we actually support and checking whether
> TPM2_PCR_Event() returns the right thing. I'm not seeing a specific
> attack that seems likely that this prevents, but it does seem like
> decent defense in depth, and if someone chooses to provision a machine
> by reading its event log and then subsequently getting an attestation
> that a future event log matches what was read, then avoiding letting
> an attacker who temporarily controls the TPM connection from
> corrupting the results seems wise. And I don't see anything at all
> that we gain by removing a check that (TPM's reported SHA1 == what we
> calculated) in the name of "not supporting SHA1") other than a few
> hundred bytes of object code. (And yes, SHA1 is much more likely to
> be supported than SM3, so it's not absurd to implement SHA1 and not
> implement SM3.)
Or,
(c) Upon initialization, cap the PCR banks with unsupported algorithms
using a well-known value.
A problem with (a) is that the result will be an unorthodox event,
PCR_EXTEND(H(H'(data))). An attestation verifier will have to be aware
of that this is being done, and have a way to determine which method was
used for each event. This creates a potentially expensive cost for any
existing attestation solutions to incorporate support for the unorthodox
event. At least for DRTM solutions, it seeks to solve a problem that TXT
does not experience.
For Linux Secure Launch, I would like to propose an alternative to what
the current logic does in the setup kernel. Specifically, Secure Launch
will trigger a TXT reset when an unsupported algorithm is encountered.
Instead, I would like to propose the adoption of (c), and have it
extends a well-known, fixed value for unsupported algorithms. Secure
Launch can leverage the fact that the TPM driver's extend function
already expects to be given digests for all active algorithms.
Therefore, it will record the well-known value, 0x01 to follow the ACM,
into the digest buffers of any algorithms that Secure Launch does not
support. This will result in the well-known value being extended each
time a measurement is recorded. This will not be a problem as no one
should be using those banks for attestation and can ignore those digests
in the event log.
I would like to note that we made a conscious design decision early on
to use the PCR performance policy approach. We weighed a variety of
security concerns, hardware availability, and the practicality of
integrating the capability into our respective efforts. I do not want
you to feel as though we are not taking your comments seriously. Ross
reached out to some their contacts, and I reached out to a colleague
with domain experience as well. From a cursory review, no one saw an
issue from a crypto standpoint, beyond some algorithm recommendations.
As we highlighted, they did caution about the resulting unorthodox
measurement that would impose a burden on attestation solutions.
Hopefully With the background and context presented, you would agree the
above is a reasonable approach. If you do have concerns, please let us know.
V/r,
Daniel P. Smith
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-12-12 19:56 ` Daniel P. Smith
@ 2024-12-12 22:30 ` Andy Lutomirski
2024-12-14 2:56 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: Andy Lutomirski @ 2024-12-12 22:30 UTC (permalink / raw)
To: Daniel P. Smith
Cc: James Bottomley, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg, nivedita,
herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Thu, Dec 12, 2024 at 11:56 AM Daniel P. Smith
<dpsmith@apertussolutions.com> wrote:
>
> Hey Luto!
>
> Let me try to address your concerns below.
>
> On 11/18/24 15:02, Andy Lutomirski wrote:
> > On Mon, Nov 18, 2024 at 11:12 AM James Bottomley
> > <James.Bottomley@hansenpartnership.com> wrote:
> >>
> >> On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
> >>> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
> >>> exclusively use TPM2_PCR_Event. I would expect that passing, say,
> >>> the entire kernel image to TPM2_PCR_Event would be a big mistake, so
> >>> instead Linux should hash the relevant data with a reasonable
> >>> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
> >>> not* include SHA-1, and may or may not be configurable at build time
> >>> to include things like SM3), concatenate them, and pass that to
> >>> TPM2_PCR_Event. And Linux should make the value that it passed to
> >>> TPM2_PCR_Event readily accessible to software using it, and should
> >>> also include some straightforward tooling to calculate it from a
> >>> given input so that software that wants to figure out what value to
> >>> expect in a PCR can easily do so.
> >>
> >> Just for clarity, this is about how the agile log format works. Each
> >> event entry in the log contains a list of bank hashes and the extends
> >> occur in log event order, so replaying a log should get you to exactly
> >> the head PCR value of each bank. If a log doesn't understand a format,
> >> like SM3, then an entry for it doesn't appear in the log and a replay
> >> says nothing about the PCR value.
> >
> > I have no idea what the "agile log format" is or what all the formats
> > in existence are. I found section 4.2.4 here:
> >
> > https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_CEL_v1_r0p41_pub.pdf
> >
> > It says:
> >
> > This field contains the list of the digest values Extended. The Extend
> > method varies with TPM command, so there is
> > no uniform meaning of TPM Extend in this instance, and separate
> > descriptions are unavoidable. If using the
> > TPM2_PCR_Extend command, this field is the data sent to the TPM (i.e.,
> > not the resulting value of the PCR after the
> > TPM2_PCR_Extend command completes). If using the TPM2_PCR_Event
> > command, this field contains the digest
> > structure returned by the TPM2_PCR_Event command (that contains the
> > digest(s) submitted to each PCR bank as
> > the internal Extend operation). This field SHALL contain the
> > information from the TPML_DIGEST_VALUES used in
> > the Extend operation.
>
>
> Let me start with providing background on the two measurement policies
> that is implemented by Intel TXT (from Intel TXT Developers Guide):
>
> - Maximum Agility PCR Extend Policy: ACM can support algorithm agile
> commands TPM2_PCR_Event; TPM2_HashSequenceStart; TPM2_HashUpdate;
> TPM2_EventSequenceComplete. When this policy is selected, ACM will use
> the commands above if not all PCR algorithms are covered by embedded set
> of algorithms and will extend all existing PCR banks. Side effect of
> this policy is possible performance loss.
>
> ‒ Maximum Performance PCR Extend Policy: ACM can support several hash
> algorithms via embedded SW. When this policy is selected, ACM will use
> embedded SW to compute hashes and then will use TPM2_PCR_Extend commands
> to extend them into PCRs. If PCRs utilizing hash algorithms not
> supported by SW are discovered, they will be capped with “1” value. This
> policy, when selected, will ensure maximum possible performance but has
> side effect of possible capping of some of the PCRs.
>
What is responsible for choosing which of these policies to use?
> Allow me to clarify/expand on the last statement in Maximum Agility.
> There is almost certainly a performance loss as anything larger than
> 1024 bytes, for example the Linux kernel, the ACM will bit-banging the
> bytes to the TPM using the TPM2_Hash* functions.
Surely, if Linux's stub started using TPM2_PCR_Event, it would first
hash any large inputs and then send the _hash_ to TPM2_PCR_Event
instead of, say, bit-banging the entire initramfs to the TPM. But
you're talking about the ACM and I'm talking about the Linux stub code
in this patchset.
But the capping-with-"1" does suggest that maybe one can actually cap
with "1" without preventing downstream software from consuming the
event log.
>
> Before addressing the next point, I would also clarify how the D-CRTM
> measurement taken by the CPU is done. It uses the _TPM_HASH_* functions,
> Section 22.9 of TPM2 Commands specification, to store SHA256(SINIT ACM)
> | EDX into all active PCR banks. For clarity, when this done, EDX holds
> the 4-byte value of the SENTER parameters for which 0 is the only valid
> value currently.
>
>
> > So we're logging the values with which we extend the PCRs. Once upon
> > a time, someone decided it was okay to skip extending a PCR bank:
> >
> > https://google.github.io/security-research/pocs/bios/tpm-carte-blanche/writeup.html
> >
> > and it was not a great idea.
>
>
> Let's begin by why/how that attack occurs. The TPM Carte Blanche attack
> took advantage of the fact that without BootGuard in place, the SRTM
> measurements are done by the software/firmware, to include the
> self-referential S-CRTM measurement. In particular, for the target
> platform, it just so happens that it was possible to construct a
> configuration where not a single hash would be sent to the SHA256 bank.
> This allowed the attacker the ability to replay any set of measurements,
> i.e. carte blanche control, into a completely empty PCR bank for which
> the attestation service would accept quotes. The key to this attack
> requires both, access to an empty PCR bank, and an attestation service
> that will accept a quote with only the exploited bank present.
>
> Let us return to my statements above, which will demonstrate why
> TXT/DRTM completely invalidates the attack. First, as noted above, when
> the CPU is processing the GETSEC[SENTER] instruction, it (the CPU) will
> compute the D-CRTM as SHA256(SINIT ACM) | EDX, sending it to the TPM
> using _TPM_HASH_* functions. The _TPM_HASH_* functions result in all PCR
> banks to be extended with the D-CRTM value. If Maximum Performance PCR
> Extend policy is in use, which is the default policy used by TrenchBoot,
> any algorithm not supported by the ACM is capped by sending the value
> "1" as the digest value for the extend. Therefore, after the TXT
> sequence has completed and before control is given to the Linux kernel
> by the ACM, all PCR banks will consist of either, the D-CRTM + all ACM
> measurements, or the D-CRTM + TPM2_PCR_Extend(0x1). There will be no PCR
> banks with empty DRTM PCRs, thus none of the banks would be usable for a
> TPM Carte Blanche-style attack.
Sure, a "carte blanche" attack in the sense that the PCRs are entirely
blank won't happen, but if any component in the chain does not extend
a bank, then an attacker can replace the code _after_ that component
without being noticed.
> (c) Upon initialization, cap the PCR banks with unsupported algorithms
> using a well-known value.
>
> A problem with (a) is that the result will be an unorthodox event,
> PCR_EXTEND(H(H'(data))). An attestation verifier will have to be aware
> of that this is being done, and have a way to determine which method was
> used for each event. This creates a potentially expensive cost for any
> existing attestation solutions to incorporate support for the unorthodox
> event. At least for DRTM solutions, it seeks to solve a problem that TXT
> does not experience.
>
> For Linux Secure Launch, I would like to propose an alternative to what
> the current logic does in the setup kernel. Specifically, Secure Launch
> will trigger a TXT reset when an unsupported algorithm is encountered.
> Instead, I would like to propose the adoption of (c), and have it
> extends a well-known, fixed value for unsupported algorithms. Secure
> Launch can leverage the fact that the TPM driver's extend function
> already expects to be given digests for all active algorithms.
> Therefore, it will record the well-known value, 0x01 to follow the ACM,
> into the digest buffers of any algorithms that Secure Launch does not
> support. This will result in the well-known value being extended each
> time a measurement is recorded. This will not be a problem as no one
> should be using those banks for attestation and can ignore those digests
> in the event log.
This seems to be at least not terrible.
Or I suppose one could use TPM_HASH_ functions? The spec for them is
somewhat impenetrable to me.
>
> I would like to note that we made a conscious design decision early on
> to use the PCR performance policy approach. We weighed a variety of
> security concerns, hardware availability, and the practicality of
> integrating the capability into our respective efforts. I do not want
> you to feel as though we are not taking your comments seriously. Ross
> reached out to some their contacts, and I reached out to a colleague
> with domain experience as well. From a cursory review, no one saw an
> issue from a crypto standpoint, beyond some algorithm recommendations.
> As we highlighted, they did caution about the resulting unorthodox
> measurement that would impose a burden on attestation solutions.
>
> Hopefully With the background and context presented, you would agree the
> above is a reasonable approach. If you do have concerns, please let us know.
>
> V/r,
> Daniel P. Smith
--
Andy Lutomirski
AMA Capital Management, LLC
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-12-12 22:30 ` Andy Lutomirski
@ 2024-12-14 2:56 ` Daniel P. Smith
0 siblings, 0 replies; 113+ messages in thread
From: Daniel P. Smith @ 2024-12-14 2:56 UTC (permalink / raw)
To: Andy Lutomirski
Cc: James Bottomley, Thomas Gleixner, Eric W. Biederman, Eric Biggers,
Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu, mingo, bp, hpa,
dave.hansen, ardb, mjg59, peterhuewe, jarkko, jgg, nivedita,
herbert, davem, corbet, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On 12/12/24 17:30, Andy Lutomirski wrote:
> On Thu, Dec 12, 2024 at 11:56 AM Daniel P. Smith
> <dpsmith@apertussolutions.com> wrote:
>>
>> Hey Luto!
>>
>> Let me try to address your concerns below.
>>
>> On 11/18/24 15:02, Andy Lutomirski wrote:
>>> On Mon, Nov 18, 2024 at 11:12 AM James Bottomley
>>> <James.Bottomley@hansenpartnership.com> wrote:
>>>>
>>>> On Mon, 2024-11-18 at 10:43 -0800, Andy Lutomirski wrote:
>>>>> Linux should not use TPM2_PCR_Extend *at all*. Instead, Linux should
>>>>> exclusively use TPM2_PCR_Event. I would expect that passing, say,
>>>>> the entire kernel image to TPM2_PCR_Event would be a big mistake, so
>>>>> instead Linux should hash the relevant data with a reasonable
>>>>> suggestion of hashes (which includes, mandatorily, SHA-384 and *does
>>>>> not* include SHA-1, and may or may not be configurable at build time
>>>>> to include things like SM3), concatenate them, and pass that to
>>>>> TPM2_PCR_Event. And Linux should make the value that it passed to
>>>>> TPM2_PCR_Event readily accessible to software using it, and should
>>>>> also include some straightforward tooling to calculate it from a
>>>>> given input so that software that wants to figure out what value to
>>>>> expect in a PCR can easily do so.
>>>>
>>>> Just for clarity, this is about how the agile log format works. Each
>>>> event entry in the log contains a list of bank hashes and the extends
>>>> occur in log event order, so replaying a log should get you to exactly
>>>> the head PCR value of each bank. If a log doesn't understand a format,
>>>> like SM3, then an entry for it doesn't appear in the log and a replay
>>>> says nothing about the PCR value.
>>>
>>> I have no idea what the "agile log format" is or what all the formats
>>> in existence are. I found section 4.2.4 here:
>>>
>>> https://trustedcomputinggroup.org/wp-content/uploads/TCG_IWG_CEL_v1_r0p41_pub.pdf
>>>
>>> It says:
>>>
>>> This field contains the list of the digest values Extended. The Extend
>>> method varies with TPM command, so there is
>>> no uniform meaning of TPM Extend in this instance, and separate
>>> descriptions are unavoidable. If using the
>>> TPM2_PCR_Extend command, this field is the data sent to the TPM (i.e.,
>>> not the resulting value of the PCR after the
>>> TPM2_PCR_Extend command completes). If using the TPM2_PCR_Event
>>> command, this field contains the digest
>>> structure returned by the TPM2_PCR_Event command (that contains the
>>> digest(s) submitted to each PCR bank as
>>> the internal Extend operation). This field SHALL contain the
>>> information from the TPML_DIGEST_VALUES used in
>>> the Extend operation.
>>
>>
>> Let me start with providing background on the two measurement policies
>> that is implemented by Intel TXT (from Intel TXT Developers Guide):
>>
>> - Maximum Agility PCR Extend Policy: ACM can support algorithm agile
>> commands TPM2_PCR_Event; TPM2_HashSequenceStart; TPM2_HashUpdate;
>> TPM2_EventSequenceComplete. When this policy is selected, ACM will use
>> the commands above if not all PCR algorithms are covered by embedded set
>> of algorithms and will extend all existing PCR banks. Side effect of
>> this policy is possible performance loss.
>>
>> ‒ Maximum Performance PCR Extend Policy: ACM can support several hash
>> algorithms via embedded SW. When this policy is selected, ACM will use
>> embedded SW to compute hashes and then will use TPM2_PCR_Extend commands
>> to extend them into PCRs. If PCRs utilizing hash algorithms not
>> supported by SW are discovered, they will be capped with “1” value. This
>> policy, when selected, will ensure maximum possible performance but has
>> side effect of possible capping of some of the PCRs.
>>
>
> What is responsible for choosing which of these policies to use?
It is setup by the Dynamic Launch Preamble (GRUB) that will invoke the
Dynamic Launch Event (GETSEC[SENTER]).
>> Allow me to clarify/expand on the last statement in Maximum Agility.
>> There is almost certainly a performance loss as anything larger than
>> 1024 bytes, for example the Linux kernel, the ACM will bit-banging the
>> bytes to the TPM using the TPM2_Hash* functions.
>
> Surely, if Linux's stub started using TPM2_PCR_Event, it would first
> hash any large inputs and then send the _hash_ to TPM2_PCR_Event
> instead of, say, bit-banging the entire initramfs to the TPM. But
> you're talking about the ACM and I'm talking about the Linux stub code
> in this patchset.
I think there might be some confusion on how this starts, let me provide
a quick, enumerated flow:
1. GRUB prepares launch environment (Linux kernel, SINIT ACM,
OsSinitData) and calls GETSEC[SENTER] instruction
2. The CPU signals PCH that DRTM has started, unlocking Locality 4
3. The CPU loads the SINIT ACM into CRAM, measures it with SHA256 and
uses _TPM_HASH_START /_TPM_HASH_DATA / _TPM_HASH / _TPM_HASH_END to
extend SHA256(ACM) | EDX into PCR17 for all PCR banks
4. The CPU then jumps into the ACM
5. The ACM does a series of actions and measurements of the system into
PCRs 17 and 18 for SHA1, SHA256, SHA384, and SM3_256 (PCR Performance
Policy)
6. The ACM then measures the "MLE", the Linux kernel in this case, using
the same algorithms
7. The ACM then caps PCRs 17 and 18 by extending 0x01 for any
unsupported algorithm the TPM supports.
8. The ACM then jumps to the Secure Launch entry point in the setup kernel
If the initramfs is external, then yes, the setup kernel would get to do
the measurement. If it is a unified kernel image, well, that whole thing
will be bit banged to the TPM by the ACM if the PCR Agile Policy is used.
> But the capping-with-"1" does suggest that maybe one can actually cap
> with "1" without preventing downstream software from consuming the
> event log.
Correct, capping the PCR should never block downstream software from
consuming the event log.
>>
>> Before addressing the next point, I would also clarify how the D-CRTM
>> measurement taken by the CPU is done. It uses the _TPM_HASH_* functions,
>> Section 22.9 of TPM2 Commands specification, to store SHA256(SINIT ACM)
>> | EDX into all active PCR banks. For clarity, when this done, EDX holds
>> the 4-byte value of the SENTER parameters for which 0 is the only valid
>> value currently.
>>
>>
>>> So we're logging the values with which we extend the PCRs. Once upon
>>> a time, someone decided it was okay to skip extending a PCR bank:
>>>
>>> https://google.github.io/security-research/pocs/bios/tpm-carte-blanche/writeup.html
>>>
>>> and it was not a great idea.
>>
>>
>> Let's begin by why/how that attack occurs. The TPM Carte Blanche attack
>> took advantage of the fact that without BootGuard in place, the SRTM
>> measurements are done by the software/firmware, to include the
>> self-referential S-CRTM measurement. In particular, for the target
>> platform, it just so happens that it was possible to construct a
>> configuration where not a single hash would be sent to the SHA256 bank.
>> This allowed the attacker the ability to replay any set of measurements,
>> i.e. carte blanche control, into a completely empty PCR bank for which
>> the attestation service would accept quotes. The key to this attack
>> requires both, access to an empty PCR bank, and an attestation service
>> that will accept a quote with only the exploited bank present.
>>
>> Let us return to my statements above, which will demonstrate why
>> TXT/DRTM completely invalidates the attack. First, as noted above, when
>> the CPU is processing the GETSEC[SENTER] instruction, it (the CPU) will
>> compute the D-CRTM as SHA256(SINIT ACM) | EDX, sending it to the TPM
>> using _TPM_HASH_* functions. The _TPM_HASH_* functions result in all PCR
>> banks to be extended with the D-CRTM value. If Maximum Performance PCR
>> Extend policy is in use, which is the default policy used by TrenchBoot,
>> any algorithm not supported by the ACM is capped by sending the value
>> "1" as the digest value for the extend. Therefore, after the TXT
>> sequence has completed and before control is given to the Linux kernel
>> by the ACM, all PCR banks will consist of either, the D-CRTM + all ACM
>> measurements, or the D-CRTM + TPM2_PCR_Extend(0x1). There will be no PCR
>> banks with empty DRTM PCRs, thus none of the banks would be usable for a
>> TPM Carte Blanche-style attack.
>
> Sure, a "carte blanche" attack in the sense that the PCRs are entirely
> blank won't happen, but if any component in the chain does not extend
> a bank, then an attacker can replace the code _after_ that component
> without being noticed.
There are two scenarios that could be considered here. The first is if
an algorithm is added to the TPM that neither the ACM nor the TPM driver
supports. The second is if an algorithm supported by the ACM and the TPM
driver is added, but not supported by Secure Launch.
In the first case, the PCR and corresponding log entries for the new
algorithm will have the D-CRTM event and Cap (0x01) event. Rendering the
bank unusable for the attacker.
For the second case, this is a "it all depends on the usage". First and
foremost, I would say it is ultimately a failure of the Attestation
Service if it evaluated algorithms that Secure Launch is not advertised
to support.
With that, let's consider the options for bad components under the
second case:
- A bad kernel image will be detected since the ACM is what measures it.
- A bad initramfs, assuming that (c) below was not implemented, then the
initramfs could add a fake entry for itself into the bank in question.
- Any component after this depends on the use case. The primary use case
currently is to combine Secure Launch with TrenchBoot additions to
u-root making it an intermediate bootloader that kexec's into the target
kernel. I bring this up because when the kexec is done, Secure Launch
does GETSEC[SEXIT]. The result being that it closes all localities
except Locality 0. They cannot be re-opened without doing a new Dynamic
Launch, which will reset them all back to 0.
I would also like to note that Secure Launch would not be the only
in-kernel capability that would have to scramble to add support for the
additional algorithm if it suddenly became available to block a Carte
Blanche attack.
>> (c) Upon initialization, cap the PCR banks with unsupported algorithms
>> using a well-known value.
>>
>> A problem with (a) is that the result will be an unorthodox event,
>> PCR_EXTEND(H(H'(data))). An attestation verifier will have to be aware
>> of that this is being done, and have a way to determine which method was
>> used for each event. This creates a potentially expensive cost for any
>> existing attestation solutions to incorporate support for the unorthodox
>> event. At least for DRTM solutions, it seeks to solve a problem that TXT
>> does not experience.
>>
>> For Linux Secure Launch, I would like to propose an alternative to what
>> the current logic does in the setup kernel. Specifically, Secure Launch
>> will trigger a TXT reset when an unsupported algorithm is encountered.
>> Instead, I would like to propose the adoption of (c), and have it
>> extends a well-known, fixed value for unsupported algorithms. Secure
>> Launch can leverage the fact that the TPM driver's extend function
>> already expects to be given digests for all active algorithms.
>> Therefore, it will record the well-known value, 0x01 to follow the ACM,
>> into the digest buffers of any algorithms that Secure Launch does not
>> support. This will result in the well-known value being extended each
>> time a measurement is recorded. This will not be a problem as no one
>> should be using those banks for attestation and can ignore those digests
>> in the event log.
>
> This seems to be at least not terrible.
With (c) in place, it would completely close off the second case for the
case when the initramfs is not part of the kernel image.
> Or I suppose one could use TPM_HASH_ functions? The spec for them is
> somewhat impenetrable to me.
Do you mean TPM2_HashSequenceStart / TPM2_SequenceUpdate /
TPM2_EventSequenceComplete? If you really meant _TPM_Hash_Start /
_TPM_Hash_Data / _TPM_Hash_End, then no, you cannot call these. They are
not sent via the Command Buffer but directly through the TPM interface.
Have a look at Section 34 of the TPM Architecture[1]. While the spec
authors wrote it generically, as if there is more than one way for an
H-CRTM to be established, the only way available for x86 is DRTM.
[1]
https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf
Ross has prepared a new version of the series using (c), which actually
reduces the size and complexity of the SL setup code. Once it has been
tested, Ross will post it so you can have some concrete code to look at
and consider the proposal.
V/r,
Daniel P. Smith
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 2:16 ` Eric Biggers
2024-05-31 13:54 ` Eric W. Biederman
@ 2024-05-31 16:18 ` ross.philipson
2024-08-27 18:14 ` Eric Biggers
2 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-05-31 16:18 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 5/30/24 7:16 PM, Eric Biggers wrote:
> On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
>> choice of hashes used lie with the platform firmware, not with
>> software, and is often outside of the users control.
>>
>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>> to safely use SHA-256 for everything else.
>>
>> The SHA-1 code here has its origins in the code from the main kernel:
>>
>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>>
>> A modified version of this code was introduced to the lib/crypto/sha1.c
>> to bring it in line with the SHA-256 code and allow it to be pulled into the
>> setup kernel in the same manner as SHA-256 is.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> Thanks. This explanation doesn't seem to have made it into the actual code or
> documentation. Can you please get it into a more permanent location?
>
> Also, can you point to where the "deliberately cap the SHA-1 PCRs" thing happens
> in the code?
>
> That paragraph is also phrased as a hypothetical, "Even if we'd prefer to use
> SHA-256-only". That implies that you do not, in fact, prefer SHA-256 only. Is
> that the case? Sure, maybe there are situations where you *have* to use SHA-1,
> but why would you not at least *prefer* SHA-256?
Yes those are fair points. We will address them and indicate we prefer
SHA-256 or better.
>
>> /*
>> * An implementation of SHA-1's compression function. Don't use in new code!
>> * You shouldn't be using SHA-1, and even if you *have* to use SHA-1, this isn't
>> * the correct way to hash something with SHA-1 (use crypto_shash instead).
>> */
>> #define SHA1_DIGEST_WORDS (SHA1_DIGEST_SIZE / 4)
>> #define SHA1_WORKSPACE_WORDS 16
>> void sha1_init(__u32 *buf);
>> void sha1_transform(__u32 *digest, const char *data, __u32 *W);
>> +void sha1(const u8 *data, unsigned int len, u8 *out);
> > Also, the comment above needs to be updated.
Ack, will address.
Thank you
>
> - Eric
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 2:16 ` Eric Biggers
2024-05-31 13:54 ` Eric W. Biederman
2024-05-31 16:18 ` ross.philipson
@ 2024-08-27 18:14 ` Eric Biggers
2024-08-28 20:14 ` ross.philipson
2 siblings, 1 reply; 113+ messages in thread
From: Eric Biggers @ 2024-08-27 18:14 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Thu, May 30, 2024 at 07:16:56PM -0700, Eric Biggers wrote:
> On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
> > From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
> >
> > For better or worse, Secure Launch needs SHA-1 and SHA-256. The
> > choice of hashes used lie with the platform firmware, not with
> > software, and is often outside of the users control.
> >
> > Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> > with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> > the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> > to safely use SHA-256 for everything else.
> >
> > The SHA-1 code here has its origins in the code from the main kernel:
> >
> > commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
> >
> > A modified version of this code was introduced to the lib/crypto/sha1.c
> > to bring it in line with the SHA-256 code and allow it to be pulled into the
> > setup kernel in the same manner as SHA-256 is.
> >
> > Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> > Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> Thanks. This explanation doesn't seem to have made it into the actual code or
> documentation. Can you please get it into a more permanent location?
I see that a new version of the patchset was sent out but this suggestion was
not taken. Are you planning to address it?
- Eric
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-27 18:14 ` Eric Biggers
@ 2024-08-28 20:14 ` ross.philipson
2024-08-28 23:13 ` Eric Biggers
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-08-28 20:14 UTC (permalink / raw)
To: Eric Biggers
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 8/27/24 11:14 AM, 'Eric Biggers' via trenchboot-devel wrote:
> On Thu, May 30, 2024 at 07:16:56PM -0700, Eric Biggers wrote:
>> On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
>>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>>
>>> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
>>> choice of hashes used lie with the platform firmware, not with
>>> software, and is often outside of the users control.
>>>
>>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>>> to safely use SHA-256 for everything else.
>>>
>>> The SHA-1 code here has its origins in the code from the main kernel:
>>>
>>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>>>
>>> A modified version of this code was introduced to the lib/crypto/sha1.c
>>> to bring it in line with the SHA-256 code and allow it to be pulled into the
>>> setup kernel in the same manner as SHA-256 is.
>>>
>>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>
>> Thanks. This explanation doesn't seem to have made it into the actual code or
>> documentation. Can you please get it into a more permanent location?
>
> I see that a new version of the patchset was sent out but this suggestion was
> not taken. Are you planning to address it?
Sorry we sort of overlooked that part of the request. We will take the
latest commit message, clean it up a little and put it in
boot/compressed/sha1.c file as a comment. I believe that is what you
would like us to do.
Thanks
Ross
>
> - Eric
>
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-08-28 20:14 ` ross.philipson
@ 2024-08-28 23:13 ` Eric Biggers
0 siblings, 0 replies; 113+ messages in thread
From: Eric Biggers @ 2024-08-28 23:13 UTC (permalink / raw)
To: ross.philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, ardb, mjg59, James.Bottomley, peterhuewe, jarkko,
jgg, luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2,
baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Wed, Aug 28, 2024 at 01:14:45PM -0700, ross.philipson@oracle.com wrote:
> On 8/27/24 11:14 AM, 'Eric Biggers' via trenchboot-devel wrote:
> > On Thu, May 30, 2024 at 07:16:56PM -0700, Eric Biggers wrote:
> > > On Thu, May 30, 2024 at 06:03:18PM -0700, Ross Philipson wrote:
> > > > From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
> > > >
> > > > For better or worse, Secure Launch needs SHA-1 and SHA-256. The
> > > > choice of hashes used lie with the platform firmware, not with
> > > > software, and is often outside of the users control.
> > > >
> > > > Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> > > > with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> > > > the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> > > > to safely use SHA-256 for everything else.
> > > >
> > > > The SHA-1 code here has its origins in the code from the main kernel:
> > > >
> > > > commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
> > > >
> > > > A modified version of this code was introduced to the lib/crypto/sha1.c
> > > > to bring it in line with the SHA-256 code and allow it to be pulled into the
> > > > setup kernel in the same manner as SHA-256 is.
> > > >
> > > > Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> > > > Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> > >
> > > Thanks. This explanation doesn't seem to have made it into the actual code or
> > > documentation. Can you please get it into a more permanent location?
> >
> > I see that a new version of the patchset was sent out but this suggestion was
> > not taken. Are you planning to address it?
>
> Sorry we sort of overlooked that part of the request. We will take the
> latest commit message, clean it up a little and put it in
> boot/compressed/sha1.c file as a comment. I believe that is what you would
> like us to do.
>
Do users of this feature need to make a decision about SHA-1? If so there needs
to be guidance in Documentation/. A comment in a .c file is not user facing.
- Eric
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-05-31 1:03 ` [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements Ross Philipson
2024-05-31 2:16 ` Eric Biggers
@ 2024-06-04 18:52 ` Jarkko Sakkinen
2024-06-04 21:02 ` ross.philipson
1 sibling, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 18:52 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
> choice of hashes used lie with the platform firmware, not with
> software, and is often outside of the users control.
>
> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> to safely use SHA-256 for everything else.
>
> The SHA-1 code here has its origins in the code from the main kernel:
>
> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>
> A modified version of this code was introduced to the lib/crypto/sha1.c
> to bring it in line with the SHA-256 code and allow it to be pulled into the
> setup kernel in the same manner as SHA-256 is.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> arch/x86/boot/compressed/Makefile | 2 +
> arch/x86/boot/compressed/early_sha1.c | 12 ++++
> include/crypto/sha1.h | 1 +
> lib/crypto/sha1.c | 81 +++++++++++++++++++++++++++
> 4 files changed, 96 insertions(+)
> create mode 100644 arch/x86/boot/compressed/early_sha1.c
>
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index e9522c6893be..3307ebef4e1b 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o
> +
> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> $(call if_changed,ld)
>
> diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c
> new file mode 100644
> index 000000000000..8a9b904a73ab
> --- /dev/null
> +++ b/arch/x86/boot/compressed/early_sha1.c
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (c) 2024 Apertus Solutions, LLC.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/linkage.h>
> +#include <linux/string.h>
> +#include <asm/boot.h>
> +#include <asm/unaligned.h>
> +
> +#include "../../../../lib/crypto/sha1.c"
}
Yep, make sense. Thinking only that should this be just sha1.c.
Comparing this to mainly drivers/firmware/efi/tpm.c, which is not
early_tpm.c where the early actually probably would make more sense
than here. Here sha1 primitive is just needed.
This is definitely a nitpick but why carry a prefix that is not
that useful, right?
> diff --git a/include/crypto/sha1.h b/include/crypto/sha1.h
> index 044ecea60ac8..d715dd5332e1 100644
> --- a/include/crypto/sha1.h
> +++ b/include/crypto/sha1.h
> @@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
> #define SHA1_WORKSPACE_WORDS 16
> void sha1_init(__u32 *buf);
> void sha1_transform(__u32 *digest, const char *data, __u32 *W);
> +void sha1(const u8 *data, unsigned int len, u8 *out);
>
> #endif /* _CRYPTO_SHA1_H */
> diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
> index 1aebe7be9401..10152125b338 100644
> --- a/lib/crypto/sha1.c
> +++ b/lib/crypto/sha1.c
> @@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
> }
> EXPORT_SYMBOL(sha1_init);
>
> +static void __sha1_transform(u32 *digest, const char *data)
> +{
> + u32 ws[SHA1_WORKSPACE_WORDS];
> +
> + sha1_transform(digest, data, ws);
> +
> + memzero_explicit(ws, sizeof(ws));
For the sake of future reference I'd carry always some inline comment
with any memzero_explicit() call site.
> +}
> +
> +static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
> +{
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> +
> + sctx->count += len;
> +
> + if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
if (unlikely((partial + len) < SHA1_BLOCK_SIZE))
goto out;
?
> + int blocks;
> +
> + if (partial) {
> + int p = SHA1_BLOCK_SIZE - partial;
> +
> + memcpy(sctx->buffer + partial, data, p);
> + data += p;
> + len -= p;
> +
> + __sha1_transform(sctx->state, sctx->buffer);
> + }
> +
> + blocks = len / SHA1_BLOCK_SIZE;
> + len %= SHA1_BLOCK_SIZE;
> +
> + if (blocks) {
> + while (blocks--) {
> + __sha1_transform(sctx->state, data);
> + data += SHA1_BLOCK_SIZE;
> + }
> + }
> + partial = 0;
> + }
> +
out:
> + if (len)
> + memcpy(sctx->buffer + partial, data, len);
Why not just memcpy() unconditionally?
> +}
> +
> +static void sha1_final(struct sha1_state *sctx, u8 *out)
> +{
> + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> + __be32 *digest = (__be32 *)out;
> + int i;
> +
> + sctx->buffer[partial++] = 0x80;
> + if (partial > bit_offset) {
> + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
> + partial = 0;
> +
> + __sha1_transform(sctx->state, sctx->buffer);
> + }
> +
> + memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> + *bits = cpu_to_be64(sctx->count << 3);
> + __sha1_transform(sctx->state, sctx->buffer);
> +
> + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
> + put_unaligned_be32(sctx->state[i], digest++);
> +
> + *sctx = (struct sha1_state){};
> +}
> +
> +void sha1(const u8 *data, unsigned int len, u8 *out)
> +{
> + struct sha1_state sctx = {0};
> +
> + sha1_init(sctx.state);
> + sctx.count = 0;
Hmm... so shouldn't C99 take care of this given the initialization
above? I'm not 100% sure here. I.e. given "= {0}", shouldn't this
already be zero?
> + sha1_update(&sctx, data, len);
> + sha1_final(&sctx, out);
> +}
> +EXPORT_SYMBOL(sha1);
> +
> MODULE_LICENSE("GPL");
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-06-04 18:52 ` Jarkko Sakkinen
@ 2024-06-04 21:02 ` ross.philipson
2024-06-04 22:40 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:02 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 11:52 AM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
>> choice of hashes used lie with the platform firmware, not with
>> software, and is often outside of the users control.
>>
>> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
>> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
>> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
>> to safely use SHA-256 for everything else.
>>
>> The SHA-1 code here has its origins in the code from the main kernel:
>>
>> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
>>
>> A modified version of this code was introduced to the lib/crypto/sha1.c
>> to bring it in line with the SHA-256 code and allow it to be pulled into the
>> setup kernel in the same manner as SHA-256 is.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> arch/x86/boot/compressed/Makefile | 2 +
>> arch/x86/boot/compressed/early_sha1.c | 12 ++++
>> include/crypto/sha1.h | 1 +
>> lib/crypto/sha1.c | 81 +++++++++++++++++++++++++++
>> 4 files changed, 96 insertions(+)
>> create mode 100644 arch/x86/boot/compressed/early_sha1.c
>>
>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>> index e9522c6893be..3307ebef4e1b 100644
>> --- a/arch/x86/boot/compressed/Makefile
>> +++ b/arch/x86/boot/compressed/Makefile
>> @@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>
>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o
>> +
>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>> $(call if_changed,ld)
>>
>> diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c
>> new file mode 100644
>> index 000000000000..8a9b904a73ab
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/early_sha1.c
>> @@ -0,0 +1,12 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (c) 2024 Apertus Solutions, LLC.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/linkage.h>
>> +#include <linux/string.h>
>> +#include <asm/boot.h>
>> +#include <asm/unaligned.h>
>> +
>> +#include "../../../../lib/crypto/sha1.c"
> }
>
> Yep, make sense. Thinking only that should this be just sha1.c.
>
> Comparing this to mainly drivers/firmware/efi/tpm.c, which is not
> early_tpm.c where the early actually probably would make more sense
> than here. Here sha1 primitive is just needed.
>
> This is definitely a nitpick but why carry a prefix that is not
> that useful, right?
I am not 100% sure what you mean here, sorry. Could you clarify about
the prefix? Do you mean why did we choose early_*? There was precedent
for doing that like early_serial_console.c.
>
>> diff --git a/include/crypto/sha1.h b/include/crypto/sha1.h
>> index 044ecea60ac8..d715dd5332e1 100644
>> --- a/include/crypto/sha1.h
>> +++ b/include/crypto/sha1.h
>> @@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
>> #define SHA1_WORKSPACE_WORDS 16
>> void sha1_init(__u32 *buf);
>> void sha1_transform(__u32 *digest, const char *data, __u32 *W);
>> +void sha1(const u8 *data, unsigned int len, u8 *out);
>>
>> #endif /* _CRYPTO_SHA1_H */
>> diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
>> index 1aebe7be9401..10152125b338 100644
>> --- a/lib/crypto/sha1.c
>> +++ b/lib/crypto/sha1.c
>> @@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
>> }
>> EXPORT_SYMBOL(sha1_init);
>>
>> +static void __sha1_transform(u32 *digest, const char *data)
>> +{
>> + u32 ws[SHA1_WORKSPACE_WORDS];
>> +
>> + sha1_transform(digest, data, ws);
>> +
>> + memzero_explicit(ws, sizeof(ws));
>
> For the sake of future reference I'd carry always some inline comment
> with any memzero_explicit() call site.
We can do that.
>
>> +}
>> +
>> +static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
>> +{
>> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
>> +
>> + sctx->count += len;
>> +
>> + if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
>
>
> if (unlikely((partial + len) < SHA1_BLOCK_SIZE))
> goto out;
>
> ?
We could do it that way. I guess it would cut down in indenting. I defer
to Daniel Smith on this...
>
>> + int blocks;
>> +
>> + if (partial) {
>> + int p = SHA1_BLOCK_SIZE - partial;
>> +
>> + memcpy(sctx->buffer + partial, data, p);
>> + data += p;
>> + len -= p;
>> +
>> + __sha1_transform(sctx->state, sctx->buffer);
>> + }
>> +
>> + blocks = len / SHA1_BLOCK_SIZE;
>> + len %= SHA1_BLOCK_SIZE;
>> +
>> + if (blocks) {
>> + while (blocks--) {
>> + __sha1_transform(sctx->state, data);
>> + data += SHA1_BLOCK_SIZE;
>> + }
>> + }
>> + partial = 0;
>> + }
>> +
>
> out:
>
>> + if (len)
>> + memcpy(sctx->buffer + partial, data, len);
>
> Why not just memcpy() unconditionally?
>
... and this.
>> +}
>> +
>> +static void sha1_final(struct sha1_state *sctx, u8 *out)
>> +{
>> + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
>> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
>> + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
>> + __be32 *digest = (__be32 *)out;
>> + int i;
>> +
>> + sctx->buffer[partial++] = 0x80;
>> + if (partial > bit_offset) {
>> + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
>> + partial = 0;
>> +
>> + __sha1_transform(sctx->state, sctx->buffer);
>> + }
>> +
>> + memset(sctx->buffer + partial, 0x0, bit_offset - partial);
>> + *bits = cpu_to_be64(sctx->count << 3);
>> + __sha1_transform(sctx->state, sctx->buffer);
>> +
>> + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
>> + put_unaligned_be32(sctx->state[i], digest++);
>> +
>> + *sctx = (struct sha1_state){};
>> +}
>> +
>> +void sha1(const u8 *data, unsigned int len, u8 *out)
>> +{
>> + struct sha1_state sctx = {0};
>> +
>> + sha1_init(sctx.state);
>> + sctx.count = 0;
>
> Hmm... so shouldn't C99 take care of this given the initialization
> above? I'm not 100% sure here. I.e. given "= {0}", shouldn't this
> already be zero?
Yes it seems so. We will look at changing that.
>
>> + sha1_update(&sctx, data, len);
>> + sha1_final(&sctx, out);
>> +}
>> +EXPORT_SYMBOL(sha1);
>> +
>> MODULE_LICENSE("GPL");
>
> BR, Jarkko
Thanks
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements
2024-06-04 21:02 ` ross.philipson
@ 2024-06-04 22:40 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:40 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 12:02 AM EEST, wrote:
> On 6/4/24 11:52 AM, Jarkko Sakkinen wrote:
> > On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
> >>
> >> For better or worse, Secure Launch needs SHA-1 and SHA-256. The
> >> choice of hashes used lie with the platform firmware, not with
> >> software, and is often outside of the users control.
> >>
> >> Even if we'd prefer to use SHA-256-only, if firmware elected to start us
> >> with the SHA-1 and SHA-256 backs active, we still need SHA-1 to parse
> >> the TPM event log thus far, and deliberately cap the SHA-1 PCRs in order
> >> to safely use SHA-256 for everything else.
> >>
> >> The SHA-1 code here has its origins in the code from the main kernel:
> >>
> >> commit c4d5b9ffa31f ("crypto: sha1 - implement base layer for SHA-1")
> >>
> >> A modified version of this code was introduced to the lib/crypto/sha1.c
> >> to bring it in line with the SHA-256 code and allow it to be pulled into the
> >> setup kernel in the same manner as SHA-256 is.
> >>
> >> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >> ---
> >> arch/x86/boot/compressed/Makefile | 2 +
> >> arch/x86/boot/compressed/early_sha1.c | 12 ++++
> >> include/crypto/sha1.h | 1 +
> >> lib/crypto/sha1.c | 81 +++++++++++++++++++++++++++
> >> 4 files changed, 96 insertions(+)
> >> create mode 100644 arch/x86/boot/compressed/early_sha1.c
> >>
> >> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> >> index e9522c6893be..3307ebef4e1b 100644
> >> --- a/arch/x86/boot/compressed/Makefile
> >> +++ b/arch/x86/boot/compressed/Makefile
> >> @@ -118,6 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> >> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> >> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> >>
> >> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o
> >> +
> >> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> >> $(call if_changed,ld)
> >>
> >> diff --git a/arch/x86/boot/compressed/early_sha1.c b/arch/x86/boot/compressed/early_sha1.c
> >> new file mode 100644
> >> index 000000000000..8a9b904a73ab
> >> --- /dev/null
> >> +++ b/arch/x86/boot/compressed/early_sha1.c
> >> @@ -0,0 +1,12 @@
> >> +// SPDX-License-Identifier: GPL-2.0
> >> +/*
> >> + * Copyright (c) 2024 Apertus Solutions, LLC.
> >> + */
> >> +
> >> +#include <linux/init.h>
> >> +#include <linux/linkage.h>
> >> +#include <linux/string.h>
> >> +#include <asm/boot.h>
> >> +#include <asm/unaligned.h>
> >> +
> >> +#include "../../../../lib/crypto/sha1.c"
> > }
> >
> > Yep, make sense. Thinking only that should this be just sha1.c.
> >
> > Comparing this to mainly drivers/firmware/efi/tpm.c, which is not
> > early_tpm.c where the early actually probably would make more sense
> > than here. Here sha1 primitive is just needed.
> >
> > This is definitely a nitpick but why carry a prefix that is not
> > that useful, right?
>
> I am not 100% sure what you mean here, sorry. Could you clarify about
> the prefix? Do you mean why did we choose early_*? There was precedent
> for doing that like early_serial_console.c.
Yep, that exactly. I'd just name as sha1.c.
>
> >
> >> diff --git a/include/crypto/sha1.h b/include/crypto/sha1.h
> >> index 044ecea60ac8..d715dd5332e1 100644
> >> --- a/include/crypto/sha1.h
> >> +++ b/include/crypto/sha1.h
> >> @@ -42,5 +42,6 @@ extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
> >> #define SHA1_WORKSPACE_WORDS 16
> >> void sha1_init(__u32 *buf);
> >> void sha1_transform(__u32 *digest, const char *data, __u32 *W);
> >> +void sha1(const u8 *data, unsigned int len, u8 *out);
> >>
> >> #endif /* _CRYPTO_SHA1_H */
> >> diff --git a/lib/crypto/sha1.c b/lib/crypto/sha1.c
> >> index 1aebe7be9401..10152125b338 100644
> >> --- a/lib/crypto/sha1.c
> >> +++ b/lib/crypto/sha1.c
> >> @@ -137,4 +137,85 @@ void sha1_init(__u32 *buf)
> >> }
> >> EXPORT_SYMBOL(sha1_init);
> >>
> >> +static void __sha1_transform(u32 *digest, const char *data)
> >> +{
> >> + u32 ws[SHA1_WORKSPACE_WORDS];
> >> +
> >> + sha1_transform(digest, data, ws);
> >> +
> >> + memzero_explicit(ws, sizeof(ws));
> >
> > For the sake of future reference I'd carry always some inline comment
> > with any memzero_explicit() call site.
>
> We can do that.
>
> >
> >> +}
> >> +
> >> +static void sha1_update(struct sha1_state *sctx, const u8 *data, unsigned int len)
> >> +{
> >> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> >> +
> >> + sctx->count += len;
> >> +
> >> + if (likely((partial + len) >= SHA1_BLOCK_SIZE)) {
> >
> >
> > if (unlikely((partial + len) < SHA1_BLOCK_SIZE))
> > goto out;
> >
> > ?
>
> We could do it that way. I guess it would cut down in indenting. I defer
> to Daniel Smith on this...
Yep, that's why I requested this.
>
> >
> >> + int blocks;
> >> +
> >> + if (partial) {
> >> + int p = SHA1_BLOCK_SIZE - partial;
> >> +
> >> + memcpy(sctx->buffer + partial, data, p);
> >> + data += p;
> >> + len -= p;
> >> +
> >> + __sha1_transform(sctx->state, sctx->buffer);
> >> + }
> >> +
> >> + blocks = len / SHA1_BLOCK_SIZE;
> >> + len %= SHA1_BLOCK_SIZE;
> >> +
> >> + if (blocks) {
> >> + while (blocks--) {
> >> + __sha1_transform(sctx->state, data);
> >> + data += SHA1_BLOCK_SIZE;
> >> + }
> >> + }
> >> + partial = 0;
> >> + }
> >> +
> >
> > out:
> >
> >> + if (len)
> >> + memcpy(sctx->buffer + partial, data, len);
> >
> > Why not just memcpy() unconditionally?
> >
>
> ... and this.
It only adds complexity with no gain.
>
> >> +}
> >> +
> >> +static void sha1_final(struct sha1_state *sctx, u8 *out)
> >> +{
> >> + const int bit_offset = SHA1_BLOCK_SIZE - sizeof(__be64);
> >> + unsigned int partial = sctx->count % SHA1_BLOCK_SIZE;
> >> + __be64 *bits = (__be64 *)(sctx->buffer + bit_offset);
> >> + __be32 *digest = (__be32 *)out;
> >> + int i;
> >> +
> >> + sctx->buffer[partial++] = 0x80;
> >> + if (partial > bit_offset) {
> >> + memset(sctx->buffer + partial, 0x0, SHA1_BLOCK_SIZE - partial);
> >> + partial = 0;
> >> +
> >> + __sha1_transform(sctx->state, sctx->buffer);
> >> + }
> >> +
> >> + memset(sctx->buffer + partial, 0x0, bit_offset - partial);
> >> + *bits = cpu_to_be64(sctx->count << 3);
> >> + __sha1_transform(sctx->state, sctx->buffer);
> >> +
> >> + for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++)
> >> + put_unaligned_be32(sctx->state[i], digest++);
> >> +
> >> + *sctx = (struct sha1_state){};
> >> +}
> >> +
> >> +void sha1(const u8 *data, unsigned int len, u8 *out)
> >> +{
> >> + struct sha1_state sctx = {0};
> >> +
> >> + sha1_init(sctx.state);
> >> + sctx.count = 0;
> >
> > Hmm... so shouldn't C99 take care of this given the initialization
> > above? I'm not 100% sure here. I.e. given "= {0}", shouldn't this
> > already be zero?
>
> Yes it seems so. We will look at changing that.
Yeah, AFAIK C99 should zero out anything remaining.
>
> >
> >> + sha1_update(&sctx, data, len);
> >> + sha1_final(&sctx, out);
> >> +}
> >> +EXPORT_SYMBOL(sha1);
> >> +
> >> MODULE_LICENSE("GPL");
> >
> > BR, Jarkko
>
> Thanks
> Ross
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 07/19] x86: Add early SHA-256 support for Secure Launch early measurements
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (5 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 06/19] x86: Add early SHA-1 support for Secure Launch early measurements Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 08/19] x86: Secure Launch kernel early boot stub Ross Philipson
` (11 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
The SHA-256 algorithm is necessary to measure configuration information into
the TPM as early as possible before using the values. This implementation
uses the established approach of #including the SHA-256 libraries directly in
the code since the compressed kernel is not uncompressed at this point.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/boot/compressed/Makefile | 2 +-
arch/x86/boot/compressed/early_sha256.c | 6 ++++++
2 files changed, 7 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/boot/compressed/early_sha256.c
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 3307ebef4e1b..9189a0e28686 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -118,7 +118,7 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
-vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o
+vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/early_sha256.c b/arch/x86/boot/compressed/early_sha256.c
new file mode 100644
index 000000000000..293742a90ddc
--- /dev/null
+++ b/arch/x86/boot/compressed/early_sha256.c
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Apertus Solutions, LLC
+ */
+
+#include "../../../../lib/crypto/sha256.c"
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (6 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 07/19] x86: Add early SHA-256 " Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 11:00 ` Ard Biesheuvel
2024-06-04 19:56 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 09/19] x86: Secure Launch kernel late " Ross Philipson
` (10 subsequent siblings)
18 siblings, 2 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
The Secure Launch (SL) stub provides the entry point for Intel TXT (and
later AMD SKINIT) to vector to during the late launch. The symbol
sl_stub_entry is that entry point and its offset into the kernel is
conveyed to the launching code using the MLE (Measured Launch
Environment) header in the structure named mle_header. The offset of the
MLE header is set in the kernel_info. The routine sl_stub contains the
very early late launch setup code responsible for setting up the basic
environment to allow the normal kernel startup_32 code to proceed. It is
also responsible for properly waking and handling the APs on Intel
platforms. The routine sl_main which runs after entering 64b mode is
responsible for measuring configuration and module information before
it is used like the boot params, the kernel command line, the TXT heap,
an external initramfs, etc.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
Documentation/arch/x86/boot.rst | 21 +
arch/x86/boot/compressed/Makefile | 3 +-
arch/x86/boot/compressed/head_64.S | 30 +
arch/x86/boot/compressed/kernel_info.S | 34 ++
arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
arch/x86/include/asm/msr-index.h | 5 +
arch/x86/include/uapi/asm/bootparam.h | 1 +
arch/x86/kernel/asm-offsets.c | 20 +
9 files changed, 1415 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/boot/compressed/sl_main.c
create mode 100644 arch/x86/boot/compressed/sl_stub.S
diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
index 4fd492cb4970..295cdf9bcbdb 100644
--- a/Documentation/arch/x86/boot.rst
+++ b/Documentation/arch/x86/boot.rst
@@ -482,6 +482,14 @@ Protocol: 2.00+
- If 1, KASLR enabled.
- If 0, KASLR disabled.
+ Bit 2 (kernel internal): SLAUNCH_FLAG
+
+ - Used internally by the setup kernel to communicate
+ Secure Launch status to kernel proper.
+
+ - If 1, Secure Launch enabled.
+ - If 0, Secure Launch disabled.
+
Bit 5 (write): QUIET_FLAG
- If 0, print early messages.
@@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
This field contains maximal allowed type for setup_data and setup_indirect structs.
+============ =================
+Field name: mle_header_offset
+Offset/size: 0x0010/4
+============ =================
+
+ This field contains the offset to the Secure Launch Measured Launch Environment
+ (MLE) header. This offset is used to locate information needed during a secure
+ late launch using Intel TXT. If the offset is zero, the kernel does not have
+ Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
+ following a success measured launch. The specific state of the processors is
+ outlined in the TXT Software Development Guide, the latest can be found here:
+ https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
+
The Image Checksum
==================
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 9189a0e28686..9076a248d4b4 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
-vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
+vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
+ $(obj)/sl_main.o $(obj)/sl_stub.o
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 1dcb794c5479..803c9e2e6d85 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
pushq $0
popfq
+#ifdef CONFIG_SECURE_LAUNCH
+ /* Ensure the relocation region is coverd by a PMR */
+ movq %rbx, %rdi
+ movl $(_bss - startup_32), %esi
+ callq sl_check_region
+#endif
+
/*
* Copy the compressed kernel to the end of our buffer
* where decompression in place becomes safe.
@@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
shrq $3, %rcx
rep stosq
+#ifdef CONFIG_SECURE_LAUNCH
+ /*
+ * Have to do the final early sl stub work in 64b area.
+ *
+ * *********** NOTE ***********
+ *
+ * Several boot params get used before we get a chance to measure
+ * them in this call. This is a known issue and we currently don't
+ * have a solution. The scratch field doesn't matter. There is no
+ * obvious way to do anything about the use of kernel_alignment or
+ * init_size though these seem low risk with all the PMR and overlap
+ * checks in place.
+ */
+ movq %r15, %rdi
+ callq sl_main
+
+ /* Ensure the decompression location is covered by a PMR */
+ movq %rbp, %rdi
+ movq output_len(%rip), %rsi
+ callq sl_check_region
+#endif
+
+ pushq %rsi
call load_stage2_idt
/* Pass boot_params to initialize_identity_maps() */
diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
index c18f07181dd5..e199b87764e9 100644
--- a/arch/x86/boot/compressed/kernel_info.S
+++ b/arch/x86/boot/compressed/kernel_info.S
@@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
/* Maximal allowed type for setup_data and setup_indirect structs. */
.long SETUP_TYPE_MAX
+ /* Offset to the MLE header structure */
+#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
+ .long rva(mle_header)
+#else
+ .long 0
+#endif
+
kernel_info_var_len_data:
/* Empty for time being... */
SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
+
+#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
+ /*
+ * The MLE Header per the TXT Specification, section 2.1
+ * MLE capabilities, see table 4. Capabilities set:
+ * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
+ * bit 1: Support for RLP wakeup using MONITOR address
+ * bit 2: The ECX register will contain the pointer to the MLE page table
+ * bit 5: TPM 1.2 family: Details/authorities PCR usage support
+ * bit 9: Supported format of TPM 2.0 event log - TCG compliant
+ */
+SYM_DATA_START(mle_header)
+ .long 0x9082ac5a /* UUID0 */
+ .long 0x74a7476f /* UUID1 */
+ .long 0xa2555c0f /* UUID2 */
+ .long 0x42b651cb /* UUID3 */
+ .long 0x00000034 /* MLE header size */
+ .long 0x00020002 /* MLE version 2.2 */
+ .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
+ .long 0x00000000 /* First valid page of MLE */
+ .long 0x00000000 /* Offset within binary of first byte of MLE */
+ .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
+ .long 0x00000227 /* Bit vector of MLE-supported capabilities */
+ .long 0x00000000 /* Starting linear address of command line (unused) */
+ .long 0x00000000 /* Ending linear address of command line (unused) */
+SYM_DATA_END(mle_header)
+#endif
diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
new file mode 100644
index 000000000000..61e9baf410fd
--- /dev/null
+++ b/arch/x86/boot/compressed/sl_main.c
@@ -0,0 +1,577 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Secure Launch early measurement and validation routines.
+ *
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ */
+
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/boot.h>
+#include <asm/msr.h>
+#include <asm/mtrr.h>
+#include <asm/processor-flags.h>
+#include <asm/asm-offsets.h>
+#include <asm/bootparam.h>
+#include <asm/bootparam_utils.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
+#include <crypto/sha1.h>
+#include <crypto/sha2.h>
+
+#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff
+
+#define SL_TPM12_LOG 1
+#define SL_TPM20_LOG 2
+
+#define SL_TPM20_MAX_ALGS 2
+
+#define SL_MAX_EVENT_DATA 64
+#define SL_TPM12_LOG_SIZE (sizeof(struct tcg_pcr_event) + \
+ SL_MAX_EVENT_DATA)
+#define SL_TPM20_LOG_SIZE (sizeof(struct tcg_pcr_event2_head) + \
+ SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
+ sizeof(struct tcg_event_field) + \
+ SL_MAX_EVENT_DATA)
+
+static void *evtlog_base;
+static u32 evtlog_size;
+static struct txt_heap_event_log_pointer2_1_element *log20_elem;
+static u32 tpm_log_ver = SL_TPM12_LOG;
+static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
+
+extern u32 sl_cpu_type;
+extern u32 sl_mle_start;
+
+static u64 sl_txt_read(u32 reg)
+{
+ return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
+}
+
+static void sl_txt_write(u32 reg, u64 val)
+{
+ writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
+}
+
+static void __noreturn sl_txt_reset(u64 error)
+{
+ /* Reading the E2STS register acts as a barrier for TXT registers */
+ sl_txt_write(TXT_CR_ERRORCODE, error);
+ sl_txt_read(TXT_CR_E2STS);
+ sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
+ sl_txt_read(TXT_CR_E2STS);
+ sl_txt_write(TXT_CR_CMD_RESET, 1);
+
+ for ( ; ; )
+ asm volatile ("hlt");
+
+ unreachable();
+}
+
+static u64 sl_rdmsr(u32 reg)
+{
+ u64 lo, hi;
+
+ asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
+
+ return (hi << 32) | lo;
+}
+
+static struct slr_table *sl_locate_and_validate_slrt(void)
+{
+ struct txt_os_mle_data *os_mle_data;
+ struct slr_table *slrt;
+ void *txt_heap;
+
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+ os_mle_data = txt_os_mle_data_start(txt_heap);
+
+ if (!os_mle_data->slrt)
+ sl_txt_reset(SL_ERROR_INVALID_SLRT);
+
+ slrt = (struct slr_table *)os_mle_data->slrt;
+
+ if (slrt->magic != SLR_TABLE_MAGIC)
+ sl_txt_reset(SL_ERROR_INVALID_SLRT);
+
+ if (slrt->architecture != SLR_INTEL_TXT)
+ sl_txt_reset(SL_ERROR_INVALID_SLRT);
+
+ return slrt;
+}
+
+static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
+{
+ struct txt_os_sinit_data *os_sinit_data;
+ void *end = base + size;
+ void *txt_heap;
+
+ if (!(sl_cpu_type & SL_CPU_INTEL))
+ return;
+
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+ os_sinit_data = txt_os_sinit_data_start(txt_heap);
+
+ if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
+ sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
+
+ /*
+ * Note that the late stub code validates that the hi PMR covers
+ * all memory above 4G. At this point the code can only check that
+ * regions are within the hi PMR but that is sufficient.
+ */
+ if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
+ if (allow_hi) {
+ if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
+ os_sinit_data->vtd_pmr_hi_size))
+ sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
+ } else {
+ sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
+ }
+ }
+
+ if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
+ sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
+}
+
+/*
+ * Some MSRs are modified by the pre-launch code including the MTRRs.
+ * The early MLE code has to restore these values. This code validates
+ * the values after they are measured.
+ */
+static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
+{
+ struct slr_txt_mtrr_state *saved_bsp_mtrrs;
+ u64 mtrr_caps, mtrr_def_type, mtrr_var;
+ struct slr_entry_intel_info *txt_info;
+ u64 misc_en_msr;
+ u32 vcnt, i;
+
+ txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
+ saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
+
+ mtrr_caps = sl_rdmsr(MSR_MTRRcap);
+ vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
+
+ if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
+ sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
+ if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
+ sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
+
+ mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
+ if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
+ sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
+
+ for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
+ mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
+ if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
+ sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
+ mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
+ if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
+ sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
+ }
+
+ misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
+ if (txt_info->saved_misc_enable_msr != misc_en_msr)
+ sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
+}
+
+static void sl_find_drtm_event_log(struct slr_table *slrt)
+{
+ struct txt_os_sinit_data *os_sinit_data;
+ struct slr_entry_log_info *log_info;
+ void *txt_heap;
+
+ log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
+ if (!log_info)
+ sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
+
+ evtlog_base = (void *)log_info->addr;
+ evtlog_size = log_info->size;
+
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+
+ /*
+ * For TPM 2.0, the event log 2.1 extended data structure has to also
+ * be located and fixed up.
+ */
+ os_sinit_data = txt_os_sinit_data_start(txt_heap);
+
+ /*
+ * Only support version 6 and later that properly handle the
+ * list of ExtDataElements in the OS-SINIT structure.
+ */
+ if (os_sinit_data->version < 6)
+ sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
+
+ /* Find the TPM2.0 logging extended heap element */
+ log20_elem = tpm20_find_log2_1_element(os_sinit_data);
+
+ /* If found, this implies TPM20 log and family */
+ if (log20_elem)
+ tpm_log_ver = SL_TPM20_LOG;
+}
+
+static void sl_validate_event_log_buffer(void)
+{
+ struct txt_os_sinit_data *os_sinit_data;
+ void *txt_heap, *txt_end;
+ void *mle_base, *mle_end;
+ void *evtlog_end;
+
+ if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
+ sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
+ evtlog_end = evtlog_base + evtlog_size;
+
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+ txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
+ os_sinit_data = txt_os_sinit_data_start(txt_heap);
+
+ mle_base = (void *)(u64)sl_mle_start;
+ mle_end = mle_base + os_sinit_data->mle_size;
+
+ /*
+ * This check is to ensure the event log buffer does not overlap with
+ * the MLE image.
+ */
+ if (evtlog_base >= mle_end && evtlog_end > mle_end)
+ goto pmr_check; /* above */
+
+ if (evtlog_end <= mle_base && evtlog_base < mle_base)
+ goto pmr_check; /* below */
+
+ sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
+
+pmr_check:
+ /*
+ * The TXT heap is protected by the DPR. If the TPM event log is
+ * inside the TXT heap, there is no need for a PMR check.
+ */
+ if (evtlog_base > txt_heap && evtlog_end < txt_end)
+ return;
+
+ sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
+}
+
+static void sl_find_event_log_algorithms(void)
+{
+ struct tcg_efi_specid_event_head *efi_head =
+ (struct tcg_efi_specid_event_head *)(evtlog_base +
+ log20_elem->first_record_offset +
+ sizeof(struct tcg_pcr_event));
+
+ if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
+ sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
+
+ memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
+ sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
+}
+
+static void sl_tpm12_log_event(u32 pcr, u32 event_type,
+ const u8 *data, u32 length,
+ const u8 *event_data, u32 event_size)
+{
+ u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
+ u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
+ struct tcg_pcr_event *pcr_event;
+ u32 total_size;
+
+ pcr_event = (struct tcg_pcr_event *)log_buf;
+ pcr_event->pcr_idx = pcr;
+ pcr_event->event_type = event_type;
+ if (length > 0) {
+ sha1(data, length, &sha1_hash[0]);
+ memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
+ }
+ pcr_event->event_size = event_size;
+ if (event_size > 0)
+ memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
+ event_data, event_size);
+
+ total_size = sizeof(struct tcg_pcr_event) + event_size;
+
+ if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
+ sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
+}
+
+static void sl_tpm20_log_event(u32 pcr, u32 event_type,
+ const u8 *data, u32 length,
+ const u8 *event_data, u32 event_size)
+{
+ u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
+ u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
+ u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
+ struct sha256_state sctx256 = {0};
+ struct tcg_pcr_event2_head *head;
+ struct tcg_event_field *event;
+ u32 total_size;
+ u16 *alg_ptr;
+ u8 *dgst_ptr;
+
+ head = (struct tcg_pcr_event2_head *)log_buf;
+ head->pcr_idx = pcr;
+ head->event_type = event_type;
+ total_size = sizeof(struct tcg_pcr_event2_head);
+ alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
+
+ for ( ; head->count < 2; head->count++) {
+ if (!tpm_algs[head->count].alg_id)
+ break;
+
+ *alg_ptr = tpm_algs[head->count].alg_id;
+ dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
+
+ if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
+ length) {
+ sha256_init(&sctx256);
+ sha256_update(&sctx256, data, length);
+ sha256_final(&sctx256, &sha256_hash[0]);
+ } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
+ length) {
+ sha1(data, length, &sha1_hash[0]);
+ }
+
+ if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
+ memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
+ total_size += SHA256_DIGEST_SIZE + sizeof(u16);
+ alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
+ } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
+ memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
+ total_size += SHA1_DIGEST_SIZE + sizeof(u16);
+ alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
+ } else {
+ sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
+ }
+ }
+
+ event = (struct tcg_event_field *)(log_buf + total_size);
+ event->event_size = event_size;
+ if (event_size > 0)
+ memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
+ total_size += sizeof(struct tcg_event_field) + event_size;
+
+ if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
+ sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
+}
+
+static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
+ const u8 *data, u32 length, const char *desc)
+{
+ if (tpm_log_ver == SL_TPM20_LOG)
+ sl_tpm20_log_event(pcr, type, data, length,
+ (const u8 *)desc, strlen(desc));
+ else
+ sl_tpm12_log_event(pcr, type, data, length,
+ (const u8 *)desc, strlen(desc));
+}
+
+static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
+ struct slr_policy_entry *entry)
+{
+ struct setup_indirect *ind;
+ struct setup_data *next;
+
+ if (!curr)
+ return NULL;
+
+ next = (struct setup_data *)(unsigned long)curr->next;
+
+ /* SETUP_INDIRECT instances have to be handled differently */
+ if (curr->type == SETUP_INDIRECT) {
+ ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
+
+ sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
+
+ sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
+ (void *)ind->addr, ind->len,
+ entry->evt_info);
+
+ return next;
+ }
+
+ sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
+ curr->len, true);
+
+ sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
+ ((u8 *)curr) + sizeof(struct setup_data),
+ curr->len,
+ entry->evt_info);
+
+ return next;
+}
+
+static void sl_extend_setup_data(struct slr_policy_entry *entry)
+{
+ struct setup_data *data;
+
+ /*
+ * Measuring the boot params measured the fixed e820 memory map.
+ * Measure any setup_data entries including e820 extended entries.
+ */
+ data = (struct setup_data *)(unsigned long)entry->entity;
+ while (data)
+ data = sl_handle_setup_data(data, entry);
+}
+
+static void sl_extend_slrt(struct slr_policy_entry *entry)
+{
+ struct slr_table *slrt = (struct slr_table *)entry->entity;
+ struct slr_entry_intel_info *intel_info;
+
+ /*
+ * In revision one of the SLRT, the only table that needs to be
+ * measured is the Intel info table. Everything else is meta-data,
+ * addresses and sizes. Note the size of what to measure is not set.
+ * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
+ * to sort out.
+ */
+ if (slrt->revision == 1) {
+ intel_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
+ if (!intel_info)
+ sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
+
+ sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
+ (void *)entry->entity, sizeof(struct slr_entry_intel_info),
+ entry->evt_info);
+ }
+}
+
+static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
+{
+ struct txt_os_mle_data *os_mle_data;
+ void *txt_heap;
+
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+ os_mle_data = txt_os_mle_data_start(txt_heap);
+
+ /*
+ * Version 1 of the OS-MLE heap structure has no fields to measure. It just
+ * has addresses and sizes and a scratch buffer.
+ */
+ if (os_mle_data->version == 1)
+ return;
+}
+
+static void sl_process_extend_policy(struct slr_table *slrt)
+{
+ struct slr_entry_policy *policy;
+ u16 i;
+
+ policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
+ if (!policy)
+ sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
+
+ for (i = 0; i < policy->nr_entries; i++) {
+ switch (policy->policy_entries[i].entity_type) {
+ case SLR_ET_SETUP_DATA:
+ sl_extend_setup_data(&policy->policy_entries[i]);
+ break;
+ case SLR_ET_SLRT:
+ sl_extend_slrt(&policy->policy_entries[i]);
+ break;
+ case SLR_ET_TXT_OS2MLE:
+ sl_extend_txt_os2mle(&policy->policy_entries[i]);
+ break;
+ case SLR_ET_UNUSED:
+ continue;
+ default:
+ sl_tpm_extend_evtlog(policy->policy_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
+ (void *)policy->policy_entries[i].entity,
+ policy->policy_entries[i].size,
+ policy->policy_entries[i].evt_info);
+ }
+ }
+}
+
+static void sl_process_extend_uefi_config(struct slr_table *slrt)
+{
+ struct slr_entry_uefi_config *uefi_config;
+ u16 i;
+
+ uefi_config = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
+
+ /* Optionally here depending on how SL kernel was booted */
+ if (!uefi_config)
+ return;
+
+ for (i = 0; i < uefi_config->nr_entries; i++) {
+ sl_tpm_extend_evtlog(uefi_config->uefi_cfg_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
+ (void *)uefi_config->uefi_cfg_entries[i].cfg,
+ uefi_config->uefi_cfg_entries[i].size,
+ uefi_config->uefi_cfg_entries[i].evt_info);
+ }
+}
+
+asmlinkage __visible void sl_check_region(void *base, u32 size)
+{
+ sl_check_pmr_coverage(base, size, false);
+}
+
+asmlinkage __visible void sl_main(void *bootparams)
+{
+ struct boot_params *bp = (struct boot_params *)bootparams;
+ struct txt_os_mle_data *os_mle_data;
+ struct slr_table *slrt;
+ void *txt_heap;
+
+ /*
+ * Ensure loadflags do not indicate a secure launch was done
+ * unless it really was.
+ */
+ bp->hdr.loadflags &= ~SLAUNCH_FLAG;
+
+ /*
+ * Currently only Intel TXT is supported for Secure Launch. Testing
+ * this value also indicates that the kernel was booted successfully
+ * through the Secure Launch entry point and is in SMX mode.
+ */
+ if (!(sl_cpu_type & SL_CPU_INTEL))
+ return;
+
+ slrt = sl_locate_and_validate_slrt();
+
+ /* Locate the TPM event log. */
+ sl_find_drtm_event_log(slrt);
+
+ /* Validate the location of the event log buffer before using it */
+ sl_validate_event_log_buffer();
+
+ /*
+ * Find the TPM hash algorithms used by the ACM and recorded in the
+ * event log.
+ */
+ if (tpm_log_ver == SL_TPM20_LOG)
+ sl_find_event_log_algorithms();
+
+ /*
+ * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
+ * anything fails, the system will reset anyway.
+ */
+ sanitize_boot_params(bp);
+ bp->hdr.loadflags |= SLAUNCH_FLAG;
+
+ sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
+
+ /* Place event log SL specific tags before and after measurements */
+ sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
+
+ /* Process all policy entries and extend the measurements to the evtlog */
+ sl_process_extend_policy(slrt);
+
+ /* Process all EFI config entries and extend the measurements to the evtlog */
+ sl_process_extend_uefi_config(slrt);
+
+ sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
+
+ /* No PMR check is needed, the TXT heap is covered by the DPR */
+ txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
+ os_mle_data = txt_os_mle_data_start(txt_heap);
+
+ /*
+ * Now that the OS-MLE data is measured, ensure the MTRR and
+ * misc enable MSRs are what we expect.
+ */
+ sl_txt_validate_msrs(os_mle_data);
+}
diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
new file mode 100644
index 000000000000..24b8f23d5dcc
--- /dev/null
+++ b/arch/x86/boot/compressed/sl_stub.S
@@ -0,0 +1,725 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Secure Launch protected mode entry point.
+ *
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ */
+ .code32
+ .text
+#include <linux/linkage.h>
+#include <asm/segment.h>
+#include <asm/msr.h>
+#include <asm/apicdef.h>
+#include <asm/trapnr.h>
+#include <asm/processor-flags.h>
+#include <asm/asm-offsets.h>
+#include <asm/bootparam.h>
+#include <asm/page_types.h>
+#include <asm/irq_vectors.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
+
+/* CPUID: leaf 1, ECX, SMX feature bit */
+#define X86_FEATURE_BIT_SMX (1 << 6)
+
+#define IDT_VECTOR_LO_BITS 0
+#define IDT_VECTOR_HI_BITS 6
+
+/*
+ * See the comment in head_64.S for detailed information on what this macro
+ * and others like it are used for. The comment appears right at the top of
+ * the file.
+ */
+#define rva(X) ((X) - sl_stub_entry)
+
+/*
+ * The GETSEC op code is open coded because older versions of
+ * GCC do not support the getsec mnemonic.
+ */
+.macro GETSEC leaf
+ pushl %ebx
+ xorl %ebx, %ebx /* Must be zero for SMCTRL */
+ movl \leaf, %eax /* Leaf function */
+ .byte 0x0f, 0x37 /* GETSEC opcode */
+ popl %ebx
+.endm
+
+.macro TXT_RESET error
+ /*
+ * Set a sticky error value and reset. Note the movs to %eax act as
+ * TXT register barriers.
+ */
+ movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
+ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
+ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
+ movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
+1:
+ hlt
+ jmp 1b
+.endm
+
+ .code32
+SYM_FUNC_START(sl_stub_entry)
+ cli
+ cld
+
+ /*
+ * On entry, %ebx has the entry abs offset to sl_stub_entry. This
+ * will be correctly scaled using the rva macro and avoid causing
+ * relocations. Only %cs and %ds segments are known good.
+ */
+
+ /* Load GDT, set segment regs and lret to __SL32_CS */
+ leal rva(sl_gdt_desc)(%ebx), %eax
+ addl %eax, 2(%eax)
+ lgdt (%eax)
+
+ movl $(__SL32_DS), %eax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+ movw %ax, %ss
+
+ /*
+ * Now that %ss is known good, take the first stack for the BSP. The
+ * AP stacks are only used on Intel.
+ */
+ leal rva(sl_stacks_end)(%ebx), %esp
+
+ leal rva(.Lsl_cs)(%ebx), %eax
+ pushl $(__SL32_CS)
+ pushl %eax
+ lret
+
+.Lsl_cs:
+ /* Save our base pointer reg and page table for MLE */
+ pushl %ebx
+ pushl %ecx
+
+ /* See if SMX feature is supported. */
+ movl $1, %eax
+ cpuid
+ testl $(X86_FEATURE_BIT_SMX), %ecx
+ jz .Ldo_unknown_cpu
+
+ popl %ecx
+ popl %ebx
+
+ /* Know it is Intel */
+ movl $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
+
+ /* Locate the base of the MLE using the page tables in %ecx */
+ call sl_find_mle_base
+
+ /* Increment CPU count for BSP */
+ incl rva(sl_txt_cpu_count)(%ebx)
+
+ /*
+ * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
+ * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
+ * allow the mainline kernel re-enable them in the normal course of
+ * booting.
+ */
+ GETSEC $(SMX_X86_GETSEC_SMCTRL)
+
+ /* Clear the TXT error registers for a clean start of day */
+ movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
+ movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
+
+ /* On Intel, the zero page address is passed in the TXT heap */
+ /* Read physical base of heap into EAX */
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
+ /* Read the size of the BIOS data into ECX (first 8 bytes) */
+ movl (%eax), %ecx
+ /* Skip over BIOS data and size of OS to MLE data section */
+ leal 8(%eax, %ecx), %eax
+
+ /* Need to verify the values in the OS-MLE struct passed in */
+ call sl_txt_verify_os_mle_struct
+
+ /*
+ * Get the boot params address from the heap. Note %esi and %ebx MUST
+ * be preserved across calls and operations.
+ */
+ movl SL_boot_params_addr(%eax), %esi
+
+ /* Save %ebx so the APs can find their way home */
+ movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
+
+ /* Fetch the AP wake code block address from the heap */
+ movl SL_ap_wake_block(%eax), %edi
+ movl %edi, rva(sl_txt_ap_wake_block)(%ebx)
+
+ /* Store the offset in the AP wake block to the jmp address */
+ movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
+ (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
+
+ /* Store the offset in the AP wake block to the AP stacks block */
+ movl $(sl_stacks - sl_txt_ap_wake_begin), \
+ (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
+
+ /* %eax still is the base of the OS-MLE block, save it */
+ pushl %eax
+
+ /* Relocate the AP wake code to the safe block */
+ call sl_txt_reloc_ap_wake
+
+ /*
+ * Wake up all APs that are blocked in the ACM and wait for them to
+ * halt. This should be done before restoring the MTRRs so the ACM is
+ * still properly in WB memory.
+ */
+ call sl_txt_wake_aps
+
+ /* Restore OS-MLE in %eax */
+ popl %eax
+
+ /*
+ * %edi is used by this routine to find the MTRRs which are in the SLRT
+ * in the Intel info.
+ */
+ movl SL_txt_info(%eax), %edi
+ call sl_txt_load_regs
+
+ jmp .Lcpu_setup_done
+
+.Ldo_unknown_cpu:
+ /* Non-Intel CPUs are not yet supported */
+ ud2
+
+.Lcpu_setup_done:
+ /*
+ * Don't enable MCE at this point. The kernel will enable
+ * it on the BSP later when it is ready.
+ */
+
+ /* Done, jump to normal 32b pm entry */
+ jmp startup_32
+SYM_FUNC_END(sl_stub_entry)
+
+SYM_FUNC_START(sl_find_mle_base)
+ /* %ecx has PDPT, get first PD */
+ movl (%ecx), %eax
+ andl $(PAGE_MASK), %eax
+ /* Get first PT from first PDE */
+ movl (%eax), %eax
+ andl $(PAGE_MASK), %eax
+ /* Get MLE base from first PTE */
+ movl (%eax), %eax
+ andl $(PAGE_MASK), %eax
+
+ movl %eax, rva(sl_mle_start)(%ebx)
+ ret
+SYM_FUNC_END(sl_find_mle_base)
+
+SYM_FUNC_START(sl_check_buffer_mle_overlap)
+ /* %ecx: buffer begin %edx: buffer end */
+ /* %ebx: MLE begin %edi: MLE end */
+ /* %eax: region may be inside MLE */
+
+ cmpl %edi, %ecx
+ jb .Lnext_check
+ cmpl %edi, %edx
+ jbe .Lnext_check
+ jmp .Lvalid /* Buffer above MLE */
+
+.Lnext_check:
+ cmpl %ebx, %edx
+ ja .Linside_check
+ cmpl %ebx, %ecx
+ jae .Linside_check
+ jmp .Lvalid /* Buffer below MLE */
+
+.Linside_check:
+ cmpl $0, %eax
+ jz .Linvalid
+ cmpl %ebx, %ecx
+ jb .Linvalid
+ cmpl %edi, %edx
+ ja .Linvalid
+ jmp .Lvalid /* Buffer in MLE */
+
+.Linvalid:
+ TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
+
+.Lvalid:
+ ret
+SYM_FUNC_END(sl_check_buffer_mle_overlap)
+
+SYM_FUNC_START(sl_txt_verify_os_mle_struct)
+ pushl %ebx
+ /*
+ * %eax points to the base of the OS-MLE struct. Need to also
+ * read some values from the OS-SINIT struct too.
+ */
+ movl -8(%eax), %ecx
+ /* Skip over OS to MLE data section and size of OS-SINIT structure */
+ leal (%eax, %ecx), %edx
+
+ /* Load MLE image base absolute offset */
+ movl rva(sl_mle_start)(%ebx), %ebx
+
+ /* Verify the value of the low PMR base. It should always be 0. */
+ movl SL_vtd_pmr_lo_base(%edx), %esi
+ cmpl $0, %esi
+ jz .Lvalid_pmr_base
+ TXT_RESET $(SL_ERROR_LO_PMR_BASE)
+
+.Lvalid_pmr_base:
+ /* Grab some values from OS-SINIT structure */
+ movl SL_mle_size(%edx), %edi
+ addl %ebx, %edi
+ jc .Loverflow_detected
+ movl SL_vtd_pmr_lo_size(%edx), %esi
+
+ /* Check the AP wake block */
+ movl SL_ap_wake_block(%eax), %ecx
+ movl SL_ap_wake_block_size(%eax), %edx
+ addl %ecx, %edx
+ jc .Loverflow_detected
+ pushl %eax
+ xorl %eax, %eax
+ call sl_check_buffer_mle_overlap
+ popl %eax
+ cmpl %esi, %edx
+ ja .Lbuffer_beyond_pmr
+
+ /*
+ * Check the boot params. Note during a UEFI boot, the boot
+ * params will be inside the MLE image. Test for this case
+ * in the overlap case.
+ */
+ movl SL_boot_params_addr(%eax), %ecx
+ movl $(PAGE_SIZE), %edx
+ addl %ecx, %edx
+ jc .Loverflow_detected
+ pushl %eax
+ movl $1, %eax
+ call sl_check_buffer_mle_overlap
+ popl %eax
+ cmpl %esi, %edx
+ ja .Lbuffer_beyond_pmr
+
+ /* Check that the AP wake block is big enough */
+ cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
+ SL_ap_wake_block_size(%eax)
+ jae .Lwake_block_ok
+ TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
+
+.Lwake_block_ok:
+ popl %ebx
+ ret
+
+.Loverflow_detected:
+ TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
+
+.Lbuffer_beyond_pmr:
+ TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
+SYM_FUNC_END(sl_txt_verify_os_mle_struct)
+
+SYM_FUNC_START(sl_txt_ap_entry)
+ cli
+ cld
+ /*
+ * The %cs and %ds segments are known good after waking the AP.
+ * First order of business is to find where we are and
+ * save it in %ebx.
+ */
+
+ /* Read physical base of heap into EAX */
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
+ /* Read the size of the BIOS data into ECX (first 8 bytes) */
+ movl (%eax), %ecx
+ /* Skip over BIOS data and size of OS to MLE data section */
+ leal 8(%eax, %ecx), %eax
+
+ /* Saved %ebx from the BSP and stash OS-MLE pointer */
+ movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
+
+ /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
+ movl SL_txt_info(%eax), %edi
+
+ /* Lock and get our stack index */
+ movl $1, %ecx
+.Lspin:
+ xorl %eax, %eax
+ lock cmpxchgl %ecx, rva(sl_txt_spin_lock)(%ebx)
+ pause
+ jnz .Lspin
+
+ /* Increment the stack index and use the next value inside lock */
+ incl rva(sl_txt_stack_index)(%ebx)
+ movl rva(sl_txt_stack_index)(%ebx), %eax
+
+ /* Unlock */
+ movl $0, rva(sl_txt_spin_lock)(%ebx)
+
+ /* Location of the relocated AP wake block */
+ movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
+
+ /* Load reloc GDT, set segment regs and lret to __SL32_CS */
+ lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
+
+ movl $(__SL32_DS), %edx
+ movw %dx, %ds
+ movw %dx, %es
+ movw %dx, %fs
+ movw %dx, %gs
+ movw %dx, %ss
+
+ /* Load our reloc AP stack */
+ movl $(TXT_BOOT_STACK_SIZE), %edx
+ mull %edx
+ leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
+ subl %eax, %esp
+
+ /* Switch to AP code segment */
+ leal rva(.Lsl_ap_cs)(%ebx), %eax
+ pushl $(__SL32_CS)
+ pushl %eax
+ lret
+
+.Lsl_ap_cs:
+ /* Load the relocated AP IDT */
+ lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
+
+ /* Fixup MTRRs and misc enable MSR on APs too */
+ call sl_txt_load_regs
+
+ /* Enable SMI with GETSEC[SMCTRL] */
+ GETSEC $(SMX_X86_GETSEC_SMCTRL)
+
+ /* IRET-to-self can be used to enable NMIs which SENTER disabled */
+ leal rva(.Lnmi_enabled_ap)(%ebx), %eax
+ pushfl
+ pushl $(__SL32_CS)
+ pushl %eax
+ iret
+
+.Lnmi_enabled_ap:
+ /* Put APs in X2APIC mode like the BSP */
+ movl $(MSR_IA32_APICBASE), %ecx
+ rdmsr
+ orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
+ wrmsr
+
+ /*
+ * Basically done, increment the CPU count and jump off to the AP
+ * wake block to wait.
+ */
+ lock incl rva(sl_txt_cpu_count)(%ebx)
+
+ movl rva(sl_txt_ap_wake_block)(%ebx), %eax
+ jmp *%eax
+SYM_FUNC_END(sl_txt_ap_entry)
+
+SYM_FUNC_START(sl_txt_reloc_ap_wake)
+ /* Save boot params register */
+ pushl %esi
+
+ movl rva(sl_txt_ap_wake_block)(%ebx), %edi
+
+ /* Fixup AP IDT and GDT descriptor before relocating */
+ leal rva(sl_ap_idt_desc)(%ebx), %eax
+ addl %edi, 2(%eax)
+ leal rva(sl_ap_gdt_desc)(%ebx), %eax
+ addl %edi, 2(%eax)
+
+ /*
+ * Copy the AP wake code and AP GDT/IDT to the protected wake block
+ * provided by the loader. Destination already in %edi.
+ */
+ movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
+ leal rva(sl_txt_ap_wake_begin)(%ebx), %esi
+ rep movsb
+
+ /* Setup the IDT for the APs to use in the relocation block */
+ movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
+ addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
+ xorl %edx, %edx
+
+ /* Form the default reset vector relocation address */
+ movl rva(sl_txt_ap_wake_block)(%ebx), %esi
+ addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
+
+1:
+ cmpw $(NR_VECTORS), %dx
+ jz .Lap_idt_done
+
+ cmpw $(X86_TRAP_NMI), %dx
+ jz 2f
+
+ /* Load all other fixed vectors with reset handler */
+ movl %esi, %eax
+ movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
+ shrl $16, %eax
+ movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
+ jmp 3f
+
+2:
+ /* Load single wake NMI IPI vector at the relocation address */
+ movl rva(sl_txt_ap_wake_block)(%ebx), %eax
+ addl $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
+ movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
+ shrl $16, %eax
+ movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
+
+3:
+ incw %dx
+ addl $8, %ecx
+ jmp 1b
+
+.Lap_idt_done:
+ popl %esi
+ ret
+SYM_FUNC_END(sl_txt_reloc_ap_wake)
+
+SYM_FUNC_START(sl_txt_load_regs)
+ /* Save base pointer register */
+ pushl %ebx
+
+ /*
+ * On Intel, the original variable MTRRs and Misc Enable MSR are
+ * restored on the BSP at early boot. Each AP will also restore
+ * its MTRRs and Misc Enable MSR.
+ */
+ pushl %edi
+ addl $(SL_saved_bsp_mtrrs), %edi
+ movl (%edi), %ebx
+ pushl %ebx /* default_mem_type lo */
+ addl $4, %edi
+ movl (%edi), %ebx
+ pushl %ebx /* default_mem_type hi */
+ addl $4, %edi
+ movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
+ addl $8, %edi /* now at MTRR pair array */
+ /* Write the variable MTRRs */
+ movl $(MSR_MTRRphysBase0), %ecx
+1:
+ cmpl $0, %ebx
+ jz 2f
+
+ movl (%edi), %eax /* MTRRphysBaseX lo */
+ addl $4, %edi
+ movl (%edi), %edx /* MTRRphysBaseX hi */
+ wrmsr
+ addl $4, %edi
+ incl %ecx
+ movl (%edi), %eax /* MTRRphysMaskX lo */
+ addl $4, %edi
+ movl (%edi), %edx /* MTRRphysMaskX hi */
+ wrmsr
+ addl $4, %edi
+ incl %ecx
+
+ decl %ebx
+ jmp 1b
+2:
+ /* Write the default MTRR register */
+ popl %edx
+ popl %eax
+ movl $(MSR_MTRRdefType), %ecx
+ wrmsr
+
+ /* Return to beginning and write the misc enable msr */
+ popl %edi
+ addl $(SL_saved_misc_enable_msr), %edi
+ movl (%edi), %eax /* saved_misc_enable_msr lo */
+ addl $4, %edi
+ movl (%edi), %edx /* saved_misc_enable_msr hi */
+ movl $(MSR_IA32_MISC_ENABLE), %ecx
+ wrmsr
+
+ popl %ebx
+ ret
+SYM_FUNC_END(sl_txt_load_regs)
+
+SYM_FUNC_START(sl_txt_wake_aps)
+ /* Save boot params register */
+ pushl %esi
+
+ /* First setup the MLE join structure and load it into TXT reg */
+ leal rva(sl_gdt)(%ebx), %eax
+ leal rva(sl_txt_ap_entry)(%ebx), %ecx
+ leal rva(sl_smx_rlp_mle_join)(%ebx), %edx
+ movl %eax, SL_rlp_gdt_base(%edx)
+ movl %ecx, SL_rlp_entry_point(%edx)
+ movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
+
+ /* Another TXT heap walk to find various values needed to wake APs */
+ movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
+ /* At BIOS data size, find the number of logical processors */
+ movl (SL_num_logical_procs + 8)(%eax), %edx
+ /* Skip over BIOS data */
+ movl (%eax), %ecx
+ addl %ecx, %eax
+ /* Skip over OS to MLE */
+ movl (%eax), %ecx
+ addl %ecx, %eax
+ /* At OS-SNIT size, get capabilities to know how to wake up the APs */
+ movl (SL_capabilities + 8)(%eax), %esi
+ /* Skip over OS to SNIT */
+ movl (%eax), %ecx
+ addl %ecx, %eax
+ /* At SINIT-MLE size, get the AP wake MONITOR address */
+ movl (SL_rlp_wakeup_addr + 8)(%eax), %edi
+
+ /* Determine how to wake up the APs */
+ testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
+ jz .Lwake_getsec
+
+ /* Wake using MWAIT MONITOR */
+ movl $1, (%edi)
+ jmp .Laps_awake
+
+.Lwake_getsec:
+ /* Wake using GETSEC(WAKEUP) */
+ GETSEC $(SMX_X86_GETSEC_WAKEUP)
+
+.Laps_awake:
+ /*
+ * All of the APs are woken up and rendesvous in the relocated wake
+ * block starting at sl_txt_ap_wake_begin. Wait for all of them to
+ * halt.
+ */
+ pause
+ cmpl rva(sl_txt_cpu_count)(%ebx), %edx
+ jne .Laps_awake
+
+ popl %esi
+ ret
+SYM_FUNC_END(sl_txt_wake_aps)
+
+/* This is the beginning of the relocated AP wake code block */
+ .global sl_txt_ap_wake_begin
+sl_txt_ap_wake_begin:
+
+ /* Get the LAPIC ID for each AP and stash it on the stack */
+ movl $(MSR_IA32_X2APIC_APICID), %ecx
+ rdmsr
+ pushl %eax
+
+ /*
+ * Get a pointer to the monitor location on this APs stack to test below
+ * after mwait returns. Currently %esp points to just past the pushed APIC
+ * ID value.
+ */
+ movl %esp, %eax
+ subl $(TXT_BOOT_STACK_SIZE - 4), %eax
+ movl $0, (%eax)
+
+ /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+
+ /*
+ * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
+ * instruction can return for a number of reasons. Test to see if it returned
+ * because the monitor was written to.
+ */
+ monitor
+
+1:
+ mfence
+ mwait
+ movl (%eax), %edx
+ testl %edx, %edx
+ jz 1b
+
+ /*
+ * This is the long absolute jump to the 32b Secure Launch protected mode stub
+ * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
+ * fixed in the SMP boot code when the first AP is brought up. This whole area
+ * is provided and protected in the memory map by the prelaunch code.
+ */
+ .byte 0xea
+sl_ap_jmp_offset:
+ .long 0x00000000
+ .word __SL32_CS
+
+SYM_FUNC_START(sl_txt_int_nmi)
+ /* NMI context, just IRET */
+ iret
+SYM_FUNC_END(sl_txt_int_nmi)
+
+SYM_FUNC_START(sl_txt_int_reset)
+ TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
+SYM_FUNC_END(sl_txt_int_reset)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_ap_idt_desc)
+ .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */
+ .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */
+SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_ap_idt)
+ .rept NR_VECTORS
+ .word 0x0000 /* Offset 15 to 0 */
+ .word __SL32_CS /* Segment selector */
+ .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */
+ .word 0x0000 /* Offset 31 to 16 */
+ .endr
+SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
+ .word sl_ap_gdt_end - sl_ap_gdt - 1
+ .long sl_ap_gdt - sl_txt_ap_wake_begin
+SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_ap_gdt)
+ .quad 0x0000000000000000 /* NULL */
+ .quad 0x00cf9a000000ffff /* __SL32_CS */
+ .quad 0x00cf92000000ffff /* __SL32_DS */
+SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
+
+ /* Small stacks for BSP and APs to work with */
+ .balign 64
+SYM_DATA_START_LOCAL(sl_stacks)
+ .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
+SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
+
+/* This is the end of the relocated AP wake code block */
+ .global sl_txt_ap_wake_end
+sl_txt_ap_wake_end:
+
+ .data
+ .balign 8
+SYM_DATA_START_LOCAL(sl_gdt_desc)
+ .word sl_gdt_end - sl_gdt - 1
+ .long sl_gdt - sl_gdt_desc
+SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_gdt)
+ .quad 0x0000000000000000 /* NULL */
+ .quad 0x00cf9a000000ffff /* __SL32_CS */
+ .quad 0x00cf92000000ffff /* __SL32_DS */
+SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
+
+ .balign 8
+SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
+ .long sl_gdt_end - sl_gdt - 1 /* GDT limit */
+ .long 0x00000000 /* GDT base */
+ .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
+ .long 0x00000000 /* Entry point physical address */
+SYM_DATA_END(sl_smx_rlp_mle_join)
+
+SYM_DATA(sl_cpu_type, .long 0x00000000)
+
+SYM_DATA(sl_mle_start, .long 0x00000000)
+
+SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
+
+SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
+
+SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
+
+SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index e022e6eb766c..37f6167f28ba 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -348,6 +348,9 @@
#define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
#define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561
+#define MSR_MTRRphysBase0 0x00000200
+#define MSR_MTRRphysMask0 0x00000201
+
#define MSR_MTRRfix64K_00000 0x00000250
#define MSR_MTRRfix16K_80000 0x00000258
#define MSR_MTRRfix16K_A0000 0x00000259
@@ -849,6 +852,8 @@
#define MSR_IA32_APICBASE_ENABLE (1<<11)
#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
+#define MSR_IA32_X2APIC_APICID 0x00000802
+
#define MSR_IA32_UCODE_WRITE 0x00000079
#define MSR_IA32_UCODE_REV 0x0000008b
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index 9b82eebd7add..7ce283a22d6b 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -12,6 +12,7 @@
/* loadflags */
#define LOADED_HIGH (1<<0)
#define KASLR_FLAG (1<<1)
+#define SLAUNCH_FLAG (1<<2)
#define QUIET_FLAG (1<<5)
#define KEEP_SEGMENTS (1<<6)
#define CAN_USE_HEAP (1<<7)
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index a98020bf31bb..925adce6e2c7 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -13,6 +13,8 @@
#include <linux/hardirq.h>
#include <linux/suspend.h>
#include <linux/kbuild.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
#include <asm/sigframe.h>
@@ -120,4 +122,22 @@ static void __used common(void)
OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
#endif
+#ifdef CONFIG_SECURE_LAUNCH
+ BLANK();
+ OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
+ OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
+ OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
+ OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
+ OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
+ OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
+ OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
+ OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
+ OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
+ OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
+ OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
+ OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
+ OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
+ OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
+ OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
+#endif
}
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 1:03 ` [PATCH v9 08/19] x86: Secure Launch kernel early boot stub Ross Philipson
@ 2024-05-31 11:00 ` Ard Biesheuvel
2024-05-31 13:33 ` Ard Biesheuvel
2024-06-04 17:14 ` ross.philipson
2024-06-04 19:56 ` Jarkko Sakkinen
1 sibling, 2 replies; 113+ messages in thread
From: Ard Biesheuvel @ 2024-05-31 11:00 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
Hello Ross,
On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> later AMD SKINIT) to vector to during the late launch. The symbol
> sl_stub_entry is that entry point and its offset into the kernel is
> conveyed to the launching code using the MLE (Measured Launch
> Environment) header in the structure named mle_header. The offset of the
> MLE header is set in the kernel_info. The routine sl_stub contains the
> very early late launch setup code responsible for setting up the basic
> environment to allow the normal kernel startup_32 code to proceed. It is
> also responsible for properly waking and handling the APs on Intel
> platforms. The routine sl_main which runs after entering 64b mode is
> responsible for measuring configuration and module information before
> it is used like the boot params, the kernel command line, the TXT heap,
> an external initramfs, etc.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> Documentation/arch/x86/boot.rst | 21 +
> arch/x86/boot/compressed/Makefile | 3 +-
> arch/x86/boot/compressed/head_64.S | 30 +
> arch/x86/boot/compressed/kernel_info.S | 34 ++
> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> arch/x86/include/asm/msr-index.h | 5 +
> arch/x86/include/uapi/asm/bootparam.h | 1 +
> arch/x86/kernel/asm-offsets.c | 20 +
> 9 files changed, 1415 insertions(+), 1 deletion(-)
> create mode 100644 arch/x86/boot/compressed/sl_main.c
> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>
> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> index 4fd492cb4970..295cdf9bcbdb 100644
> --- a/Documentation/arch/x86/boot.rst
> +++ b/Documentation/arch/x86/boot.rst
> @@ -482,6 +482,14 @@ Protocol: 2.00+
> - If 1, KASLR enabled.
> - If 0, KASLR disabled.
>
> + Bit 2 (kernel internal): SLAUNCH_FLAG
> +
> + - Used internally by the setup kernel to communicate
> + Secure Launch status to kernel proper.
> +
> + - If 1, Secure Launch enabled.
> + - If 0, Secure Launch disabled.
> +
> Bit 5 (write): QUIET_FLAG
>
> - If 0, print early messages.
> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>
> This field contains maximal allowed type for setup_data and setup_indirect structs.
>
> +============ =================
> +Field name: mle_header_offset
> +Offset/size: 0x0010/4
> +============ =================
> +
> + This field contains the offset to the Secure Launch Measured Launch Environment
> + (MLE) header. This offset is used to locate information needed during a secure
> + late launch using Intel TXT. If the offset is zero, the kernel does not have
> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> + following a success measured launch. The specific state of the processors is
> + outlined in the TXT Software Development Guide, the latest can be found here:
> + https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> +
>
Could we just repaint this field as the offset relative to the start
of kernel_info rather than relative to the start of the image? That
way, there is no need for patch #1, and given that the consumer of
this field accesses it via kernel_info, I wouldn't expect any issues
in applying this offset to obtain the actual address.
> The Image Checksum
> ==================
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index 9189a0e28686..9076a248d4b4 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> + $(obj)/sl_main.o $(obj)/sl_stub.o
>
> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> $(call if_changed,ld)
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index 1dcb794c5479..803c9e2e6d85 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> pushq $0
> popfq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + /* Ensure the relocation region is coverd by a PMR */
covered
> + movq %rbx, %rdi
> + movl $(_bss - startup_32), %esi
> + callq sl_check_region
> +#endif
> +
> /*
> * Copy the compressed kernel to the end of our buffer
> * where decompression in place becomes safe.
> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> shrq $3, %rcx
> rep stosq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + /*
> + * Have to do the final early sl stub work in 64b area.
> + *
> + * *********** NOTE ***********
> + *
> + * Several boot params get used before we get a chance to measure
> + * them in this call. This is a known issue and we currently don't
> + * have a solution. The scratch field doesn't matter. There is no
> + * obvious way to do anything about the use of kernel_alignment or
> + * init_size though these seem low risk with all the PMR and overlap
> + * checks in place.
> + */
> + movq %r15, %rdi
> + callq sl_main
> +
> + /* Ensure the decompression location is covered by a PMR */
> + movq %rbp, %rdi
> + movq output_len(%rip), %rsi
> + callq sl_check_region
> +#endif
> +
> + pushq %rsi
This looks like a rebase error.
> call load_stage2_idt
>
> /* Pass boot_params to initialize_identity_maps() */
> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> index c18f07181dd5..e199b87764e9 100644
> --- a/arch/x86/boot/compressed/kernel_info.S
> +++ b/arch/x86/boot/compressed/kernel_info.S
> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> /* Maximal allowed type for setup_data and setup_indirect structs. */
> .long SETUP_TYPE_MAX
>
> + /* Offset to the MLE header structure */
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> + .long rva(mle_header)
... so this could just be mle_header - kernel_info, and the consumer
can do the math instead.
> +#else
> + .long 0
> +#endif
> +
> kernel_info_var_len_data:
> /* Empty for time being... */
> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> +
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> + /*
> + * The MLE Header per the TXT Specification, section 2.1
> + * MLE capabilities, see table 4. Capabilities set:
> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> + * bit 1: Support for RLP wakeup using MONITOR address
> + * bit 2: The ECX register will contain the pointer to the MLE page table
> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> + */
> +SYM_DATA_START(mle_header)
> + .long 0x9082ac5a /* UUID0 */
> + .long 0x74a7476f /* UUID1 */
> + .long 0xa2555c0f /* UUID2 */
> + .long 0x42b651cb /* UUID3 */
> + .long 0x00000034 /* MLE header size */
> + .long 0x00020002 /* MLE version 2.2 */
> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
and these should perhaps be relative to mle_header?
> + .long 0x00000000 /* First valid page of MLE */
> + .long 0x00000000 /* Offset within binary of first byte of MLE */
> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
and here
> + .long 0x00000227 /* Bit vector of MLE-supported capabilities */
> + .long 0x00000000 /* Starting linear address of command line (unused) */
> + .long 0x00000000 /* Ending linear address of command line (unused) */
> +SYM_DATA_END(mle_header)
> +#endif
> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
> new file mode 100644
> index 000000000000..61e9baf410fd
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_main.c
> @@ -0,0 +1,577 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Secure Launch early measurement and validation routines.
> + *
> + * Copyright (c) 2024, Oracle and/or its affiliates.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/boot.h>
> +#include <asm/msr.h>
> +#include <asm/mtrr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/bootparam_utils.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +#include <crypto/sha1.h>
> +#include <crypto/sha2.h>
> +
> +#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff
> +
> +#define SL_TPM12_LOG 1
> +#define SL_TPM20_LOG 2
> +
> +#define SL_TPM20_MAX_ALGS 2
> +
> +#define SL_MAX_EVENT_DATA 64
> +#define SL_TPM12_LOG_SIZE (sizeof(struct tcg_pcr_event) + \
> + SL_MAX_EVENT_DATA)
> +#define SL_TPM20_LOG_SIZE (sizeof(struct tcg_pcr_event2_head) + \
> + SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
> + sizeof(struct tcg_event_field) + \
> + SL_MAX_EVENT_DATA)
> +
> +static void *evtlog_base;
> +static u32 evtlog_size;
> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
> +static u32 tpm_log_ver = SL_TPM12_LOG;
> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
> +
> +extern u32 sl_cpu_type;
> +extern u32 sl_mle_start;
> +
> +static u64 sl_txt_read(u32 reg)
> +{
> + return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void sl_txt_write(u32 reg, u64 val)
> +{
> + writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void __noreturn sl_txt_reset(u64 error)
> +{
> + /* Reading the E2STS register acts as a barrier for TXT registers */
> + sl_txt_write(TXT_CR_ERRORCODE, error);
> + sl_txt_read(TXT_CR_E2STS);
> + sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
> + sl_txt_read(TXT_CR_E2STS);
> + sl_txt_write(TXT_CR_CMD_RESET, 1);
> +
> + for ( ; ; )
> + asm volatile ("hlt");
> +
> + unreachable();
> +}
> +
> +static u64 sl_rdmsr(u32 reg)
> +{
> + u64 lo, hi;
> +
> + asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
> +
> + return (hi << 32) | lo;
> +}
> +
> +static struct slr_table *sl_locate_and_validate_slrt(void)
> +{
> + struct txt_os_mle_data *os_mle_data;
> + struct slr_table *slrt;
> + void *txt_heap;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + if (!os_mle_data->slrt)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + slrt = (struct slr_table *)os_mle_data->slrt;
> +
> + if (slrt->magic != SLR_TABLE_MAGIC)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + if (slrt->architecture != SLR_INTEL_TXT)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + return slrt;
> +}
> +
> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + void *end = base + size;
> + void *txt_heap;
> +
> + if (!(sl_cpu_type & SL_CPU_INTEL))
> + return;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
> + sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
> +
> + /*
> + * Note that the late stub code validates that the hi PMR covers
> + * all memory above 4G. At this point the code can only check that
> + * regions are within the hi PMR but that is sufficient.
> + */
> + if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
Better to put the cast on the pointers, given that we are doing
arithmetic, and use SZ_4G instead of open coding this constant 4
times.
> + if (allow_hi) {
> + if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
> + os_sinit_data->vtd_pmr_hi_size))
> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> + } else {
> + sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
> + }
> + }
> +
> + if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> +}
> +
> +/*
> + * Some MSRs are modified by the pre-launch code including the MTRRs.
> + * The early MLE code has to restore these values. This code validates
> + * the values after they are measured.
> + */
> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
> +{
> + struct slr_txt_mtrr_state *saved_bsp_mtrrs;
> + u64 mtrr_caps, mtrr_def_type, mtrr_var;
> + struct slr_entry_intel_info *txt_info;
> + u64 misc_en_msr;
> + u32 vcnt, i;
> +
> + txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
> + saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
> +
> + mtrr_caps = sl_rdmsr(MSR_MTRRcap);
> + vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
> +
> + if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> + if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> +
> + mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
> + if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
> + sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
> +
> + for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
> + mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
> + sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
> + mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
> + sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
> + }
> +
> + misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
> + if (txt_info->saved_misc_enable_msr != misc_en_msr)
> + sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
> +}
> +
> +static void sl_find_drtm_event_log(struct slr_table *slrt)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + struct slr_entry_log_info *log_info;
> + void *txt_heap;
> +
> + log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
> + if (!log_info)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + evtlog_base = (void *)log_info->addr;
> + evtlog_size = log_info->size;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +
> + /*
> + * For TPM 2.0, the event log 2.1 extended data structure has to also
> + * be located and fixed up.
> + */
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + /*
> + * Only support version 6 and later that properly handle the
> + * list of ExtDataElements in the OS-SINIT structure.
> + */
> + if (os_sinit_data->version < 6)
> + sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
> +
> + /* Find the TPM2.0 logging extended heap element */
> + log20_elem = tpm20_find_log2_1_element(os_sinit_data);
> +
> + /* If found, this implies TPM20 log and family */
> + if (log20_elem)
> + tpm_log_ver = SL_TPM20_LOG;
> +}
> +
> +static void sl_validate_event_log_buffer(void)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + void *txt_heap, *txt_end;
> + void *mle_base, *mle_end;
> + void *evtlog_end;
> +
> + if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
> + sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
> + evtlog_end = evtlog_base + evtlog_size;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + mle_base = (void *)(u64)sl_mle_start;
> + mle_end = mle_base + os_sinit_data->mle_size;
> +
> + /*
> + * This check is to ensure the event log buffer does not overlap with
> + * the MLE image.
> + */
> + if (evtlog_base >= mle_end && evtlog_end > mle_end)
> + goto pmr_check; /* above */
> +
> + if (evtlog_end <= mle_base && evtlog_base < mle_base)
> + goto pmr_check; /* below */
> +
> + sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
> +
> +pmr_check:
> + /*
> + * The TXT heap is protected by the DPR. If the TPM event log is
> + * inside the TXT heap, there is no need for a PMR check.
> + */
> + if (evtlog_base > txt_heap && evtlog_end < txt_end)
> + return;
> +
> + sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
> +}
> +
> +static void sl_find_event_log_algorithms(void)
> +{
> + struct tcg_efi_specid_event_head *efi_head =
> + (struct tcg_efi_specid_event_head *)(evtlog_base +
> + log20_elem->first_record_offset +
> + sizeof(struct tcg_pcr_event));
> +
> + if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
> + sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
> +
> + memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
> + sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
> +}
> +
> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
> + const u8 *data, u32 length,
> + const u8 *event_data, u32 event_size)
> +{
> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> + u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
> + struct tcg_pcr_event *pcr_event;
> + u32 total_size;
> +
> + pcr_event = (struct tcg_pcr_event *)log_buf;
> + pcr_event->pcr_idx = pcr;
> + pcr_event->event_type = event_type;
> + if (length > 0) {
> + sha1(data, length, &sha1_hash[0]);
> + memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
> + }
> + pcr_event->event_size = event_size;
> + if (event_size > 0)
> + memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
> + event_data, event_size);
> +
> + total_size = sizeof(struct tcg_pcr_event) + event_size;
> +
> + if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
> + const u8 *data, u32 length,
> + const u8 *event_data, u32 event_size)
> +{
> + u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> + u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
> + struct sha256_state sctx256 = {0};
> + struct tcg_pcr_event2_head *head;
> + struct tcg_event_field *event;
> + u32 total_size;
> + u16 *alg_ptr;
> + u8 *dgst_ptr;
> +
> + head = (struct tcg_pcr_event2_head *)log_buf;
> + head->pcr_idx = pcr;
> + head->event_type = event_type;
> + total_size = sizeof(struct tcg_pcr_event2_head);
> + alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
> +
> + for ( ; head->count < 2; head->count++) {
> + if (!tpm_algs[head->count].alg_id)
> + break;
> +
> + *alg_ptr = tpm_algs[head->count].alg_id;
> + dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
> +
> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
> + length) {
> + sha256_init(&sctx256);
> + sha256_update(&sctx256, data, length);
> + sha256_final(&sctx256, &sha256_hash[0]);
> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
> + length) {
> + sha1(data, length, &sha1_hash[0]);
> + }
> +
> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
> + memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
> + total_size += SHA256_DIGEST_SIZE + sizeof(u16);
> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
> + memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
> + total_size += SHA1_DIGEST_SIZE + sizeof(u16);
> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
> + } else {
> + sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
> + }
> + }
> +
> + event = (struct tcg_event_field *)(log_buf + total_size);
> + event->event_size = event_size;
> + if (event_size > 0)
> + memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
> + total_size += sizeof(struct tcg_event_field) + event_size;
> +
> + if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
> + const u8 *data, u32 length, const char *desc)
> +{
> + if (tpm_log_ver == SL_TPM20_LOG)
> + sl_tpm20_log_event(pcr, type, data, length,
> + (const u8 *)desc, strlen(desc));
> + else
> + sl_tpm12_log_event(pcr, type, data, length,
> + (const u8 *)desc, strlen(desc));
> +}
> +
> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
> + struct slr_policy_entry *entry)
> +{
> + struct setup_indirect *ind;
> + struct setup_data *next;
> +
> + if (!curr)
> + return NULL;
> +
> + next = (struct setup_data *)(unsigned long)curr->next;
> +
> + /* SETUP_INDIRECT instances have to be handled differently */
> + if (curr->type == SETUP_INDIRECT) {
> + ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
> +
> + sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)ind->addr, ind->len,
> + entry->evt_info);
> +
> + return next;
> + }
> +
> + sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
> + curr->len, true);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + ((u8 *)curr) + sizeof(struct setup_data),
> + curr->len,
> + entry->evt_info);
> +
> + return next;
> +}
> +
> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
> +{
> + struct setup_data *data;
> +
> + /*
> + * Measuring the boot params measured the fixed e820 memory map.
> + * Measure any setup_data entries including e820 extended entries.
> + */
> + data = (struct setup_data *)(unsigned long)entry->entity;
> + while (data)
> + data = sl_handle_setup_data(data, entry);
> +}
> +
> +static void sl_extend_slrt(struct slr_policy_entry *entry)
> +{
> + struct slr_table *slrt = (struct slr_table *)entry->entity;
> + struct slr_entry_intel_info *intel_info;
> +
> + /*
> + * In revision one of the SLRT, the only table that needs to be
> + * measured is the Intel info table. Everything else is meta-data,
> + * addresses and sizes. Note the size of what to measure is not set.
> + * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
> + * to sort out.
> + */
> + if (slrt->revision == 1) {
> + intel_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
> + if (!intel_info)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)entry->entity, sizeof(struct slr_entry_intel_info),
> + entry->evt_info);
> + }
> +}
> +
> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
> +{
> + struct txt_os_mle_data *os_mle_data;
> + void *txt_heap;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + /*
> + * Version 1 of the OS-MLE heap structure has no fields to measure. It just
> + * has addresses and sizes and a scratch buffer.
> + */
> + if (os_mle_data->version == 1)
> + return;
> +}
> +
> +static void sl_process_extend_policy(struct slr_table *slrt)
> +{
> + struct slr_entry_policy *policy;
> + u16 i;
> +
> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
> + if (!policy)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + for (i = 0; i < policy->nr_entries; i++) {
> + switch (policy->policy_entries[i].entity_type) {
> + case SLR_ET_SETUP_DATA:
> + sl_extend_setup_data(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_SLRT:
> + sl_extend_slrt(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_TXT_OS2MLE:
> + sl_extend_txt_os2mle(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_UNUSED:
> + continue;
> + default:
> + sl_tpm_extend_evtlog(policy->policy_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)policy->policy_entries[i].entity,
> + policy->policy_entries[i].size,
> + policy->policy_entries[i].evt_info);
> + }
> + }
> +}
> +
> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
> +{
> + struct slr_entry_uefi_config *uefi_config;
> + u16 i;
> +
> + uefi_config = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
> +
> + /* Optionally here depending on how SL kernel was booted */
> + if (!uefi_config)
> + return;
> +
> + for (i = 0; i < uefi_config->nr_entries; i++) {
> + sl_tpm_extend_evtlog(uefi_config->uefi_cfg_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)uefi_config->uefi_cfg_entries[i].cfg,
> + uefi_config->uefi_cfg_entries[i].size,
> + uefi_config->uefi_cfg_entries[i].evt_info);
> + }
> +}
> +
> +asmlinkage __visible void sl_check_region(void *base, u32 size)
> +{
> + sl_check_pmr_coverage(base, size, false);
> +}
> +
> +asmlinkage __visible void sl_main(void *bootparams)
> +{
> + struct boot_params *bp = (struct boot_params *)bootparams;
> + struct txt_os_mle_data *os_mle_data;
> + struct slr_table *slrt;
> + void *txt_heap;
> +
> + /*
> + * Ensure loadflags do not indicate a secure launch was done
> + * unless it really was.
> + */
> + bp->hdr.loadflags &= ~SLAUNCH_FLAG;
> +
> + /*
> + * Currently only Intel TXT is supported for Secure Launch. Testing
> + * this value also indicates that the kernel was booted successfully
> + * through the Secure Launch entry point and is in SMX mode.
> + */
> + if (!(sl_cpu_type & SL_CPU_INTEL))
> + return;
> +
> + slrt = sl_locate_and_validate_slrt();
> +
> + /* Locate the TPM event log. */
> + sl_find_drtm_event_log(slrt);
> +
> + /* Validate the location of the event log buffer before using it */
> + sl_validate_event_log_buffer();
> +
> + /*
> + * Find the TPM hash algorithms used by the ACM and recorded in the
> + * event log.
> + */
> + if (tpm_log_ver == SL_TPM20_LOG)
> + sl_find_event_log_algorithms();
> +
> + /*
> + * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
> + * anything fails, the system will reset anyway.
> + */
> + sanitize_boot_params(bp);
> + bp->hdr.loadflags |= SLAUNCH_FLAG;
> +
> + sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
> +
> + /* Place event log SL specific tags before and after measurements */
> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
> +
> + /* Process all policy entries and extend the measurements to the evtlog */
> + sl_process_extend_policy(slrt);
> +
> + /* Process all EFI config entries and extend the measurements to the evtlog */
> + sl_process_extend_uefi_config(slrt);
> +
> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
> +
> + /* No PMR check is needed, the TXT heap is covered by the DPR */
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + /*
> + * Now that the OS-MLE data is measured, ensure the MTRR and
> + * misc enable MSRs are what we expect.
> + */
> + sl_txt_validate_msrs(os_mle_data);
> +}
> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
> new file mode 100644
> index 000000000000..24b8f23d5dcc
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_stub.S
> @@ -0,0 +1,725 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Secure Launch protected mode entry point.
> + *
> + * Copyright (c) 2024, Oracle and/or its affiliates.
> + */
> + .code32
> + .text
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/msr.h>
> +#include <asm/apicdef.h>
> +#include <asm/trapnr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/page_types.h>
> +#include <asm/irq_vectors.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +
> +/* CPUID: leaf 1, ECX, SMX feature bit */
> +#define X86_FEATURE_BIT_SMX (1 << 6)
> +
> +#define IDT_VECTOR_LO_BITS 0
> +#define IDT_VECTOR_HI_BITS 6
> +
> +/*
> + * See the comment in head_64.S for detailed information on what this macro
> + * and others like it are used for. The comment appears right at the top of
> + * the file.
> + */
> +#define rva(X) ((X) - sl_stub_entry)
> +
> +/*
> + * The GETSEC op code is open coded because older versions of
> + * GCC do not support the getsec mnemonic.
> + */
> +.macro GETSEC leaf
> + pushl %ebx
> + xorl %ebx, %ebx /* Must be zero for SMCTRL */
> + movl \leaf, %eax /* Leaf function */
> + .byte 0x0f, 0x37 /* GETSEC opcode */
> + popl %ebx
> +.endm
> +
> +.macro TXT_RESET error
> + /*
> + * Set a sticky error value and reset. Note the movs to %eax act as
> + * TXT register barriers.
> + */
> + movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
> +1:
> + hlt
> + jmp 1b
> +.endm
> +
> + .code32
> +SYM_FUNC_START(sl_stub_entry)
> + cli
> + cld
> +
> + /*
> + * On entry, %ebx has the entry abs offset to sl_stub_entry. This
> + * will be correctly scaled using the rva macro and avoid causing
> + * relocations. Only %cs and %ds segments are known good.
Could you please clarify this? 'scaling' is unidiomatic in this
context, and actually means something different in my book. AIUI, %ebx
is guaranteed to carry the actual address of sl_stub_entry(), and
rva() is used to generate relative references using %ebx as a base, as
to avoid /absolute/ relocations, which would require fixups at
runtime.
> + */
> +
> + /* Load GDT, set segment regs and lret to __SL32_CS */
> + leal rva(sl_gdt_desc)(%ebx), %eax
> + addl %eax, 2(%eax)
> + lgdt (%eax)
> +
> + movl $(__SL32_DS), %eax
> + movw %ax, %ds
> + movw %ax, %es
> + movw %ax, %fs
> + movw %ax, %gs
> + movw %ax, %ss
> +
> + /*
> + * Now that %ss is known good, take the first stack for the BSP. The
> + * AP stacks are only used on Intel.
> + */
> + leal rva(sl_stacks_end)(%ebx), %esp
> +
> + leal rva(.Lsl_cs)(%ebx), %eax
> + pushl $(__SL32_CS)
> + pushl %eax
> + lret
> +
> +.Lsl_cs:
> + /* Save our base pointer reg and page table for MLE */
> + pushl %ebx
> + pushl %ecx
> +
> + /* See if SMX feature is supported. */
> + movl $1, %eax
> + cpuid
> + testl $(X86_FEATURE_BIT_SMX), %ecx
> + jz .Ldo_unknown_cpu
> +
> + popl %ecx
> + popl %ebx
> +
> + /* Know it is Intel */
> + movl $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
> +
> + /* Locate the base of the MLE using the page tables in %ecx */
> + call sl_find_mle_base
> +
> + /* Increment CPU count for BSP */
> + incl rva(sl_txt_cpu_count)(%ebx)
> +
> + /*
> + * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
> + * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
> + * allow the mainline kernel re-enable them in the normal course of
> + * booting.
> + */
> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
> +
> + /* Clear the TXT error registers for a clean start of day */
> + movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> + movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
> +
> + /* On Intel, the zero page address is passed in the TXT heap */
> + /* Read physical base of heap into EAX */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
> + movl (%eax), %ecx
> + /* Skip over BIOS data and size of OS to MLE data section */
> + leal 8(%eax, %ecx), %eax
> +
> + /* Need to verify the values in the OS-MLE struct passed in */
> + call sl_txt_verify_os_mle_struct
> +
> + /*
> + * Get the boot params address from the heap. Note %esi and %ebx MUST
> + * be preserved across calls and operations.
> + */
> + movl SL_boot_params_addr(%eax), %esi
> +
> + /* Save %ebx so the APs can find their way home */
> + movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
> +
> + /* Fetch the AP wake code block address from the heap */
> + movl SL_ap_wake_block(%eax), %edi
> + movl %edi, rva(sl_txt_ap_wake_block)(%ebx)
> +
> + /* Store the offset in the AP wake block to the jmp address */
> + movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
> + (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
> +
> + /* Store the offset in the AP wake block to the AP stacks block */
> + movl $(sl_stacks - sl_txt_ap_wake_begin), \
> + (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
> +
> + /* %eax still is the base of the OS-MLE block, save it */
> + pushl %eax
> +
> + /* Relocate the AP wake code to the safe block */
> + call sl_txt_reloc_ap_wake
> +
> + /*
> + * Wake up all APs that are blocked in the ACM and wait for them to
> + * halt. This should be done before restoring the MTRRs so the ACM is
> + * still properly in WB memory.
> + */
> + call sl_txt_wake_aps
> +
> + /* Restore OS-MLE in %eax */
> + popl %eax
> +
> + /*
> + * %edi is used by this routine to find the MTRRs which are in the SLRT
> + * in the Intel info.
> + */
> + movl SL_txt_info(%eax), %edi
> + call sl_txt_load_regs
> +
> + jmp .Lcpu_setup_done
> +
> +.Ldo_unknown_cpu:
> + /* Non-Intel CPUs are not yet supported */
> + ud2
> +
> +.Lcpu_setup_done:
> + /*
> + * Don't enable MCE at this point. The kernel will enable
> + * it on the BSP later when it is ready.
> + */
> +
> + /* Done, jump to normal 32b pm entry */
> + jmp startup_32
> +SYM_FUNC_END(sl_stub_entry)
> +
> +SYM_FUNC_START(sl_find_mle_base)
> + /* %ecx has PDPT, get first PD */
> + movl (%ecx), %eax
> + andl $(PAGE_MASK), %eax
> + /* Get first PT from first PDE */
> + movl (%eax), %eax
> + andl $(PAGE_MASK), %eax
> + /* Get MLE base from first PTE */
> + movl (%eax), %eax
> + andl $(PAGE_MASK), %eax
> +
> + movl %eax, rva(sl_mle_start)(%ebx)
> + ret
> +SYM_FUNC_END(sl_find_mle_base)
> +
> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
> + /* %ecx: buffer begin %edx: buffer end */
> + /* %ebx: MLE begin %edi: MLE end */
> + /* %eax: region may be inside MLE */
> +
> + cmpl %edi, %ecx
> + jb .Lnext_check
> + cmpl %edi, %edx
> + jbe .Lnext_check
> + jmp .Lvalid /* Buffer above MLE */
> +
> +.Lnext_check:
> + cmpl %ebx, %edx
> + ja .Linside_check
> + cmpl %ebx, %ecx
> + jae .Linside_check
> + jmp .Lvalid /* Buffer below MLE */
> +
> +.Linside_check:
> + cmpl $0, %eax
> + jz .Linvalid
> + cmpl %ebx, %ecx
> + jb .Linvalid
> + cmpl %edi, %edx
> + ja .Linvalid
> + jmp .Lvalid /* Buffer in MLE */
> +
> +.Linvalid:
> + TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
> +
> +.Lvalid:
> + ret
> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
> +
> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
> + pushl %ebx
> + /*
> + * %eax points to the base of the OS-MLE struct. Need to also
> + * read some values from the OS-SINIT struct too.
> + */
> + movl -8(%eax), %ecx
> + /* Skip over OS to MLE data section and size of OS-SINIT structure */
> + leal (%eax, %ecx), %edx
> +
> + /* Load MLE image base absolute offset */
> + movl rva(sl_mle_start)(%ebx), %ebx
> +
> + /* Verify the value of the low PMR base. It should always be 0. */
> + movl SL_vtd_pmr_lo_base(%edx), %esi
> + cmpl $0, %esi
> + jz .Lvalid_pmr_base
> + TXT_RESET $(SL_ERROR_LO_PMR_BASE)
> +
> +.Lvalid_pmr_base:
> + /* Grab some values from OS-SINIT structure */
> + movl SL_mle_size(%edx), %edi
> + addl %ebx, %edi
> + jc .Loverflow_detected
> + movl SL_vtd_pmr_lo_size(%edx), %esi
> +
> + /* Check the AP wake block */
> + movl SL_ap_wake_block(%eax), %ecx
> + movl SL_ap_wake_block_size(%eax), %edx
> + addl %ecx, %edx
> + jc .Loverflow_detected
> + pushl %eax
> + xorl %eax, %eax
> + call sl_check_buffer_mle_overlap
> + popl %eax
> + cmpl %esi, %edx
> + ja .Lbuffer_beyond_pmr
> +
> + /*
> + * Check the boot params. Note during a UEFI boot, the boot
> + * params will be inside the MLE image. Test for this case
> + * in the overlap case.
> + */
> + movl SL_boot_params_addr(%eax), %ecx
> + movl $(PAGE_SIZE), %edx
> + addl %ecx, %edx
> + jc .Loverflow_detected
> + pushl %eax
> + movl $1, %eax
> + call sl_check_buffer_mle_overlap
> + popl %eax
> + cmpl %esi, %edx
> + ja .Lbuffer_beyond_pmr
> +
> + /* Check that the AP wake block is big enough */
> + cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
> + SL_ap_wake_block_size(%eax)
> + jae .Lwake_block_ok
> + TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
> +
> +.Lwake_block_ok:
> + popl %ebx
> + ret
> +
> +.Loverflow_detected:
> + TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
> +
> +.Lbuffer_beyond_pmr:
> + TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
> +
> +SYM_FUNC_START(sl_txt_ap_entry)
> + cli
> + cld
> + /*
> + * The %cs and %ds segments are known good after waking the AP.
> + * First order of business is to find where we are and
> + * save it in %ebx.
> + */
> +
> + /* Read physical base of heap into EAX */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
> + movl (%eax), %ecx
> + /* Skip over BIOS data and size of OS to MLE data section */
> + leal 8(%eax, %ecx), %eax
> +
> + /* Saved %ebx from the BSP and stash OS-MLE pointer */
> + movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
> +
> + /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
> + movl SL_txt_info(%eax), %edi
> +
> + /* Lock and get our stack index */
> + movl $1, %ecx
> +.Lspin:
> + xorl %eax, %eax
> + lock cmpxchgl %ecx, rva(sl_txt_spin_lock)(%ebx)
> + pause
> + jnz .Lspin
> +
> + /* Increment the stack index and use the next value inside lock */
> + incl rva(sl_txt_stack_index)(%ebx)
> + movl rva(sl_txt_stack_index)(%ebx), %eax
> +
> + /* Unlock */
> + movl $0, rva(sl_txt_spin_lock)(%ebx)
> +
> + /* Location of the relocated AP wake block */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
> +
> + /* Load reloc GDT, set segment regs and lret to __SL32_CS */
> + lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> + movl $(__SL32_DS), %edx
> + movw %dx, %ds
> + movw %dx, %es
> + movw %dx, %fs
> + movw %dx, %gs
> + movw %dx, %ss
> +
> + /* Load our reloc AP stack */
> + movl $(TXT_BOOT_STACK_SIZE), %edx
> + mull %edx
> + leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
> + subl %eax, %esp
> +
> + /* Switch to AP code segment */
> + leal rva(.Lsl_ap_cs)(%ebx), %eax
> + pushl $(__SL32_CS)
> + pushl %eax
> + lret
> +
> +.Lsl_ap_cs:
> + /* Load the relocated AP IDT */
> + lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> + /* Fixup MTRRs and misc enable MSR on APs too */
> + call sl_txt_load_regs
> +
> + /* Enable SMI with GETSEC[SMCTRL] */
> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
> +
> + /* IRET-to-self can be used to enable NMIs which SENTER disabled */
> + leal rva(.Lnmi_enabled_ap)(%ebx), %eax
> + pushfl
> + pushl $(__SL32_CS)
> + pushl %eax
> + iret
> +
> +.Lnmi_enabled_ap:
> + /* Put APs in X2APIC mode like the BSP */
> + movl $(MSR_IA32_APICBASE), %ecx
> + rdmsr
> + orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
> + wrmsr
> +
> + /*
> + * Basically done, increment the CPU count and jump off to the AP
> + * wake block to wait.
> + */
> + lock incl rva(sl_txt_cpu_count)(%ebx)
> +
> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
> + jmp *%eax
> +SYM_FUNC_END(sl_txt_ap_entry)
> +
> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
> + /* Save boot params register */
> + pushl %esi
> +
> + movl rva(sl_txt_ap_wake_block)(%ebx), %edi
> +
> + /* Fixup AP IDT and GDT descriptor before relocating */
> + leal rva(sl_ap_idt_desc)(%ebx), %eax
> + addl %edi, 2(%eax)
> + leal rva(sl_ap_gdt_desc)(%ebx), %eax
> + addl %edi, 2(%eax)
> +
> + /*
> + * Copy the AP wake code and AP GDT/IDT to the protected wake block
> + * provided by the loader. Destination already in %edi.
> + */
> + movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
> + leal rva(sl_txt_ap_wake_begin)(%ebx), %esi
> + rep movsb
> +
> + /* Setup the IDT for the APs to use in the relocation block */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
> + addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
> + xorl %edx, %edx
> +
> + /* Form the default reset vector relocation address */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %esi
> + addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
> +
> +1:
> + cmpw $(NR_VECTORS), %dx
> + jz .Lap_idt_done
> +
> + cmpw $(X86_TRAP_NMI), %dx
> + jz 2f
> +
> + /* Load all other fixed vectors with reset handler */
> + movl %esi, %eax
> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> + shrl $16, %eax
> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> + jmp 3f
> +
> +2:
> + /* Load single wake NMI IPI vector at the relocation address */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
> + addl $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> + shrl $16, %eax
> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> +
> +3:
> + incw %dx
> + addl $8, %ecx
> + jmp 1b
> +
> +.Lap_idt_done:
> + popl %esi
> + ret
> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
> +
> +SYM_FUNC_START(sl_txt_load_regs)
> + /* Save base pointer register */
> + pushl %ebx
> +
> + /*
> + * On Intel, the original variable MTRRs and Misc Enable MSR are
> + * restored on the BSP at early boot. Each AP will also restore
> + * its MTRRs and Misc Enable MSR.
> + */
> + pushl %edi
> + addl $(SL_saved_bsp_mtrrs), %edi
> + movl (%edi), %ebx
> + pushl %ebx /* default_mem_type lo */
> + addl $4, %edi
> + movl (%edi), %ebx
> + pushl %ebx /* default_mem_type hi */
> + addl $4, %edi
> + movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
> + addl $8, %edi /* now at MTRR pair array */
> + /* Write the variable MTRRs */
> + movl $(MSR_MTRRphysBase0), %ecx
> +1:
> + cmpl $0, %ebx
> + jz 2f
> +
> + movl (%edi), %eax /* MTRRphysBaseX lo */
> + addl $4, %edi
> + movl (%edi), %edx /* MTRRphysBaseX hi */
> + wrmsr
> + addl $4, %edi
> + incl %ecx
> + movl (%edi), %eax /* MTRRphysMaskX lo */
> + addl $4, %edi
> + movl (%edi), %edx /* MTRRphysMaskX hi */
> + wrmsr
> + addl $4, %edi
> + incl %ecx
> +
> + decl %ebx
> + jmp 1b
> +2:
> + /* Write the default MTRR register */
> + popl %edx
> + popl %eax
> + movl $(MSR_MTRRdefType), %ecx
> + wrmsr
> +
> + /* Return to beginning and write the misc enable msr */
> + popl %edi
> + addl $(SL_saved_misc_enable_msr), %edi
> + movl (%edi), %eax /* saved_misc_enable_msr lo */
> + addl $4, %edi
> + movl (%edi), %edx /* saved_misc_enable_msr hi */
> + movl $(MSR_IA32_MISC_ENABLE), %ecx
> + wrmsr
> +
> + popl %ebx
> + ret
> +SYM_FUNC_END(sl_txt_load_regs)
> +
> +SYM_FUNC_START(sl_txt_wake_aps)
> + /* Save boot params register */
> + pushl %esi
> +
> + /* First setup the MLE join structure and load it into TXT reg */
> + leal rva(sl_gdt)(%ebx), %eax
> + leal rva(sl_txt_ap_entry)(%ebx), %ecx
> + leal rva(sl_smx_rlp_mle_join)(%ebx), %edx
> + movl %eax, SL_rlp_gdt_base(%edx)
> + movl %ecx, SL_rlp_entry_point(%edx)
> + movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
> +
> + /* Another TXT heap walk to find various values needed to wake APs */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* At BIOS data size, find the number of logical processors */
> + movl (SL_num_logical_procs + 8)(%eax), %edx
> + /* Skip over BIOS data */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* Skip over OS to MLE */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* At OS-SNIT size, get capabilities to know how to wake up the APs */
> + movl (SL_capabilities + 8)(%eax), %esi
> + /* Skip over OS to SNIT */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* At SINIT-MLE size, get the AP wake MONITOR address */
> + movl (SL_rlp_wakeup_addr + 8)(%eax), %edi
> +
> + /* Determine how to wake up the APs */
> + testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
> + jz .Lwake_getsec
> +
> + /* Wake using MWAIT MONITOR */
> + movl $1, (%edi)
> + jmp .Laps_awake
> +
> +.Lwake_getsec:
> + /* Wake using GETSEC(WAKEUP) */
> + GETSEC $(SMX_X86_GETSEC_WAKEUP)
> +
> +.Laps_awake:
> + /*
> + * All of the APs are woken up and rendesvous in the relocated wake
> + * block starting at sl_txt_ap_wake_begin. Wait for all of them to
> + * halt.
> + */
> + pause
> + cmpl rva(sl_txt_cpu_count)(%ebx), %edx
> + jne .Laps_awake
> +
> + popl %esi
> + ret
> +SYM_FUNC_END(sl_txt_wake_aps)
> +
> +/* This is the beginning of the relocated AP wake code block */
> + .global sl_txt_ap_wake_begin
> +sl_txt_ap_wake_begin:
> +
> + /* Get the LAPIC ID for each AP and stash it on the stack */
> + movl $(MSR_IA32_X2APIC_APICID), %ecx
> + rdmsr
> + pushl %eax
> +
> + /*
> + * Get a pointer to the monitor location on this APs stack to test below
> + * after mwait returns. Currently %esp points to just past the pushed APIC
> + * ID value.
> + */
> + movl %esp, %eax
> + subl $(TXT_BOOT_STACK_SIZE - 4), %eax
> + movl $0, (%eax)
> +
> + /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
> + xorl %ecx, %ecx
> + xorl %edx, %edx
> +
> + /*
> + * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
> + * instruction can return for a number of reasons. Test to see if it returned
> + * because the monitor was written to.
> + */
> + monitor
> +
> +1:
> + mfence
> + mwait
> + movl (%eax), %edx
> + testl %edx, %edx
> + jz 1b
> +
> + /*
> + * This is the long absolute jump to the 32b Secure Launch protected mode stub
> + * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
> + * fixed in the SMP boot code when the first AP is brought up. This whole area
> + * is provided and protected in the memory map by the prelaunch code.
> + */
> + .byte 0xea
> +sl_ap_jmp_offset:
> + .long 0x00000000
> + .word __SL32_CS
> +
> +SYM_FUNC_START(sl_txt_int_nmi)
> + /* NMI context, just IRET */
> + iret
> +SYM_FUNC_END(sl_txt_int_nmi)
> +
> +SYM_FUNC_START(sl_txt_int_reset)
> + TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
> +SYM_FUNC_END(sl_txt_int_reset)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
> + .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */
> + .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */
> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt)
> + .rept NR_VECTORS
> + .word 0x0000 /* Offset 15 to 0 */
> + .word __SL32_CS /* Segment selector */
> + .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */
> + .word 0x0000 /* Offset 31 to 16 */
> + .endr
> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
> + .word sl_ap_gdt_end - sl_ap_gdt - 1
> + .long sl_ap_gdt - sl_txt_ap_wake_begin
> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt)
> + .quad 0x0000000000000000 /* NULL */
> + .quad 0x00cf9a000000ffff /* __SL32_CS */
> + .quad 0x00cf92000000ffff /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
> +
> + /* Small stacks for BSP and APs to work with */
> + .balign 64
> +SYM_DATA_START_LOCAL(sl_stacks)
> + .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
> +
> +/* This is the end of the relocated AP wake code block */
> + .global sl_txt_ap_wake_end
> +sl_txt_ap_wake_end:
> +
> + .data
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt_desc)
> + .word sl_gdt_end - sl_gdt - 1
> + .long sl_gdt - sl_gdt_desc
> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt)
> + .quad 0x0000000000000000 /* NULL */
> + .quad 0x00cf9a000000ffff /* __SL32_CS */
> + .quad 0x00cf92000000ffff /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
> + .long sl_gdt_end - sl_gdt - 1 /* GDT limit */
> + .long 0x00000000 /* GDT base */
> + .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
> + .long 0x00000000 /* Entry point physical address */
> +SYM_DATA_END(sl_smx_rlp_mle_join)
> +
> +SYM_DATA(sl_cpu_type, .long 0x00000000)
> +
> +SYM_DATA(sl_mle_start, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
> index e022e6eb766c..37f6167f28ba 100644
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -348,6 +348,9 @@
> #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
> #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561
>
> +#define MSR_MTRRphysBase0 0x00000200
> +#define MSR_MTRRphysMask0 0x00000201
> +
> #define MSR_MTRRfix64K_00000 0x00000250
> #define MSR_MTRRfix16K_80000 0x00000258
> #define MSR_MTRRfix16K_A0000 0x00000259
> @@ -849,6 +852,8 @@
> #define MSR_IA32_APICBASE_ENABLE (1<<11)
> #define MSR_IA32_APICBASE_BASE (0xfffff<<12)
>
> +#define MSR_IA32_X2APIC_APICID 0x00000802
> +
> #define MSR_IA32_UCODE_WRITE 0x00000079
> #define MSR_IA32_UCODE_REV 0x0000008b
>
> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> index 9b82eebd7add..7ce283a22d6b 100644
> --- a/arch/x86/include/uapi/asm/bootparam.h
> +++ b/arch/x86/include/uapi/asm/bootparam.h
> @@ -12,6 +12,7 @@
> /* loadflags */
> #define LOADED_HIGH (1<<0)
> #define KASLR_FLAG (1<<1)
> +#define SLAUNCH_FLAG (1<<2)
> #define QUIET_FLAG (1<<5)
> #define KEEP_SEGMENTS (1<<6)
> #define CAN_USE_HEAP (1<<7)
> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
> index a98020bf31bb..925adce6e2c7 100644
> --- a/arch/x86/kernel/asm-offsets.c
> +++ b/arch/x86/kernel/asm-offsets.c
> @@ -13,6 +13,8 @@
> #include <linux/hardirq.h>
> #include <linux/suspend.h>
> #include <linux/kbuild.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> #include <asm/processor.h>
> #include <asm/thread_info.h>
> #include <asm/sigframe.h>
> @@ -120,4 +122,22 @@ static void __used common(void)
> OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
> #endif
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + BLANK();
> + OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
> + OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
> + OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
> + OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
> + OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
> + OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
> + OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
> + OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
> + OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
> + OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
> + OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
> + OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
> + OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
> + OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
> + OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
> +#endif
> }
> --
> 2.39.3
>
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 11:00 ` Ard Biesheuvel
@ 2024-05-31 13:33 ` Ard Biesheuvel
2024-05-31 14:04 ` Ard Biesheuvel
2024-06-04 17:24 ` ross.philipson
2024-06-04 17:14 ` ross.philipson
1 sibling, 2 replies; 113+ messages in thread
From: Ard Biesheuvel @ 2024-05-31 13:33 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> Hello Ross,
>
> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
> >
> > The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> > later AMD SKINIT) to vector to during the late launch. The symbol
> > sl_stub_entry is that entry point and its offset into the kernel is
> > conveyed to the launching code using the MLE (Measured Launch
> > Environment) header in the structure named mle_header. The offset of the
> > MLE header is set in the kernel_info. The routine sl_stub contains the
> > very early late launch setup code responsible for setting up the basic
> > environment to allow the normal kernel startup_32 code to proceed. It is
> > also responsible for properly waking and handling the APs on Intel
> > platforms. The routine sl_main which runs after entering 64b mode is
> > responsible for measuring configuration and module information before
> > it is used like the boot params, the kernel command line, the TXT heap,
> > an external initramfs, etc.
> >
> > Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> > ---
> > Documentation/arch/x86/boot.rst | 21 +
> > arch/x86/boot/compressed/Makefile | 3 +-
> > arch/x86/boot/compressed/head_64.S | 30 +
> > arch/x86/boot/compressed/kernel_info.S | 34 ++
> > arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> > arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> > arch/x86/include/asm/msr-index.h | 5 +
> > arch/x86/include/uapi/asm/bootparam.h | 1 +
> > arch/x86/kernel/asm-offsets.c | 20 +
> > 9 files changed, 1415 insertions(+), 1 deletion(-)
> > create mode 100644 arch/x86/boot/compressed/sl_main.c
> > create mode 100644 arch/x86/boot/compressed/sl_stub.S
> >
> > diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> > index 4fd492cb4970..295cdf9bcbdb 100644
> > --- a/Documentation/arch/x86/boot.rst
> > +++ b/Documentation/arch/x86/boot.rst
> > @@ -482,6 +482,14 @@ Protocol: 2.00+
> > - If 1, KASLR enabled.
> > - If 0, KASLR disabled.
> >
> > + Bit 2 (kernel internal): SLAUNCH_FLAG
> > +
> > + - Used internally by the setup kernel to communicate
> > + Secure Launch status to kernel proper.
> > +
> > + - If 1, Secure Launch enabled.
> > + - If 0, Secure Launch disabled.
> > +
> > Bit 5 (write): QUIET_FLAG
> >
> > - If 0, print early messages.
> > @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
> >
> > This field contains maximal allowed type for setup_data and setup_indirect structs.
> >
> > +============ =================
> > +Field name: mle_header_offset
> > +Offset/size: 0x0010/4
> > +============ =================
> > +
> > + This field contains the offset to the Secure Launch Measured Launch Environment
> > + (MLE) header. This offset is used to locate information needed during a secure
> > + late launch using Intel TXT. If the offset is zero, the kernel does not have
> > + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> > + following a success measured launch. The specific state of the processors is
> > + outlined in the TXT Software Development Guide, the latest can be found here:
> > + https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> > +
> >
>
> Could we just repaint this field as the offset relative to the start
> of kernel_info rather than relative to the start of the image? That
> way, there is no need for patch #1, and given that the consumer of
> this field accesses it via kernel_info, I wouldn't expect any issues
> in applying this offset to obtain the actual address.
>
>
> > The Image Checksum
> > ==================
> > diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> > index 9189a0e28686..9076a248d4b4 100644
> > --- a/arch/x86/boot/compressed/Makefile
> > +++ b/arch/x86/boot/compressed/Makefile
> > @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> > vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> > vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> >
> > -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> > +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> > + $(obj)/sl_main.o $(obj)/sl_stub.o
> >
> > $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> > $(call if_changed,ld)
> > diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> > index 1dcb794c5479..803c9e2e6d85 100644
> > --- a/arch/x86/boot/compressed/head_64.S
> > +++ b/arch/x86/boot/compressed/head_64.S
> > @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> > pushq $0
> > popfq
> >
> > +#ifdef CONFIG_SECURE_LAUNCH
> > + /* Ensure the relocation region is coverd by a PMR */
>
> covered
>
> > + movq %rbx, %rdi
> > + movl $(_bss - startup_32), %esi
> > + callq sl_check_region
> > +#endif
> > +
> > /*
> > * Copy the compressed kernel to the end of our buffer
> > * where decompression in place becomes safe.
> > @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> > shrq $3, %rcx
> > rep stosq
> >
> > +#ifdef CONFIG_SECURE_LAUNCH
> > + /*
> > + * Have to do the final early sl stub work in 64b area.
> > + *
> > + * *********** NOTE ***********
> > + *
> > + * Several boot params get used before we get a chance to measure
> > + * them in this call. This is a known issue and we currently don't
> > + * have a solution. The scratch field doesn't matter. There is no
> > + * obvious way to do anything about the use of kernel_alignment or
> > + * init_size though these seem low risk with all the PMR and overlap
> > + * checks in place.
> > + */
> > + movq %r15, %rdi
> > + callq sl_main
> > +
> > + /* Ensure the decompression location is covered by a PMR */
> > + movq %rbp, %rdi
> > + movq output_len(%rip), %rsi
> > + callq sl_check_region
> > +#endif
> > +
> > + pushq %rsi
>
> This looks like a rebase error.
>
> > call load_stage2_idt
> >
> > /* Pass boot_params to initialize_identity_maps() */
> > diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> > index c18f07181dd5..e199b87764e9 100644
> > --- a/arch/x86/boot/compressed/kernel_info.S
> > +++ b/arch/x86/boot/compressed/kernel_info.S
> > @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> > /* Maximal allowed type for setup_data and setup_indirect structs. */
> > .long SETUP_TYPE_MAX
> >
> > + /* Offset to the MLE header structure */
> > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > + .long rva(mle_header)
>
> ... so this could just be mle_header - kernel_info, and the consumer
> can do the math instead.
>
> > +#else
> > + .long 0
> > +#endif
> > +
> > kernel_info_var_len_data:
> > /* Empty for time being... */
> > SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> > +
> > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > + /*
> > + * The MLE Header per the TXT Specification, section 2.1
> > + * MLE capabilities, see table 4. Capabilities set:
> > + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> > + * bit 1: Support for RLP wakeup using MONITOR address
> > + * bit 2: The ECX register will contain the pointer to the MLE page table
> > + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> > + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> > + */
> > +SYM_DATA_START(mle_header)
> > + .long 0x9082ac5a /* UUID0 */
> > + .long 0x74a7476f /* UUID1 */
> > + .long 0xa2555c0f /* UUID2 */
> > + .long 0x42b651cb /* UUID3 */
> > + .long 0x00000034 /* MLE header size */
> > + .long 0x00020002 /* MLE version 2.2 */
> > + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>
> and these should perhaps be relative to mle_header?
>
> > + .long 0x00000000 /* First valid page of MLE */
> > + .long 0x00000000 /* Offset within binary of first byte of MLE */
> > + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>
> and here
>
Ugh never mind - these are specified externally.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 13:33 ` Ard Biesheuvel
@ 2024-05-31 14:04 ` Ard Biesheuvel
2024-05-31 16:13 ` Ard Biesheuvel
2024-06-04 17:31 ` ross.philipson
2024-06-04 17:24 ` ross.philipson
1 sibling, 2 replies; 113+ messages in thread
From: Ard Biesheuvel @ 2024-05-31 14:04 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Fri, 31 May 2024 at 15:33, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
> >
> > Hello Ross,
> >
> > On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
> > >
> > > The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> > > later AMD SKINIT) to vector to during the late launch. The symbol
> > > sl_stub_entry is that entry point and its offset into the kernel is
> > > conveyed to the launching code using the MLE (Measured Launch
> > > Environment) header in the structure named mle_header. The offset of the
> > > MLE header is set in the kernel_info. The routine sl_stub contains the
> > > very early late launch setup code responsible for setting up the basic
> > > environment to allow the normal kernel startup_32 code to proceed. It is
> > > also responsible for properly waking and handling the APs on Intel
> > > platforms. The routine sl_main which runs after entering 64b mode is
> > > responsible for measuring configuration and module information before
> > > it is used like the boot params, the kernel command line, the TXT heap,
> > > an external initramfs, etc.
> > >
> > > Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> > > ---
> > > Documentation/arch/x86/boot.rst | 21 +
> > > arch/x86/boot/compressed/Makefile | 3 +-
> > > arch/x86/boot/compressed/head_64.S | 30 +
> > > arch/x86/boot/compressed/kernel_info.S | 34 ++
> > > arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> > > arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> > > arch/x86/include/asm/msr-index.h | 5 +
> > > arch/x86/include/uapi/asm/bootparam.h | 1 +
> > > arch/x86/kernel/asm-offsets.c | 20 +
> > > 9 files changed, 1415 insertions(+), 1 deletion(-)
> > > create mode 100644 arch/x86/boot/compressed/sl_main.c
> > > create mode 100644 arch/x86/boot/compressed/sl_stub.S
> > >
> > > diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> > > index 4fd492cb4970..295cdf9bcbdb 100644
> > > --- a/Documentation/arch/x86/boot.rst
> > > +++ b/Documentation/arch/x86/boot.rst
> > > @@ -482,6 +482,14 @@ Protocol: 2.00+
> > > - If 1, KASLR enabled.
> > > - If 0, KASLR disabled.
> > >
> > > + Bit 2 (kernel internal): SLAUNCH_FLAG
> > > +
> > > + - Used internally by the setup kernel to communicate
> > > + Secure Launch status to kernel proper.
> > > +
> > > + - If 1, Secure Launch enabled.
> > > + - If 0, Secure Launch disabled.
> > > +
> > > Bit 5 (write): QUIET_FLAG
> > >
> > > - If 0, print early messages.
> > > @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
> > >
> > > This field contains maximal allowed type for setup_data and setup_indirect structs.
> > >
> > > +============ =================
> > > +Field name: mle_header_offset
> > > +Offset/size: 0x0010/4
> > > +============ =================
> > > +
> > > + This field contains the offset to the Secure Launch Measured Launch Environment
> > > + (MLE) header. This offset is used to locate information needed during a secure
> > > + late launch using Intel TXT. If the offset is zero, the kernel does not have
> > > + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> > > + following a success measured launch. The specific state of the processors is
> > > + outlined in the TXT Software Development Guide, the latest can be found here:
> > > + https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> > > +
> > >
> >
> > Could we just repaint this field as the offset relative to the start
> > of kernel_info rather than relative to the start of the image? That
> > way, there is no need for patch #1, and given that the consumer of
> > this field accesses it via kernel_info, I wouldn't expect any issues
> > in applying this offset to obtain the actual address.
> >
> >
> > > The Image Checksum
> > > ==================
> > > diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> > > index 9189a0e28686..9076a248d4b4 100644
> > > --- a/arch/x86/boot/compressed/Makefile
> > > +++ b/arch/x86/boot/compressed/Makefile
> > > @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> > > vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> > > vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> > >
> > > -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> > > +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> > > + $(obj)/sl_main.o $(obj)/sl_stub.o
> > >
> > > $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> > > $(call if_changed,ld)
> > > diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> > > index 1dcb794c5479..803c9e2e6d85 100644
> > > --- a/arch/x86/boot/compressed/head_64.S
> > > +++ b/arch/x86/boot/compressed/head_64.S
> > > @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> > > pushq $0
> > > popfq
> > >
> > > +#ifdef CONFIG_SECURE_LAUNCH
> > > + /* Ensure the relocation region is coverd by a PMR */
> >
> > covered
> >
> > > + movq %rbx, %rdi
> > > + movl $(_bss - startup_32), %esi
> > > + callq sl_check_region
> > > +#endif
> > > +
> > > /*
> > > * Copy the compressed kernel to the end of our buffer
> > > * where decompression in place becomes safe.
> > > @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> > > shrq $3, %rcx
> > > rep stosq
> > >
> > > +#ifdef CONFIG_SECURE_LAUNCH
> > > + /*
> > > + * Have to do the final early sl stub work in 64b area.
> > > + *
> > > + * *********** NOTE ***********
> > > + *
> > > + * Several boot params get used before we get a chance to measure
> > > + * them in this call. This is a known issue and we currently don't
> > > + * have a solution. The scratch field doesn't matter. There is no
> > > + * obvious way to do anything about the use of kernel_alignment or
> > > + * init_size though these seem low risk with all the PMR and overlap
> > > + * checks in place.
> > > + */
> > > + movq %r15, %rdi
> > > + callq sl_main
> > > +
> > > + /* Ensure the decompression location is covered by a PMR */
> > > + movq %rbp, %rdi
> > > + movq output_len(%rip), %rsi
> > > + callq sl_check_region
> > > +#endif
> > > +
> > > + pushq %rsi
> >
> > This looks like a rebase error.
> >
> > > call load_stage2_idt
> > >
> > > /* Pass boot_params to initialize_identity_maps() */
> > > diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> > > index c18f07181dd5..e199b87764e9 100644
> > > --- a/arch/x86/boot/compressed/kernel_info.S
> > > +++ b/arch/x86/boot/compressed/kernel_info.S
> > > @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> > > /* Maximal allowed type for setup_data and setup_indirect structs. */
> > > .long SETUP_TYPE_MAX
> > >
> > > + /* Offset to the MLE header structure */
> > > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > > + .long rva(mle_header)
> >
> > ... so this could just be mle_header - kernel_info, and the consumer
> > can do the math instead.
> >
> > > +#else
> > > + .long 0
> > > +#endif
> > > +
> > > kernel_info_var_len_data:
> > > /* Empty for time being... */
> > > SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> > > +
> > > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > > + /*
> > > + * The MLE Header per the TXT Specification, section 2.1
> > > + * MLE capabilities, see table 4. Capabilities set:
> > > + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> > > + * bit 1: Support for RLP wakeup using MONITOR address
> > > + * bit 2: The ECX register will contain the pointer to the MLE page table
> > > + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> > > + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> > > + */
> > > +SYM_DATA_START(mle_header)
> > > + .long 0x9082ac5a /* UUID0 */
> > > + .long 0x74a7476f /* UUID1 */
> > > + .long 0xa2555c0f /* UUID2 */
> > > + .long 0x42b651cb /* UUID3 */
> > > + .long 0x00000034 /* MLE header size */
> > > + .long 0x00020002 /* MLE version 2.2 */
> > > + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> >
> > and these should perhaps be relative to mle_header?
> >
> > > + .long 0x00000000 /* First valid page of MLE */
> > > + .long 0x00000000 /* Offset within binary of first byte of MLE */
> > > + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> >
> > and here
> >
>
> Ugh never mind - these are specified externally.
OK, so instead of patch #1, please use the linker script to generate
these constants.
I.e., add this to arch/x86/boot/compressed/vmlinux.lds.S
#ifdef CONFIG_SECURE_LAUNCH
PROVIDE(mle_header_offset = mle_header - startup_32);
PROVIDE(sl_stub_entry_offset = sl_stub_entry - startup_32);
PROVIDE(_edata_offset = _edata - startup_32);
#endif
and use the symbols on the left hand side in the code.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 14:04 ` Ard Biesheuvel
@ 2024-05-31 16:13 ` Ard Biesheuvel
2024-06-04 17:31 ` ross.philipson
1 sibling, 0 replies; 113+ messages in thread
From: Ard Biesheuvel @ 2024-05-31 16:13 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Fri, 31 May 2024 at 16:04, Ard Biesheuvel <ardb@kernel.org> wrote:
>
> On Fri, 31 May 2024 at 15:33, Ard Biesheuvel <ardb@kernel.org> wrote:
> >
> > On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
> > >
> > > Hello Ross,
> > >
> > > On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
> > > >
> > > > The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> > > > later AMD SKINIT) to vector to during the late launch. The symbol
> > > > sl_stub_entry is that entry point and its offset into the kernel is
> > > > conveyed to the launching code using the MLE (Measured Launch
> > > > Environment) header in the structure named mle_header. The offset of the
> > > > MLE header is set in the kernel_info. The routine sl_stub contains the
> > > > very early late launch setup code responsible for setting up the basic
> > > > environment to allow the normal kernel startup_32 code to proceed. It is
> > > > also responsible for properly waking and handling the APs on Intel
> > > > platforms. The routine sl_main which runs after entering 64b mode is
> > > > responsible for measuring configuration and module information before
> > > > it is used like the boot params, the kernel command line, the TXT heap,
> > > > an external initramfs, etc.
> > > >
> > > > Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> > > > ---
> > > > Documentation/arch/x86/boot.rst | 21 +
> > > > arch/x86/boot/compressed/Makefile | 3 +-
> > > > arch/x86/boot/compressed/head_64.S | 30 +
> > > > arch/x86/boot/compressed/kernel_info.S | 34 ++
> > > > arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> > > > arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> > > > arch/x86/include/asm/msr-index.h | 5 +
> > > > arch/x86/include/uapi/asm/bootparam.h | 1 +
> > > > arch/x86/kernel/asm-offsets.c | 20 +
> > > > 9 files changed, 1415 insertions(+), 1 deletion(-)
> > > > create mode 100644 arch/x86/boot/compressed/sl_main.c
> > > > create mode 100644 arch/x86/boot/compressed/sl_stub.S
> > > >
> > > > diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> > > > index 4fd492cb4970..295cdf9bcbdb 100644
> > > > --- a/Documentation/arch/x86/boot.rst
> > > > +++ b/Documentation/arch/x86/boot.rst
> > > > @@ -482,6 +482,14 @@ Protocol: 2.00+
> > > > - If 1, KASLR enabled.
> > > > - If 0, KASLR disabled.
> > > >
> > > > + Bit 2 (kernel internal): SLAUNCH_FLAG
> > > > +
> > > > + - Used internally by the setup kernel to communicate
> > > > + Secure Launch status to kernel proper.
> > > > +
> > > > + - If 1, Secure Launch enabled.
> > > > + - If 0, Secure Launch disabled.
> > > > +
> > > > Bit 5 (write): QUIET_FLAG
> > > >
> > > > - If 0, print early messages.
> > > > @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
> > > >
> > > > This field contains maximal allowed type for setup_data and setup_indirect structs.
> > > >
> > > > +============ =================
> > > > +Field name: mle_header_offset
> > > > +Offset/size: 0x0010/4
> > > > +============ =================
> > > > +
> > > > + This field contains the offset to the Secure Launch Measured Launch Environment
> > > > + (MLE) header. This offset is used to locate information needed during a secure
> > > > + late launch using Intel TXT. If the offset is zero, the kernel does not have
> > > > + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> > > > + following a success measured launch. The specific state of the processors is
> > > > + outlined in the TXT Software Development Guide, the latest can be found here:
> > > > + https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> > > > +
> > > >
> > >
> > > Could we just repaint this field as the offset relative to the start
> > > of kernel_info rather than relative to the start of the image? That
> > > way, there is no need for patch #1, and given that the consumer of
> > > this field accesses it via kernel_info, I wouldn't expect any issues
> > > in applying this offset to obtain the actual address.
> > >
> > >
> > > > The Image Checksum
> > > > ==================
> > > > diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> > > > index 9189a0e28686..9076a248d4b4 100644
> > > > --- a/arch/x86/boot/compressed/Makefile
> > > > +++ b/arch/x86/boot/compressed/Makefile
> > > > @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> > > > vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> > > > vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> > > >
> > > > -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> > > > +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> > > > + $(obj)/sl_main.o $(obj)/sl_stub.o
> > > >
> > > > $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> > > > $(call if_changed,ld)
> > > > diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> > > > index 1dcb794c5479..803c9e2e6d85 100644
> > > > --- a/arch/x86/boot/compressed/head_64.S
> > > > +++ b/arch/x86/boot/compressed/head_64.S
> > > > @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> > > > pushq $0
> > > > popfq
> > > >
> > > > +#ifdef CONFIG_SECURE_LAUNCH
> > > > + /* Ensure the relocation region is coverd by a PMR */
> > >
> > > covered
> > >
> > > > + movq %rbx, %rdi
> > > > + movl $(_bss - startup_32), %esi
> > > > + callq sl_check_region
> > > > +#endif
> > > > +
> > > > /*
> > > > * Copy the compressed kernel to the end of our buffer
> > > > * where decompression in place becomes safe.
> > > > @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> > > > shrq $3, %rcx
> > > > rep stosq
> > > >
> > > > +#ifdef CONFIG_SECURE_LAUNCH
> > > > + /*
> > > > + * Have to do the final early sl stub work in 64b area.
> > > > + *
> > > > + * *********** NOTE ***********
> > > > + *
> > > > + * Several boot params get used before we get a chance to measure
> > > > + * them in this call. This is a known issue and we currently don't
> > > > + * have a solution. The scratch field doesn't matter. There is no
> > > > + * obvious way to do anything about the use of kernel_alignment or
> > > > + * init_size though these seem low risk with all the PMR and overlap
> > > > + * checks in place.
> > > > + */
> > > > + movq %r15, %rdi
> > > > + callq sl_main
> > > > +
> > > > + /* Ensure the decompression location is covered by a PMR */
> > > > + movq %rbp, %rdi
> > > > + movq output_len(%rip), %rsi
> > > > + callq sl_check_region
> > > > +#endif
> > > > +
> > > > + pushq %rsi
> > >
> > > This looks like a rebase error.
> > >
> > > > call load_stage2_idt
> > > >
> > > > /* Pass boot_params to initialize_identity_maps() */
> > > > diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> > > > index c18f07181dd5..e199b87764e9 100644
> > > > --- a/arch/x86/boot/compressed/kernel_info.S
> > > > +++ b/arch/x86/boot/compressed/kernel_info.S
> > > > @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> > > > /* Maximal allowed type for setup_data and setup_indirect structs. */
> > > > .long SETUP_TYPE_MAX
> > > >
> > > > + /* Offset to the MLE header structure */
> > > > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > > > + .long rva(mle_header)
> > >
> > > ... so this could just be mle_header - kernel_info, and the consumer
> > > can do the math instead.
> > >
> > > > +#else
> > > > + .long 0
> > > > +#endif
> > > > +
> > > > kernel_info_var_len_data:
> > > > /* Empty for time being... */
> > > > SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> > > > +
> > > > +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> > > > + /*
> > > > + * The MLE Header per the TXT Specification, section 2.1
> > > > + * MLE capabilities, see table 4. Capabilities set:
> > > > + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> > > > + * bit 1: Support for RLP wakeup using MONITOR address
> > > > + * bit 2: The ECX register will contain the pointer to the MLE page table
> > > > + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> > > > + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> > > > + */
> > > > +SYM_DATA_START(mle_header)
> > > > + .long 0x9082ac5a /* UUID0 */
> > > > + .long 0x74a7476f /* UUID1 */
> > > > + .long 0xa2555c0f /* UUID2 */
> > > > + .long 0x42b651cb /* UUID3 */
> > > > + .long 0x00000034 /* MLE header size */
> > > > + .long 0x00020002 /* MLE version 2.2 */
> > > > + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> > >
> > > and these should perhaps be relative to mle_header?
> > >
> > > > + .long 0x00000000 /* First valid page of MLE */
> > > > + .long 0x00000000 /* Offset within binary of first byte of MLE */
> > > > + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> > >
> > > and here
> > >
> >
> > Ugh never mind - these are specified externally.
>
> OK, so instead of patch #1, please use the linker script to generate
> these constants.
>
> I.e., add this to arch/x86/boot/compressed/vmlinux.lds.S
>
> #ifdef CONFIG_SECURE_LAUNCH
> PROVIDE(mle_header_offset = mle_header - startup_32);
> PROVIDE(sl_stub_entry_offset = sl_stub_entry - startup_32);
> PROVIDE(_edata_offset = _edata - startup_32);
> #endif
>
> and use the symbols on the left hand side in the code.
Bah this works with Clang but not with GCC/ld.bfd
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 14:04 ` Ard Biesheuvel
2024-05-31 16:13 ` Ard Biesheuvel
@ 2024-06-04 17:31 ` ross.philipson
1 sibling, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 17:31 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel, ross.philipson
On 5/31/24 7:04 AM, Ard Biesheuvel wrote:
> On Fri, 31 May 2024 at 15:33, Ard Biesheuvel <ardb@kernel.org> wrote:
>>
>> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
>>>
>>> Hello Ross,
>>>
>>> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>>>
>>>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>>>> later AMD SKINIT) to vector to during the late launch. The symbol
>>>> sl_stub_entry is that entry point and its offset into the kernel is
>>>> conveyed to the launching code using the MLE (Measured Launch
>>>> Environment) header in the structure named mle_header. The offset of the
>>>> MLE header is set in the kernel_info. The routine sl_stub contains the
>>>> very early late launch setup code responsible for setting up the basic
>>>> environment to allow the normal kernel startup_32 code to proceed. It is
>>>> also responsible for properly waking and handling the APs on Intel
>>>> platforms. The routine sl_main which runs after entering 64b mode is
>>>> responsible for measuring configuration and module information before
>>>> it is used like the boot params, the kernel command line, the TXT heap,
>>>> an external initramfs, etc.
>>>>
>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>> ---
>>>> Documentation/arch/x86/boot.rst | 21 +
>>>> arch/x86/boot/compressed/Makefile | 3 +-
>>>> arch/x86/boot/compressed/head_64.S | 30 +
>>>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>>>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>>>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>>>> arch/x86/include/asm/msr-index.h | 5 +
>>>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>>>> arch/x86/kernel/asm-offsets.c | 20 +
>>>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>>>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>>>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>>>
>>>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>>>> index 4fd492cb4970..295cdf9bcbdb 100644
>>>> --- a/Documentation/arch/x86/boot.rst
>>>> +++ b/Documentation/arch/x86/boot.rst
>>>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>>>> - If 1, KASLR enabled.
>>>> - If 0, KASLR disabled.
>>>>
>>>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>>>> +
>>>> + - Used internally by the setup kernel to communicate
>>>> + Secure Launch status to kernel proper.
>>>> +
>>>> + - If 1, Secure Launch enabled.
>>>> + - If 0, Secure Launch disabled.
>>>> +
>>>> Bit 5 (write): QUIET_FLAG
>>>>
>>>> - If 0, print early messages.
>>>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>>>
>>>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>>>
>>>> +============ =================
>>>> +Field name: mle_header_offset
>>>> +Offset/size: 0x0010/4
>>>> +============ =================
>>>> +
>>>> + This field contains the offset to the Secure Launch Measured Launch Environment
>>>> + (MLE) header. This offset is used to locate information needed during a secure
>>>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>>>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>>>> + following a success measured launch. The specific state of the processors is
>>>> + outlined in the TXT Software Development Guide, the latest can be found here:
>>>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!ItP96GzpIqxa7wGXth63mmzkWPbBgoixpG3-Gj1tlstBVkReH_hagE-Sa_E6DwcvYtu5xLOwbVWeeXGa$
>>>> +
>>>>
>>>
>>> Could we just repaint this field as the offset relative to the start
>>> of kernel_info rather than relative to the start of the image? That
>>> way, there is no need for patch #1, and given that the consumer of
>>> this field accesses it via kernel_info, I wouldn't expect any issues
>>> in applying this offset to obtain the actual address.
>>>
>>>
>>>> The Image Checksum
>>>> ==================
>>>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>>>> index 9189a0e28686..9076a248d4b4 100644
>>>> --- a/arch/x86/boot/compressed/Makefile
>>>> +++ b/arch/x86/boot/compressed/Makefile
>>>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>>>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>>>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>>>
>>>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>>>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>>>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>>>
>>>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>>>> $(call if_changed,ld)
>>>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>>>> index 1dcb794c5479..803c9e2e6d85 100644
>>>> --- a/arch/x86/boot/compressed/head_64.S
>>>> +++ b/arch/x86/boot/compressed/head_64.S
>>>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>>>> pushq $0
>>>> popfq
>>>>
>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>> + /* Ensure the relocation region is coverd by a PMR */
>>>
>>> covered
>>>
>>>> + movq %rbx, %rdi
>>>> + movl $(_bss - startup_32), %esi
>>>> + callq sl_check_region
>>>> +#endif
>>>> +
>>>> /*
>>>> * Copy the compressed kernel to the end of our buffer
>>>> * where decompression in place becomes safe.
>>>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>>>> shrq $3, %rcx
>>>> rep stosq
>>>>
>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>> + /*
>>>> + * Have to do the final early sl stub work in 64b area.
>>>> + *
>>>> + * *********** NOTE ***********
>>>> + *
>>>> + * Several boot params get used before we get a chance to measure
>>>> + * them in this call. This is a known issue and we currently don't
>>>> + * have a solution. The scratch field doesn't matter. There is no
>>>> + * obvious way to do anything about the use of kernel_alignment or
>>>> + * init_size though these seem low risk with all the PMR and overlap
>>>> + * checks in place.
>>>> + */
>>>> + movq %r15, %rdi
>>>> + callq sl_main
>>>> +
>>>> + /* Ensure the decompression location is covered by a PMR */
>>>> + movq %rbp, %rdi
>>>> + movq output_len(%rip), %rsi
>>>> + callq sl_check_region
>>>> +#endif
>>>> +
>>>> + pushq %rsi
>>>
>>> This looks like a rebase error.
>>>
>>>> call load_stage2_idt
>>>>
>>>> /* Pass boot_params to initialize_identity_maps() */
>>>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>>>> index c18f07181dd5..e199b87764e9 100644
>>>> --- a/arch/x86/boot/compressed/kernel_info.S
>>>> +++ b/arch/x86/boot/compressed/kernel_info.S
>>>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>>>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>>>> .long SETUP_TYPE_MAX
>>>>
>>>> + /* Offset to the MLE header structure */
>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>> + .long rva(mle_header)
>>>
>>> ... so this could just be mle_header - kernel_info, and the consumer
>>> can do the math instead.
>>>
>>>> +#else
>>>> + .long 0
>>>> +#endif
>>>> +
>>>> kernel_info_var_len_data:
>>>> /* Empty for time being... */
>>>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>>>> +
>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>> + /*
>>>> + * The MLE Header per the TXT Specification, section 2.1
>>>> + * MLE capabilities, see table 4. Capabilities set:
>>>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>>>> + * bit 1: Support for RLP wakeup using MONITOR address
>>>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>>>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>>>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>>>> + */
>>>> +SYM_DATA_START(mle_header)
>>>> + .long 0x9082ac5a /* UUID0 */
>>>> + .long 0x74a7476f /* UUID1 */
>>>> + .long 0xa2555c0f /* UUID2 */
>>>> + .long 0x42b651cb /* UUID3 */
>>>> + .long 0x00000034 /* MLE header size */
>>>> + .long 0x00020002 /* MLE version 2.2 */
>>>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>>>
>>> and these should perhaps be relative to mle_header?
>>>
>>>> + .long 0x00000000 /* First valid page of MLE */
>>>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>>>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>>>
>>> and here
>>>
>>
>> Ugh never mind - these are specified externally.
>
> OK, so instead of patch #1, please use the linker script to generate
> these constants.
>
> I.e., add this to arch/x86/boot/compressed/vmlinux.lds.S
>
> #ifdef CONFIG_SECURE_LAUNCH
> PROVIDE(mle_header_offset = mle_header - startup_32);
> PROVIDE(sl_stub_entry_offset = sl_stub_entry - startup_32);
> PROVIDE(_edata_offset = _edata - startup_32);
> #endif
>
> and use the symbols on the left hand side in the code.
Hmmm that is an interesting approach we had not considered but we surely
will now. We are not wedded to keeping patch #1 by any means. Thank you
for your suggestions.
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 13:33 ` Ard Biesheuvel
2024-05-31 14:04 ` Ard Biesheuvel
@ 2024-06-04 17:24 ` ross.philipson
2024-06-04 17:27 ` Ard Biesheuvel
1 sibling, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 17:24 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel, ross.philipson
On 5/31/24 6:33 AM, Ard Biesheuvel wrote:
> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
>>
>> Hello Ross,
>>
>> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>>
>>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>>> later AMD SKINIT) to vector to during the late launch. The symbol
>>> sl_stub_entry is that entry point and its offset into the kernel is
>>> conveyed to the launching code using the MLE (Measured Launch
>>> Environment) header in the structure named mle_header. The offset of the
>>> MLE header is set in the kernel_info. The routine sl_stub contains the
>>> very early late launch setup code responsible for setting up the basic
>>> environment to allow the normal kernel startup_32 code to proceed. It is
>>> also responsible for properly waking and handling the APs on Intel
>>> platforms. The routine sl_main which runs after entering 64b mode is
>>> responsible for measuring configuration and module information before
>>> it is used like the boot params, the kernel command line, the TXT heap,
>>> an external initramfs, etc.
>>>
>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>> ---
>>> Documentation/arch/x86/boot.rst | 21 +
>>> arch/x86/boot/compressed/Makefile | 3 +-
>>> arch/x86/boot/compressed/head_64.S | 30 +
>>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>>> arch/x86/include/asm/msr-index.h | 5 +
>>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>>> arch/x86/kernel/asm-offsets.c | 20 +
>>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>>
>>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>>> index 4fd492cb4970..295cdf9bcbdb 100644
>>> --- a/Documentation/arch/x86/boot.rst
>>> +++ b/Documentation/arch/x86/boot.rst
>>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>>> - If 1, KASLR enabled.
>>> - If 0, KASLR disabled.
>>>
>>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>>> +
>>> + - Used internally by the setup kernel to communicate
>>> + Secure Launch status to kernel proper.
>>> +
>>> + - If 1, Secure Launch enabled.
>>> + - If 0, Secure Launch disabled.
>>> +
>>> Bit 5 (write): QUIET_FLAG
>>>
>>> - If 0, print early messages.
>>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>>
>>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>>
>>> +============ =================
>>> +Field name: mle_header_offset
>>> +Offset/size: 0x0010/4
>>> +============ =================
>>> +
>>> + This field contains the offset to the Secure Launch Measured Launch Environment
>>> + (MLE) header. This offset is used to locate information needed during a secure
>>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>>> + following a success measured launch. The specific state of the processors is
>>> + outlined in the TXT Software Development Guide, the latest can be found here:
>>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!Mng0gnPhOYZ8D02t1rYwQfY6U3uWaypJyd1T2rsWz3QNHr9GhIZ9ANB_-cgPExxX0e0KmCpda-3VX8Fj$
>>> +
>>>
>>
>> Could we just repaint this field as the offset relative to the start
>> of kernel_info rather than relative to the start of the image? That
>> way, there is no need for patch #1, and given that the consumer of
>> this field accesses it via kernel_info, I wouldn't expect any issues
>> in applying this offset to obtain the actual address.
>>
>>
>>> The Image Checksum
>>> ==================
>>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>>> index 9189a0e28686..9076a248d4b4 100644
>>> --- a/arch/x86/boot/compressed/Makefile
>>> +++ b/arch/x86/boot/compressed/Makefile
>>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>>
>>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>>
>>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>>> $(call if_changed,ld)
>>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>>> index 1dcb794c5479..803c9e2e6d85 100644
>>> --- a/arch/x86/boot/compressed/head_64.S
>>> +++ b/arch/x86/boot/compressed/head_64.S
>>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>>> pushq $0
>>> popfq
>>>
>>> +#ifdef CONFIG_SECURE_LAUNCH
>>> + /* Ensure the relocation region is coverd by a PMR */
>>
>> covered
>>
>>> + movq %rbx, %rdi
>>> + movl $(_bss - startup_32), %esi
>>> + callq sl_check_region
>>> +#endif
>>> +
>>> /*
>>> * Copy the compressed kernel to the end of our buffer
>>> * where decompression in place becomes safe.
>>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>>> shrq $3, %rcx
>>> rep stosq
>>>
>>> +#ifdef CONFIG_SECURE_LAUNCH
>>> + /*
>>> + * Have to do the final early sl stub work in 64b area.
>>> + *
>>> + * *********** NOTE ***********
>>> + *
>>> + * Several boot params get used before we get a chance to measure
>>> + * them in this call. This is a known issue and we currently don't
>>> + * have a solution. The scratch field doesn't matter. There is no
>>> + * obvious way to do anything about the use of kernel_alignment or
>>> + * init_size though these seem low risk with all the PMR and overlap
>>> + * checks in place.
>>> + */
>>> + movq %r15, %rdi
>>> + callq sl_main
>>> +
>>> + /* Ensure the decompression location is covered by a PMR */
>>> + movq %rbp, %rdi
>>> + movq output_len(%rip), %rsi
>>> + callq sl_check_region
>>> +#endif
>>> +
>>> + pushq %rsi
>>
>> This looks like a rebase error.
>>
>>> call load_stage2_idt
>>>
>>> /* Pass boot_params to initialize_identity_maps() */
>>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>>> index c18f07181dd5..e199b87764e9 100644
>>> --- a/arch/x86/boot/compressed/kernel_info.S
>>> +++ b/arch/x86/boot/compressed/kernel_info.S
>>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>>> .long SETUP_TYPE_MAX
>>>
>>> + /* Offset to the MLE header structure */
>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>> + .long rva(mle_header)
>>
>> ... so this could just be mle_header - kernel_info, and the consumer
>> can do the math instead.
>>
>>> +#else
>>> + .long 0
>>> +#endif
>>> +
>>> kernel_info_var_len_data:
>>> /* Empty for time being... */
>>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>>> +
>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>> + /*
>>> + * The MLE Header per the TXT Specification, section 2.1
>>> + * MLE capabilities, see table 4. Capabilities set:
>>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>>> + * bit 1: Support for RLP wakeup using MONITOR address
>>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>>> + */
>>> +SYM_DATA_START(mle_header)
>>> + .long 0x9082ac5a /* UUID0 */
>>> + .long 0x74a7476f /* UUID1 */
>>> + .long 0xa2555c0f /* UUID2 */
>>> + .long 0x42b651cb /* UUID3 */
>>> + .long 0x00000034 /* MLE header size */
>>> + .long 0x00020002 /* MLE version 2.2 */
>>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>>
>> and these should perhaps be relative to mle_header?
>>
>>> + .long 0x00000000 /* First valid page of MLE */
>>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>>
>> and here
>>
>
> Ugh never mind - these are specified externally.
Can you clarify your follow on comment here?
Thank you,
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 17:24 ` ross.philipson
@ 2024-06-04 17:27 ` Ard Biesheuvel
2024-06-04 17:33 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Ard Biesheuvel @ 2024-06-04 17:27 UTC (permalink / raw)
To: ross.philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Tue, 4 Jun 2024 at 19:24, <ross.philipson@oracle.com> wrote:
>
> On 5/31/24 6:33 AM, Ard Biesheuvel wrote:
> > On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
> >>
> >> Hello Ross,
> >>
> >> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
> >>>
> >>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> >>> later AMD SKINIT) to vector to during the late launch. The symbol
> >>> sl_stub_entry is that entry point and its offset into the kernel is
> >>> conveyed to the launching code using the MLE (Measured Launch
> >>> Environment) header in the structure named mle_header. The offset of the
> >>> MLE header is set in the kernel_info. The routine sl_stub contains the
> >>> very early late launch setup code responsible for setting up the basic
> >>> environment to allow the normal kernel startup_32 code to proceed. It is
> >>> also responsible for properly waking and handling the APs on Intel
> >>> platforms. The routine sl_main which runs after entering 64b mode is
> >>> responsible for measuring configuration and module information before
> >>> it is used like the boot params, the kernel command line, the TXT heap,
> >>> an external initramfs, etc.
> >>>
> >>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >>> ---
> >>> Documentation/arch/x86/boot.rst | 21 +
> >>> arch/x86/boot/compressed/Makefile | 3 +-
> >>> arch/x86/boot/compressed/head_64.S | 30 +
> >>> arch/x86/boot/compressed/kernel_info.S | 34 ++
> >>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> >>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> >>> arch/x86/include/asm/msr-index.h | 5 +
> >>> arch/x86/include/uapi/asm/bootparam.h | 1 +
> >>> arch/x86/kernel/asm-offsets.c | 20 +
> >>> 9 files changed, 1415 insertions(+), 1 deletion(-)
> >>> create mode 100644 arch/x86/boot/compressed/sl_main.c
> >>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
> >>>
> >>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> >>> index 4fd492cb4970..295cdf9bcbdb 100644
> >>> --- a/Documentation/arch/x86/boot.rst
> >>> +++ b/Documentation/arch/x86/boot.rst
> >>> @@ -482,6 +482,14 @@ Protocol: 2.00+
> >>> - If 1, KASLR enabled.
> >>> - If 0, KASLR disabled.
> >>>
> >>> + Bit 2 (kernel internal): SLAUNCH_FLAG
> >>> +
> >>> + - Used internally by the setup kernel to communicate
> >>> + Secure Launch status to kernel proper.
> >>> +
> >>> + - If 1, Secure Launch enabled.
> >>> + - If 0, Secure Launch disabled.
> >>> +
> >>> Bit 5 (write): QUIET_FLAG
> >>>
> >>> - If 0, print early messages.
> >>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
> >>>
> >>> This field contains maximal allowed type for setup_data and setup_indirect structs.
> >>>
> >>> +============ =================
> >>> +Field name: mle_header_offset
> >>> +Offset/size: 0x0010/4
> >>> +============ =================
> >>> +
> >>> + This field contains the offset to the Secure Launch Measured Launch Environment
> >>> + (MLE) header. This offset is used to locate information needed during a secure
> >>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
> >>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> >>> + following a success measured launch. The specific state of the processors is
> >>> + outlined in the TXT Software Development Guide, the latest can be found here:
> >>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!Mng0gnPhOYZ8D02t1rYwQfY6U3uWaypJyd1T2rsWz3QNHr9GhIZ9ANB_-cgPExxX0e0KmCpda-3VX8Fj$
> >>> +
> >>>
> >>
> >> Could we just repaint this field as the offset relative to the start
> >> of kernel_info rather than relative to the start of the image? That
> >> way, there is no need for patch #1, and given that the consumer of
> >> this field accesses it via kernel_info, I wouldn't expect any issues
> >> in applying this offset to obtain the actual address.
> >>
> >>
> >>> The Image Checksum
> >>> ==================
> >>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> >>> index 9189a0e28686..9076a248d4b4 100644
> >>> --- a/arch/x86/boot/compressed/Makefile
> >>> +++ b/arch/x86/boot/compressed/Makefile
> >>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> >>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> >>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> >>>
> >>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> >>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> >>> + $(obj)/sl_main.o $(obj)/sl_stub.o
> >>>
> >>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> >>> $(call if_changed,ld)
> >>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> >>> index 1dcb794c5479..803c9e2e6d85 100644
> >>> --- a/arch/x86/boot/compressed/head_64.S
> >>> +++ b/arch/x86/boot/compressed/head_64.S
> >>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> >>> pushq $0
> >>> popfq
> >>>
> >>> +#ifdef CONFIG_SECURE_LAUNCH
> >>> + /* Ensure the relocation region is coverd by a PMR */
> >>
> >> covered
> >>
> >>> + movq %rbx, %rdi
> >>> + movl $(_bss - startup_32), %esi
> >>> + callq sl_check_region
> >>> +#endif
> >>> +
> >>> /*
> >>> * Copy the compressed kernel to the end of our buffer
> >>> * where decompression in place becomes safe.
> >>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> >>> shrq $3, %rcx
> >>> rep stosq
> >>>
> >>> +#ifdef CONFIG_SECURE_LAUNCH
> >>> + /*
> >>> + * Have to do the final early sl stub work in 64b area.
> >>> + *
> >>> + * *********** NOTE ***********
> >>> + *
> >>> + * Several boot params get used before we get a chance to measure
> >>> + * them in this call. This is a known issue and we currently don't
> >>> + * have a solution. The scratch field doesn't matter. There is no
> >>> + * obvious way to do anything about the use of kernel_alignment or
> >>> + * init_size though these seem low risk with all the PMR and overlap
> >>> + * checks in place.
> >>> + */
> >>> + movq %r15, %rdi
> >>> + callq sl_main
> >>> +
> >>> + /* Ensure the decompression location is covered by a PMR */
> >>> + movq %rbp, %rdi
> >>> + movq output_len(%rip), %rsi
> >>> + callq sl_check_region
> >>> +#endif
> >>> +
> >>> + pushq %rsi
> >>
> >> This looks like a rebase error.
> >>
> >>> call load_stage2_idt
> >>>
> >>> /* Pass boot_params to initialize_identity_maps() */
> >>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> >>> index c18f07181dd5..e199b87764e9 100644
> >>> --- a/arch/x86/boot/compressed/kernel_info.S
> >>> +++ b/arch/x86/boot/compressed/kernel_info.S
> >>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> >>> /* Maximal allowed type for setup_data and setup_indirect structs. */
> >>> .long SETUP_TYPE_MAX
> >>>
> >>> + /* Offset to the MLE header structure */
> >>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> >>> + .long rva(mle_header)
> >>
> >> ... so this could just be mle_header - kernel_info, and the consumer
> >> can do the math instead.
> >>
> >>> +#else
> >>> + .long 0
> >>> +#endif
> >>> +
> >>> kernel_info_var_len_data:
> >>> /* Empty for time being... */
> >>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> >>> +
> >>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> >>> + /*
> >>> + * The MLE Header per the TXT Specification, section 2.1
> >>> + * MLE capabilities, see table 4. Capabilities set:
> >>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> >>> + * bit 1: Support for RLP wakeup using MONITOR address
> >>> + * bit 2: The ECX register will contain the pointer to the MLE page table
> >>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> >>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> >>> + */
> >>> +SYM_DATA_START(mle_header)
> >>> + .long 0x9082ac5a /* UUID0 */
> >>> + .long 0x74a7476f /* UUID1 */
> >>> + .long 0xa2555c0f /* UUID2 */
> >>> + .long 0x42b651cb /* UUID3 */
> >>> + .long 0x00000034 /* MLE header size */
> >>> + .long 0x00020002 /* MLE version 2.2 */
> >>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> >>
> >> and these should perhaps be relative to mle_header?
> >>
> >>> + .long 0x00000000 /* First valid page of MLE */
> >>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
> >>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> >>
> >> and here
> >>
> >
> > Ugh never mind - these are specified externally.
>
> Can you clarify your follow on comment here?
>
I noticed that -as you pointed out in your previous reply- these
fields cannot be repainted at will, as they are defined by an external
specification.
I'll play a bit more with this code tomorrow - I would *really* like
to avoid the need for patch #1, as it adds another constraint on how
we construct the boot image, and this is already riddled with legacy
and other complications.
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 17:27 ` Ard Biesheuvel
@ 2024-06-04 17:33 ` ross.philipson
2024-06-04 20:54 ` Ard Biesheuvel
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 17:33 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel, ross.philipson
On 6/4/24 10:27 AM, Ard Biesheuvel wrote:
> On Tue, 4 Jun 2024 at 19:24, <ross.philipson@oracle.com> wrote:
>>
>> On 5/31/24 6:33 AM, Ard Biesheuvel wrote:
>>> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
>>>>
>>>> Hello Ross,
>>>>
>>>> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>>>>
>>>>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>>>>> later AMD SKINIT) to vector to during the late launch. The symbol
>>>>> sl_stub_entry is that entry point and its offset into the kernel is
>>>>> conveyed to the launching code using the MLE (Measured Launch
>>>>> Environment) header in the structure named mle_header. The offset of the
>>>>> MLE header is set in the kernel_info. The routine sl_stub contains the
>>>>> very early late launch setup code responsible for setting up the basic
>>>>> environment to allow the normal kernel startup_32 code to proceed. It is
>>>>> also responsible for properly waking and handling the APs on Intel
>>>>> platforms. The routine sl_main which runs after entering 64b mode is
>>>>> responsible for measuring configuration and module information before
>>>>> it is used like the boot params, the kernel command line, the TXT heap,
>>>>> an external initramfs, etc.
>>>>>
>>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>>> ---
>>>>> Documentation/arch/x86/boot.rst | 21 +
>>>>> arch/x86/boot/compressed/Makefile | 3 +-
>>>>> arch/x86/boot/compressed/head_64.S | 30 +
>>>>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>>>>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>>>>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>>>>> arch/x86/include/asm/msr-index.h | 5 +
>>>>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>>>>> arch/x86/kernel/asm-offsets.c | 20 +
>>>>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>>>>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>>>>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>>>>
>>>>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>>>>> index 4fd492cb4970..295cdf9bcbdb 100644
>>>>> --- a/Documentation/arch/x86/boot.rst
>>>>> +++ b/Documentation/arch/x86/boot.rst
>>>>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>>>>> - If 1, KASLR enabled.
>>>>> - If 0, KASLR disabled.
>>>>>
>>>>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>>>>> +
>>>>> + - Used internally by the setup kernel to communicate
>>>>> + Secure Launch status to kernel proper.
>>>>> +
>>>>> + - If 1, Secure Launch enabled.
>>>>> + - If 0, Secure Launch disabled.
>>>>> +
>>>>> Bit 5 (write): QUIET_FLAG
>>>>>
>>>>> - If 0, print early messages.
>>>>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>>>>
>>>>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>>>>
>>>>> +============ =================
>>>>> +Field name: mle_header_offset
>>>>> +Offset/size: 0x0010/4
>>>>> +============ =================
>>>>> +
>>>>> + This field contains the offset to the Secure Launch Measured Launch Environment
>>>>> + (MLE) header. This offset is used to locate information needed during a secure
>>>>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>>>>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>>>>> + following a success measured launch. The specific state of the processors is
>>>>> + outlined in the TXT Software Development Guide, the latest can be found here:
>>>>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!Mng0gnPhOYZ8D02t1rYwQfY6U3uWaypJyd1T2rsWz3QNHr9GhIZ9ANB_-cgPExxX0e0KmCpda-3VX8Fj$
>>>>> +
>>>>>
>>>>
>>>> Could we just repaint this field as the offset relative to the start
>>>> of kernel_info rather than relative to the start of the image? That
>>>> way, there is no need for patch #1, and given that the consumer of
>>>> this field accesses it via kernel_info, I wouldn't expect any issues
>>>> in applying this offset to obtain the actual address.
>>>>
>>>>
>>>>> The Image Checksum
>>>>> ==================
>>>>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>>>>> index 9189a0e28686..9076a248d4b4 100644
>>>>> --- a/arch/x86/boot/compressed/Makefile
>>>>> +++ b/arch/x86/boot/compressed/Makefile
>>>>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>>>>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>>>>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>>>>
>>>>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>>>>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>>>>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>>>>
>>>>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>>>>> $(call if_changed,ld)
>>>>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>>>>> index 1dcb794c5479..803c9e2e6d85 100644
>>>>> --- a/arch/x86/boot/compressed/head_64.S
>>>>> +++ b/arch/x86/boot/compressed/head_64.S
>>>>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>>>>> pushq $0
>>>>> popfq
>>>>>
>>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>>> + /* Ensure the relocation region is coverd by a PMR */
>>>>
>>>> covered
>>>>
>>>>> + movq %rbx, %rdi
>>>>> + movl $(_bss - startup_32), %esi
>>>>> + callq sl_check_region
>>>>> +#endif
>>>>> +
>>>>> /*
>>>>> * Copy the compressed kernel to the end of our buffer
>>>>> * where decompression in place becomes safe.
>>>>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>>>>> shrq $3, %rcx
>>>>> rep stosq
>>>>>
>>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>>> + /*
>>>>> + * Have to do the final early sl stub work in 64b area.
>>>>> + *
>>>>> + * *********** NOTE ***********
>>>>> + *
>>>>> + * Several boot params get used before we get a chance to measure
>>>>> + * them in this call. This is a known issue and we currently don't
>>>>> + * have a solution. The scratch field doesn't matter. There is no
>>>>> + * obvious way to do anything about the use of kernel_alignment or
>>>>> + * init_size though these seem low risk with all the PMR and overlap
>>>>> + * checks in place.
>>>>> + */
>>>>> + movq %r15, %rdi
>>>>> + callq sl_main
>>>>> +
>>>>> + /* Ensure the decompression location is covered by a PMR */
>>>>> + movq %rbp, %rdi
>>>>> + movq output_len(%rip), %rsi
>>>>> + callq sl_check_region
>>>>> +#endif
>>>>> +
>>>>> + pushq %rsi
>>>>
>>>> This looks like a rebase error.
>>>>
>>>>> call load_stage2_idt
>>>>>
>>>>> /* Pass boot_params to initialize_identity_maps() */
>>>>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>>>>> index c18f07181dd5..e199b87764e9 100644
>>>>> --- a/arch/x86/boot/compressed/kernel_info.S
>>>>> +++ b/arch/x86/boot/compressed/kernel_info.S
>>>>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>>>>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>>>>> .long SETUP_TYPE_MAX
>>>>>
>>>>> + /* Offset to the MLE header structure */
>>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>>> + .long rva(mle_header)
>>>>
>>>> ... so this could just be mle_header - kernel_info, and the consumer
>>>> can do the math instead.
>>>>
>>>>> +#else
>>>>> + .long 0
>>>>> +#endif
>>>>> +
>>>>> kernel_info_var_len_data:
>>>>> /* Empty for time being... */
>>>>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>>>>> +
>>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>>> + /*
>>>>> + * The MLE Header per the TXT Specification, section 2.1
>>>>> + * MLE capabilities, see table 4. Capabilities set:
>>>>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>>>>> + * bit 1: Support for RLP wakeup using MONITOR address
>>>>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>>>>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>>>>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>>>>> + */
>>>>> +SYM_DATA_START(mle_header)
>>>>> + .long 0x9082ac5a /* UUID0 */
>>>>> + .long 0x74a7476f /* UUID1 */
>>>>> + .long 0xa2555c0f /* UUID2 */
>>>>> + .long 0x42b651cb /* UUID3 */
>>>>> + .long 0x00000034 /* MLE header size */
>>>>> + .long 0x00020002 /* MLE version 2.2 */
>>>>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>>>>
>>>> and these should perhaps be relative to mle_header?
>>>>
>>>>> + .long 0x00000000 /* First valid page of MLE */
>>>>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>>>>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>>>>
>>>> and here
>>>>
>>>
>>> Ugh never mind - these are specified externally.
>>
>> Can you clarify your follow on comment here?
>>
>
> I noticed that -as you pointed out in your previous reply- these
> fields cannot be repainted at will, as they are defined by an external
> specification.
>
> I'll play a bit more with this code tomorrow - I would *really* like
> to avoid the need for patch #1, as it adds another constraint on how
> we construct the boot image, and this is already riddled with legacy
> and other complications.
Yea I should have read forward through all your replies before
responding to the first one but I think it clarified things as you point
out here. We appreciate you help and suggestions.
Ross
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 17:33 ` ross.philipson
@ 2024-06-04 20:54 ` Ard Biesheuvel
2024-06-04 21:12 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Ard Biesheuvel @ 2024-06-04 20:54 UTC (permalink / raw)
To: ross.philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Tue, 4 Jun 2024 at 19:34, <ross.philipson@oracle.com> wrote:
>
> On 6/4/24 10:27 AM, Ard Biesheuvel wrote:
> > On Tue, 4 Jun 2024 at 19:24, <ross.philipson@oracle.com> wrote:
> >>
> >> On 5/31/24 6:33 AM, Ard Biesheuvel wrote:
> >>> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
> >>>>
> >>>> Hello Ross,
> >>>>
> >>>> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
> >>>>>
> >>>>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> >>>>> later AMD SKINIT) to vector to during the late launch. The symbol
> >>>>> sl_stub_entry is that entry point and its offset into the kernel is
> >>>>> conveyed to the launching code using the MLE (Measured Launch
> >>>>> Environment) header in the structure named mle_header. The offset of the
> >>>>> MLE header is set in the kernel_info. The routine sl_stub contains the
> >>>>> very early late launch setup code responsible for setting up the basic
> >>>>> environment to allow the normal kernel startup_32 code to proceed. It is
> >>>>> also responsible for properly waking and handling the APs on Intel
> >>>>> platforms. The routine sl_main which runs after entering 64b mode is
> >>>>> responsible for measuring configuration and module information before
> >>>>> it is used like the boot params, the kernel command line, the TXT heap,
> >>>>> an external initramfs, etc.
> >>>>>
> >>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >>>>> ---
> >>>>> Documentation/arch/x86/boot.rst | 21 +
> >>>>> arch/x86/boot/compressed/Makefile | 3 +-
> >>>>> arch/x86/boot/compressed/head_64.S | 30 +
> >>>>> arch/x86/boot/compressed/kernel_info.S | 34 ++
> >>>>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> >>>>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> >>>>> arch/x86/include/asm/msr-index.h | 5 +
> >>>>> arch/x86/include/uapi/asm/bootparam.h | 1 +
> >>>>> arch/x86/kernel/asm-offsets.c | 20 +
> >>>>> 9 files changed, 1415 insertions(+), 1 deletion(-)
> >>>>> create mode 100644 arch/x86/boot/compressed/sl_main.c
> >>>>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
> >>>>>
> >>>>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> >>>>> index 4fd492cb4970..295cdf9bcbdb 100644
> >>>>> --- a/Documentation/arch/x86/boot.rst
> >>>>> +++ b/Documentation/arch/x86/boot.rst
> >>>>> @@ -482,6 +482,14 @@ Protocol: 2.00+
> >>>>> - If 1, KASLR enabled.
> >>>>> - If 0, KASLR disabled.
> >>>>>
> >>>>> + Bit 2 (kernel internal): SLAUNCH_FLAG
> >>>>> +
> >>>>> + - Used internally by the setup kernel to communicate
> >>>>> + Secure Launch status to kernel proper.
> >>>>> +
> >>>>> + - If 1, Secure Launch enabled.
> >>>>> + - If 0, Secure Launch disabled.
> >>>>> +
> >>>>> Bit 5 (write): QUIET_FLAG
> >>>>>
> >>>>> - If 0, print early messages.
> >>>>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
> >>>>>
> >>>>> This field contains maximal allowed type for setup_data and setup_indirect structs.
> >>>>>
> >>>>> +============ =================
> >>>>> +Field name: mle_header_offset
> >>>>> +Offset/size: 0x0010/4
> >>>>> +============ =================
> >>>>> +
> >>>>> + This field contains the offset to the Secure Launch Measured Launch Environment
> >>>>> + (MLE) header. This offset is used to locate information needed during a secure
> >>>>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
> >>>>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> >>>>> + following a success measured launch. The specific state of the processors is
> >>>>> + outlined in the TXT Software Development Guide, the latest can be found here:
> >>>>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!Mng0gnPhOYZ8D02t1rYwQfY6U3uWaypJyd1T2rsWz3QNHr9GhIZ9ANB_-cgPExxX0e0KmCpda-3VX8Fj$
> >>>>> +
> >>>>>
> >>>>
> >>>> Could we just repaint this field as the offset relative to the start
> >>>> of kernel_info rather than relative to the start of the image? That
> >>>> way, there is no need for patch #1, and given that the consumer of
> >>>> this field accesses it via kernel_info, I wouldn't expect any issues
> >>>> in applying this offset to obtain the actual address.
> >>>>
> >>>>
> >>>>> The Image Checksum
> >>>>> ==================
> >>>>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> >>>>> index 9189a0e28686..9076a248d4b4 100644
> >>>>> --- a/arch/x86/boot/compressed/Makefile
> >>>>> +++ b/arch/x86/boot/compressed/Makefile
> >>>>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> >>>>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> >>>>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
> >>>>>
> >>>>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> >>>>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> >>>>> + $(obj)/sl_main.o $(obj)/sl_stub.o
> >>>>>
> >>>>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> >>>>> $(call if_changed,ld)
> >>>>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> >>>>> index 1dcb794c5479..803c9e2e6d85 100644
> >>>>> --- a/arch/x86/boot/compressed/head_64.S
> >>>>> +++ b/arch/x86/boot/compressed/head_64.S
> >>>>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> >>>>> pushq $0
> >>>>> popfq
> >>>>>
> >>>>> +#ifdef CONFIG_SECURE_LAUNCH
> >>>>> + /* Ensure the relocation region is coverd by a PMR */
> >>>>
> >>>> covered
> >>>>
> >>>>> + movq %rbx, %rdi
> >>>>> + movl $(_bss - startup_32), %esi
> >>>>> + callq sl_check_region
> >>>>> +#endif
> >>>>> +
> >>>>> /*
> >>>>> * Copy the compressed kernel to the end of our buffer
> >>>>> * where decompression in place becomes safe.
> >>>>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> >>>>> shrq $3, %rcx
> >>>>> rep stosq
> >>>>>
> >>>>> +#ifdef CONFIG_SECURE_LAUNCH
> >>>>> + /*
> >>>>> + * Have to do the final early sl stub work in 64b area.
> >>>>> + *
> >>>>> + * *********** NOTE ***********
> >>>>> + *
> >>>>> + * Several boot params get used before we get a chance to measure
> >>>>> + * them in this call. This is a known issue and we currently don't
> >>>>> + * have a solution. The scratch field doesn't matter. There is no
> >>>>> + * obvious way to do anything about the use of kernel_alignment or
> >>>>> + * init_size though these seem low risk with all the PMR and overlap
> >>>>> + * checks in place.
> >>>>> + */
> >>>>> + movq %r15, %rdi
> >>>>> + callq sl_main
> >>>>> +
> >>>>> + /* Ensure the decompression location is covered by a PMR */
> >>>>> + movq %rbp, %rdi
> >>>>> + movq output_len(%rip), %rsi
> >>>>> + callq sl_check_region
> >>>>> +#endif
> >>>>> +
> >>>>> + pushq %rsi
> >>>>
> >>>> This looks like a rebase error.
> >>>>
> >>>>> call load_stage2_idt
> >>>>>
> >>>>> /* Pass boot_params to initialize_identity_maps() */
> >>>>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> >>>>> index c18f07181dd5..e199b87764e9 100644
> >>>>> --- a/arch/x86/boot/compressed/kernel_info.S
> >>>>> +++ b/arch/x86/boot/compressed/kernel_info.S
> >>>>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> >>>>> /* Maximal allowed type for setup_data and setup_indirect structs. */
> >>>>> .long SETUP_TYPE_MAX
> >>>>>
> >>>>> + /* Offset to the MLE header structure */
> >>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> >>>>> + .long rva(mle_header)
> >>>>
> >>>> ... so this could just be mle_header - kernel_info, and the consumer
> >>>> can do the math instead.
> >>>>
> >>>>> +#else
> >>>>> + .long 0
> >>>>> +#endif
> >>>>> +
> >>>>> kernel_info_var_len_data:
> >>>>> /* Empty for time being... */
> >>>>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> >>>>> +
> >>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> >>>>> + /*
> >>>>> + * The MLE Header per the TXT Specification, section 2.1
> >>>>> + * MLE capabilities, see table 4. Capabilities set:
> >>>>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> >>>>> + * bit 1: Support for RLP wakeup using MONITOR address
> >>>>> + * bit 2: The ECX register will contain the pointer to the MLE page table
> >>>>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> >>>>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> >>>>> + */
> >>>>> +SYM_DATA_START(mle_header)
> >>>>> + .long 0x9082ac5a /* UUID0 */
> >>>>> + .long 0x74a7476f /* UUID1 */
> >>>>> + .long 0xa2555c0f /* UUID2 */
> >>>>> + .long 0x42b651cb /* UUID3 */
> >>>>> + .long 0x00000034 /* MLE header size */
> >>>>> + .long 0x00020002 /* MLE version 2.2 */
> >>>>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> >>>>
> >>>> and these should perhaps be relative to mle_header?
> >>>>
> >>>>> + .long 0x00000000 /* First valid page of MLE */
> >>>>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
> >>>>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> >>>>
> >>>> and here
> >>>>
> >>>
> >>> Ugh never mind - these are specified externally.
> >>
> >> Can you clarify your follow on comment here?
> >>
> >
> > I noticed that -as you pointed out in your previous reply- these
> > fields cannot be repainted at will, as they are defined by an external
> > specification.
> >
> > I'll play a bit more with this code tomorrow - I would *really* like
> > to avoid the need for patch #1, as it adds another constraint on how
> > we construct the boot image, and this is already riddled with legacy
> > and other complications.
>
> Yea I should have read forward through all your replies before
> responding to the first one but I think it clarified things as you point
> out here. We appreciate you help and suggestions.
>
OK, so I have a solution that does not require kernel_info at a fixed offset:
- put this at the end of arch/x86/boot/compressed/vmlinux.lds.S
#ifdef CONFIG_SECURE_LAUNCH
PROVIDE(kernel_info_offset = ABSOLUTE(kernel_info - startup_32));
PROVIDE(mle_header_offset = kernel_info_offset +
ABSOLUTE(mle_header - startup_32));
PROVIDE(sl_stub_entry_offset = kernel_info_offset +
ABSOLUTE(sl_stub_entry - startup_32));
PROVIDE(_edata_offset = kernel_info_offset + ABSOLUTE(_edata
- startup_32));
#endif
and use this for the header fields:
/* Offset to the MLE header structure */
#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
.long mle_header_offset - kernel_info
#else
.long 0
#endif
SYM_DATA_START(mle_header)
.long 0x9082ac5a /* UUID0 */
.long 0x74a7476f /* UUID1 */
.long 0xa2555c0f /* UUID2 */
.long 0x42b651cb /* UUID3 */
.long 0x00000034 /* MLE header size */
.long 0x00020002 /* MLE version 2.2 */
.long sl_stub_entry_offset - kernel_info /* Linear entry
point of MLE (virt. address) */
.long 0x00000000 /* First valid page of MLE */
.long 0x00000000 /* Offset within binary of first byte of MLE */
.long _edata_offset - kernel_info /* Offset within binary of
last byte + 1 of MLE */
.long 0x00000227 /* Bit vector of MLE-supported capabilities */
.long 0x00000000 /* Starting linear address of command line
(unused) */
.long 0x00000000 /* Ending linear address of command line (unused) */
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 20:54 ` Ard Biesheuvel
@ 2024-06-04 21:12 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:12 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel, ross.philipson
On 6/4/24 1:54 PM, Ard Biesheuvel wrote:
> On Tue, 4 Jun 2024 at 19:34, <ross.philipson@oracle.com> wrote:
>>
>> On 6/4/24 10:27 AM, Ard Biesheuvel wrote:
>>> On Tue, 4 Jun 2024 at 19:24, <ross.philipson@oracle.com> wrote:
>>>>
>>>> On 5/31/24 6:33 AM, Ard Biesheuvel wrote:
>>>>> On Fri, 31 May 2024 at 13:00, Ard Biesheuvel <ardb@kernel.org> wrote:
>>>>>>
>>>>>> Hello Ross,
>>>>>>
>>>>>> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>>>>>>
>>>>>>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>>>>>>> later AMD SKINIT) to vector to during the late launch. The symbol
>>>>>>> sl_stub_entry is that entry point and its offset into the kernel is
>>>>>>> conveyed to the launching code using the MLE (Measured Launch
>>>>>>> Environment) header in the structure named mle_header. The offset of the
>>>>>>> MLE header is set in the kernel_info. The routine sl_stub contains the
>>>>>>> very early late launch setup code responsible for setting up the basic
>>>>>>> environment to allow the normal kernel startup_32 code to proceed. It is
>>>>>>> also responsible for properly waking and handling the APs on Intel
>>>>>>> platforms. The routine sl_main which runs after entering 64b mode is
>>>>>>> responsible for measuring configuration and module information before
>>>>>>> it is used like the boot params, the kernel command line, the TXT heap,
>>>>>>> an external initramfs, etc.
>>>>>>>
>>>>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>>>>> ---
>>>>>>> Documentation/arch/x86/boot.rst | 21 +
>>>>>>> arch/x86/boot/compressed/Makefile | 3 +-
>>>>>>> arch/x86/boot/compressed/head_64.S | 30 +
>>>>>>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>>>>>>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>>>>>>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>>>>>>> arch/x86/include/asm/msr-index.h | 5 +
>>>>>>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>>>>>>> arch/x86/kernel/asm-offsets.c | 20 +
>>>>>>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>>>>>>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>>>>>>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>>>>>>
>>>>>>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>>>>>>> index 4fd492cb4970..295cdf9bcbdb 100644
>>>>>>> --- a/Documentation/arch/x86/boot.rst
>>>>>>> +++ b/Documentation/arch/x86/boot.rst
>>>>>>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>>>>>>> - If 1, KASLR enabled.
>>>>>>> - If 0, KASLR disabled.
>>>>>>>
>>>>>>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>>>>>>> +
>>>>>>> + - Used internally by the setup kernel to communicate
>>>>>>> + Secure Launch status to kernel proper.
>>>>>>> +
>>>>>>> + - If 1, Secure Launch enabled.
>>>>>>> + - If 0, Secure Launch disabled.
>>>>>>> +
>>>>>>> Bit 5 (write): QUIET_FLAG
>>>>>>>
>>>>>>> - If 0, print early messages.
>>>>>>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>>>>>>
>>>>>>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>>>>>>
>>>>>>> +============ =================
>>>>>>> +Field name: mle_header_offset
>>>>>>> +Offset/size: 0x0010/4
>>>>>>> +============ =================
>>>>>>> +
>>>>>>> + This field contains the offset to the Secure Launch Measured Launch Environment
>>>>>>> + (MLE) header. This offset is used to locate information needed during a secure
>>>>>>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>>>>>>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>>>>>>> + following a success measured launch. The specific state of the processors is
>>>>>>> + outlined in the TXT Software Development Guide, the latest can be found here:
>>>>>>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!Mng0gnPhOYZ8D02t1rYwQfY6U3uWaypJyd1T2rsWz3QNHr9GhIZ9ANB_-cgPExxX0e0KmCpda-3VX8Fj$
>>>>>>> +
>>>>>>>
>>>>>>
>>>>>> Could we just repaint this field as the offset relative to the start
>>>>>> of kernel_info rather than relative to the start of the image? That
>>>>>> way, there is no need for patch #1, and given that the consumer of
>>>>>> this field accesses it via kernel_info, I wouldn't expect any issues
>>>>>> in applying this offset to obtain the actual address.
>>>>>>
>>>>>>
>>>>>>> The Image Checksum
>>>>>>> ==================
>>>>>>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>>>>>>> index 9189a0e28686..9076a248d4b4 100644
>>>>>>> --- a/arch/x86/boot/compressed/Makefile
>>>>>>> +++ b/arch/x86/boot/compressed/Makefile
>>>>>>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>>>>>>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>>>>>>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>>>>>>
>>>>>>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>>>>>>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>>>>>>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>>>>>>
>>>>>>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>>>>>>> $(call if_changed,ld)
>>>>>>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>>>>>>> index 1dcb794c5479..803c9e2e6d85 100644
>>>>>>> --- a/arch/x86/boot/compressed/head_64.S
>>>>>>> +++ b/arch/x86/boot/compressed/head_64.S
>>>>>>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>>>>>>> pushq $0
>>>>>>> popfq
>>>>>>>
>>>>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>>>>> + /* Ensure the relocation region is coverd by a PMR */
>>>>>>
>>>>>> covered
>>>>>>
>>>>>>> + movq %rbx, %rdi
>>>>>>> + movl $(_bss - startup_32), %esi
>>>>>>> + callq sl_check_region
>>>>>>> +#endif
>>>>>>> +
>>>>>>> /*
>>>>>>> * Copy the compressed kernel to the end of our buffer
>>>>>>> * where decompression in place becomes safe.
>>>>>>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>>>>>>> shrq $3, %rcx
>>>>>>> rep stosq
>>>>>>>
>>>>>>> +#ifdef CONFIG_SECURE_LAUNCH
>>>>>>> + /*
>>>>>>> + * Have to do the final early sl stub work in 64b area.
>>>>>>> + *
>>>>>>> + * *********** NOTE ***********
>>>>>>> + *
>>>>>>> + * Several boot params get used before we get a chance to measure
>>>>>>> + * them in this call. This is a known issue and we currently don't
>>>>>>> + * have a solution. The scratch field doesn't matter. There is no
>>>>>>> + * obvious way to do anything about the use of kernel_alignment or
>>>>>>> + * init_size though these seem low risk with all the PMR and overlap
>>>>>>> + * checks in place.
>>>>>>> + */
>>>>>>> + movq %r15, %rdi
>>>>>>> + callq sl_main
>>>>>>> +
>>>>>>> + /* Ensure the decompression location is covered by a PMR */
>>>>>>> + movq %rbp, %rdi
>>>>>>> + movq output_len(%rip), %rsi
>>>>>>> + callq sl_check_region
>>>>>>> +#endif
>>>>>>> +
>>>>>>> + pushq %rsi
>>>>>>
>>>>>> This looks like a rebase error.
>>>>>>
>>>>>>> call load_stage2_idt
>>>>>>>
>>>>>>> /* Pass boot_params to initialize_identity_maps() */
>>>>>>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>>>>>>> index c18f07181dd5..e199b87764e9 100644
>>>>>>> --- a/arch/x86/boot/compressed/kernel_info.S
>>>>>>> +++ b/arch/x86/boot/compressed/kernel_info.S
>>>>>>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>>>>>>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>>>>>>> .long SETUP_TYPE_MAX
>>>>>>>
>>>>>>> + /* Offset to the MLE header structure */
>>>>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>>>>> + .long rva(mle_header)
>>>>>>
>>>>>> ... so this could just be mle_header - kernel_info, and the consumer
>>>>>> can do the math instead.
>>>>>>
>>>>>>> +#else
>>>>>>> + .long 0
>>>>>>> +#endif
>>>>>>> +
>>>>>>> kernel_info_var_len_data:
>>>>>>> /* Empty for time being... */
>>>>>>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>>>>>>> +
>>>>>>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>>>>>>> + /*
>>>>>>> + * The MLE Header per the TXT Specification, section 2.1
>>>>>>> + * MLE capabilities, see table 4. Capabilities set:
>>>>>>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>>>>>>> + * bit 1: Support for RLP wakeup using MONITOR address
>>>>>>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>>>>>>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>>>>>>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>>>>>>> + */
>>>>>>> +SYM_DATA_START(mle_header)
>>>>>>> + .long 0x9082ac5a /* UUID0 */
>>>>>>> + .long 0x74a7476f /* UUID1 */
>>>>>>> + .long 0xa2555c0f /* UUID2 */
>>>>>>> + .long 0x42b651cb /* UUID3 */
>>>>>>> + .long 0x00000034 /* MLE header size */
>>>>>>> + .long 0x00020002 /* MLE version 2.2 */
>>>>>>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>>>>>>
>>>>>> and these should perhaps be relative to mle_header?
>>>>>>
>>>>>>> + .long 0x00000000 /* First valid page of MLE */
>>>>>>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>>>>>>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>>>>>>
>>>>>> and here
>>>>>>
>>>>>
>>>>> Ugh never mind - these are specified externally.
>>>>
>>>> Can you clarify your follow on comment here?
>>>>
>>>
>>> I noticed that -as you pointed out in your previous reply- these
>>> fields cannot be repainted at will, as they are defined by an external
>>> specification.
>>>
>>> I'll play a bit more with this code tomorrow - I would *really* like
>>> to avoid the need for patch #1, as it adds another constraint on how
>>> we construct the boot image, and this is already riddled with legacy
>>> and other complications.
>>
>> Yea I should have read forward through all your replies before
>> responding to the first one but I think it clarified things as you point
>> out here. We appreciate you help and suggestions.
>>
>
> OK, so I have a solution that does not require kernel_info at a fixed offset:
>
> - put this at the end of arch/x86/boot/compressed/vmlinux.lds.S
>
> #ifdef CONFIG_SECURE_LAUNCH
> PROVIDE(kernel_info_offset = ABSOLUTE(kernel_info - startup_32));
> PROVIDE(mle_header_offset = kernel_info_offset +
> ABSOLUTE(mle_header - startup_32));
> PROVIDE(sl_stub_entry_offset = kernel_info_offset +
> ABSOLUTE(sl_stub_entry - startup_32));
> PROVIDE(_edata_offset = kernel_info_offset + ABSOLUTE(_edata
> - startup_32));
> #endif
>
>
> and use this for the header fields:
>
> /* Offset to the MLE header structure */
> #if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> .long mle_header_offset - kernel_info
> #else
> .long 0
> #endif
>
Awesome thank you! We will work on incorporating this unless someone
else sees a problem with it (or we run into problems and need to revisit).
Ross
>
>
> SYM_DATA_START(mle_header)
> .long 0x9082ac5a /* UUID0 */
> .long 0x74a7476f /* UUID1 */
> .long 0xa2555c0f /* UUID2 */
> .long 0x42b651cb /* UUID3 */
> .long 0x00000034 /* MLE header size */
> .long 0x00020002 /* MLE version 2.2 */
> .long sl_stub_entry_offset - kernel_info /* Linear entry
> point of MLE (virt. address) */
> .long 0x00000000 /* First valid page of MLE */
> .long 0x00000000 /* Offset within binary of first byte of MLE */
> .long _edata_offset - kernel_info /* Offset within binary of
> last byte + 1 of MLE */
> .long 0x00000227 /* Bit vector of MLE-supported capabilities */
> .long 0x00000000 /* Starting linear address of command line
> (unused) */
> .long 0x00000000 /* Ending linear address of command line (unused) */
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 11:00 ` Ard Biesheuvel
2024-05-31 13:33 ` Ard Biesheuvel
@ 2024-06-04 17:14 ` ross.philipson
1 sibling, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 17:14 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 5/31/24 4:00 AM, Ard Biesheuvel wrote:
> Hello Ross,
Hi Ard,
>
> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>> later AMD SKINIT) to vector to during the late launch. The symbol
>> sl_stub_entry is that entry point and its offset into the kernel is
>> conveyed to the launching code using the MLE (Measured Launch
>> Environment) header in the structure named mle_header. The offset of the
>> MLE header is set in the kernel_info. The routine sl_stub contains the
>> very early late launch setup code responsible for setting up the basic
>> environment to allow the normal kernel startup_32 code to proceed. It is
>> also responsible for properly waking and handling the APs on Intel
>> platforms. The routine sl_main which runs after entering 64b mode is
>> responsible for measuring configuration and module information before
>> it is used like the boot params, the kernel command line, the TXT heap,
>> an external initramfs, etc.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> Documentation/arch/x86/boot.rst | 21 +
>> arch/x86/boot/compressed/Makefile | 3 +-
>> arch/x86/boot/compressed/head_64.S | 30 +
>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>> arch/x86/include/asm/msr-index.h | 5 +
>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>> arch/x86/kernel/asm-offsets.c | 20 +
>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>
>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>> index 4fd492cb4970..295cdf9bcbdb 100644
>> --- a/Documentation/arch/x86/boot.rst
>> +++ b/Documentation/arch/x86/boot.rst
>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>> - If 1, KASLR enabled.
>> - If 0, KASLR disabled.
>>
>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>> +
>> + - Used internally by the setup kernel to communicate
>> + Secure Launch status to kernel proper.
>> +
>> + - If 1, Secure Launch enabled.
>> + - If 0, Secure Launch disabled.
>> +
>> Bit 5 (write): QUIET_FLAG
>>
>> - If 0, print early messages.
>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>
>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>
>> +============ =================
>> +Field name: mle_header_offset
>> +Offset/size: 0x0010/4
>> +============ =================
>> +
>> + This field contains the offset to the Secure Launch Measured Launch Environment
>> + (MLE) header. This offset is used to locate information needed during a secure
>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>> + following a success measured launch. The specific state of the processors is
>> + outlined in the TXT Software Development Guide, the latest can be found here:
>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!MdqTLUxfB5YUUOB1qyhkN8TF9HAoGW7yy_2qwZGWz8eb73CYkDXY-h1SeyaZjwzsSWz408D3LgDD8Zmw$
>> +
>>
>
> Could we just repaint this field as the offset relative to the start
> of kernel_info rather than relative to the start of the image? That
> way, there is no need for patch #1, and given that the consumer of
> this field accesses it via kernel_info, I wouldn't expect any issues
> in applying this offset to obtain the actual address.
What you suggest here may be possible with respect to the location of
the MLE header itself, we need to give that more thought. The real issue
though is covered in my response below concerning the fields in the MLE
header.
>
>
>> The Image Checksum
>> ==================
>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>> index 9189a0e28686..9076a248d4b4 100644
>> --- a/arch/x86/boot/compressed/Makefile
>> +++ b/arch/x86/boot/compressed/Makefile
>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>
>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>
>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>> $(call if_changed,ld)
>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>> index 1dcb794c5479..803c9e2e6d85 100644
>> --- a/arch/x86/boot/compressed/head_64.S
>> +++ b/arch/x86/boot/compressed/head_64.S
>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>> pushq $0
>> popfq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + /* Ensure the relocation region is coverd by a PMR */
>
> covered
Ack
>
>> + movq %rbx, %rdi
>> + movl $(_bss - startup_32), %esi
>> + callq sl_check_region
>> +#endif
>> +
>> /*
>> * Copy the compressed kernel to the end of our buffer
>> * where decompression in place becomes safe.
>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>> shrq $3, %rcx
>> rep stosq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + /*
>> + * Have to do the final early sl stub work in 64b area.
>> + *
>> + * *********** NOTE ***********
>> + *
>> + * Several boot params get used before we get a chance to measure
>> + * them in this call. This is a known issue and we currently don't
>> + * have a solution. The scratch field doesn't matter. There is no
>> + * obvious way to do anything about the use of kernel_alignment or
>> + * init_size though these seem low risk with all the PMR and overlap
>> + * checks in place.
>> + */
>> + movq %r15, %rdi
>> + callq sl_main
>> +
>> + /* Ensure the decompression location is covered by a PMR */
>> + movq %rbp, %rdi
>> + movq output_len(%rip), %rsi
>> + callq sl_check_region
>> +#endif
>> +
>> + pushq %rsi
>
> This looks like a rebase error.
I will need to look closely at this. I remember removing the push/pop we
added but this does seem wrong.
>
>> call load_stage2_idt
>>
>> /* Pass boot_params to initialize_identity_maps() */
>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>> index c18f07181dd5..e199b87764e9 100644
>> --- a/arch/x86/boot/compressed/kernel_info.S
>> +++ b/arch/x86/boot/compressed/kernel_info.S
>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>> .long SETUP_TYPE_MAX
>>
>> + /* Offset to the MLE header structure */
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> + .long rva(mle_header)
>
> ... so this could just be mle_header - kernel_info, and the consumer
> can do the math instead.
While we might be able to do this...
>
>> +#else
>> + .long 0
>> +#endif
>> +
>> kernel_info_var_len_data:
>> /* Empty for time being... */
>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>> +
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> + /*
>> + * The MLE Header per the TXT Specification, section 2.1
>> + * MLE capabilities, see table 4. Capabilities set:
>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>> + * bit 1: Support for RLP wakeup using MONITOR address
>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>> + */
>> +SYM_DATA_START(mle_header)
>> + .long 0x9082ac5a /* UUID0 */
>> + .long 0x74a7476f /* UUID1 */
>> + .long 0xa2555c0f /* UUID2 */
>> + .long 0x42b651cb /* UUID3 */
>> + .long 0x00000034 /* MLE header size */
>> + .long 0x00020002 /* MLE version 2.2 */
>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>
> and these should perhaps be relative to mle_header?
... this would be much more problematic. For TXT, the SINIT ACM is the
consumer of this field and it expects it to be relative to the beginning
of the MLE image (i.e. the setup kernl and piggy in this case) and we
have no control over that. We used to fix this value up in the prologue
code for the launch but this was not a clean approach. The same issue
applies to the next comment too. We will have to see what other options
we may be able to adopt here.
>
>> + .long 0x00000000 /* First valid page of MLE */
>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>
> and here
See last comment.
>
>> + .long 0x00000227 /* Bit vector of MLE-supported capabilities */
>> + .long 0x00000000 /* Starting linear address of command line (unused) */
>> + .long 0x00000000 /* Ending linear address of command line (unused) */
>> +SYM_DATA_END(mle_header)
>> +#endif
>> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
>> new file mode 100644
>> index 000000000000..61e9baf410fd
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_main.c
>> @@ -0,0 +1,577 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Secure Launch early measurement and validation routines.
>> + *
>> + * Copyright (c) 2024, Oracle and/or its affiliates.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/string.h>
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/boot.h>
>> +#include <asm/msr.h>
>> +#include <asm/mtrr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/bootparam_utils.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +#include <crypto/sha1.h>
>> +#include <crypto/sha2.h>
>> +
>> +#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff
>> +
>> +#define SL_TPM12_LOG 1
>> +#define SL_TPM20_LOG 2
>> +
>> +#define SL_TPM20_MAX_ALGS 2
>> +
>> +#define SL_MAX_EVENT_DATA 64
>> +#define SL_TPM12_LOG_SIZE (sizeof(struct tcg_pcr_event) + \
>> + SL_MAX_EVENT_DATA)
>> +#define SL_TPM20_LOG_SIZE (sizeof(struct tcg_pcr_event2_head) + \
>> + SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
>> + sizeof(struct tcg_event_field) + \
>> + SL_MAX_EVENT_DATA)
>> +
>> +static void *evtlog_base;
>> +static u32 evtlog_size;
>> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
>> +static u32 tpm_log_ver = SL_TPM12_LOG;
>> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
>> +
>> +extern u32 sl_cpu_type;
>> +extern u32 sl_mle_start;
>> +
>> +static u64 sl_txt_read(u32 reg)
>> +{
>> + return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void sl_txt_write(u32 reg, u64 val)
>> +{
>> + writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void __noreturn sl_txt_reset(u64 error)
>> +{
>> + /* Reading the E2STS register acts as a barrier for TXT registers */
>> + sl_txt_write(TXT_CR_ERRORCODE, error);
>> + sl_txt_read(TXT_CR_E2STS);
>> + sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
>> + sl_txt_read(TXT_CR_E2STS);
>> + sl_txt_write(TXT_CR_CMD_RESET, 1);
>> +
>> + for ( ; ; )
>> + asm volatile ("hlt");
>> +
>> + unreachable();
>> +}
>> +
>> +static u64 sl_rdmsr(u32 reg)
>> +{
>> + u64 lo, hi;
>> +
>> + asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
>> +
>> + return (hi << 32) | lo;
>> +}
>> +
>> +static struct slr_table *sl_locate_and_validate_slrt(void)
>> +{
>> + struct txt_os_mle_data *os_mle_data;
>> + struct slr_table *slrt;
>> + void *txt_heap;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + if (!os_mle_data->slrt)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + slrt = (struct slr_table *)os_mle_data->slrt;
>> +
>> + if (slrt->magic != SLR_TABLE_MAGIC)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + if (slrt->architecture != SLR_INTEL_TXT)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + return slrt;
>> +}
>> +
>> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + void *end = base + size;
>> + void *txt_heap;
>> +
>> + if (!(sl_cpu_type & SL_CPU_INTEL))
>> + return;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
>> + sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
>> +
>> + /*
>> + * Note that the late stub code validates that the hi PMR covers
>> + * all memory above 4G. At this point the code can only check that
>> + * regions are within the hi PMR but that is sufficient.
>> + */
>> + if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
>
> Better to put the cast on the pointers, given that we are doing
> arithmetic, and use SZ_4G instead of open coding this constant 4
> times.
Good idea, we will do that.
>
>
>
>> + if (allow_hi) {
>> + if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
>> + os_sinit_data->vtd_pmr_hi_size))
>> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> + } else {
>> + sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
>> + }
>> + }
>> +
>> + if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
>> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> +}
>> +
>> +/*
>> + * Some MSRs are modified by the pre-launch code including the MTRRs.
>> + * The early MLE code has to restore these values. This code validates
>> + * the values after they are measured.
>> + */
>> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
>> +{
>> + struct slr_txt_mtrr_state *saved_bsp_mtrrs;
>> + u64 mtrr_caps, mtrr_def_type, mtrr_var;
>> + struct slr_entry_intel_info *txt_info;
>> + u64 misc_en_msr;
>> + u32 vcnt, i;
>> +
>> + txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
>> + saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
>> +
>> + mtrr_caps = sl_rdmsr(MSR_MTRRcap);
>> + vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
>> +
>> + if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> + if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> +
>> + mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
>> + if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
>> +
>> + for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
>> + mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
>> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
>> + mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
>> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
>> + }
>> +
>> + misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
>> + if (txt_info->saved_misc_enable_msr != misc_en_msr)
>> + sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
>> +}
>> +
>> +static void sl_find_drtm_event_log(struct slr_table *slrt)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + struct slr_entry_log_info *log_info;
>> + void *txt_heap;
>> +
>> + log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
>> + if (!log_info)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + evtlog_base = (void *)log_info->addr;
>> + evtlog_size = log_info->size;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +
>> + /*
>> + * For TPM 2.0, the event log 2.1 extended data structure has to also
>> + * be located and fixed up.
>> + */
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + /*
>> + * Only support version 6 and later that properly handle the
>> + * list of ExtDataElements in the OS-SINIT structure.
>> + */
>> + if (os_sinit_data->version < 6)
>> + sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
>> +
>> + /* Find the TPM2.0 logging extended heap element */
>> + log20_elem = tpm20_find_log2_1_element(os_sinit_data);
>> +
>> + /* If found, this implies TPM20 log and family */
>> + if (log20_elem)
>> + tpm_log_ver = SL_TPM20_LOG;
>> +}
>> +
>> +static void sl_validate_event_log_buffer(void)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + void *txt_heap, *txt_end;
>> + void *mle_base, *mle_end;
>> + void *evtlog_end;
>> +
>> + if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
>> + sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
>> + evtlog_end = evtlog_base + evtlog_size;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + mle_base = (void *)(u64)sl_mle_start;
>> + mle_end = mle_base + os_sinit_data->mle_size;
>> +
>> + /*
>> + * This check is to ensure the event log buffer does not overlap with
>> + * the MLE image.
>> + */
>> + if (evtlog_base >= mle_end && evtlog_end > mle_end)
>> + goto pmr_check; /* above */
>> +
>> + if (evtlog_end <= mle_base && evtlog_base < mle_base)
>> + goto pmr_check; /* below */
>> +
>> + sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
>> +
>> +pmr_check:
>> + /*
>> + * The TXT heap is protected by the DPR. If the TPM event log is
>> + * inside the TXT heap, there is no need for a PMR check.
>> + */
>> + if (evtlog_base > txt_heap && evtlog_end < txt_end)
>> + return;
>> +
>> + sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
>> +}
>> +
>> +static void sl_find_event_log_algorithms(void)
>> +{
>> + struct tcg_efi_specid_event_head *efi_head =
>> + (struct tcg_efi_specid_event_head *)(evtlog_base +
>> + log20_elem->first_record_offset +
>> + sizeof(struct tcg_pcr_event));
>> +
>> + if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
>> + sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
>> +
>> + memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
>> + sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
>> +}
>> +
>> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
>> + const u8 *data, u32 length,
>> + const u8 *event_data, u32 event_size)
>> +{
>> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> + u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
>> + struct tcg_pcr_event *pcr_event;
>> + u32 total_size;
>> +
>> + pcr_event = (struct tcg_pcr_event *)log_buf;
>> + pcr_event->pcr_idx = pcr;
>> + pcr_event->event_type = event_type;
>> + if (length > 0) {
>> + sha1(data, length, &sha1_hash[0]);
>> + memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
>> + }
>> + pcr_event->event_size = event_size;
>> + if (event_size > 0)
>> + memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
>> + event_data, event_size);
>> +
>> + total_size = sizeof(struct tcg_pcr_event) + event_size;
>> +
>> + if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
>> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
>> + const u8 *data, u32 length,
>> + const u8 *event_data, u32 event_size)
>> +{
>> + u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
>> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> + u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
>> + struct sha256_state sctx256 = {0};
>> + struct tcg_pcr_event2_head *head;
>> + struct tcg_event_field *event;
>> + u32 total_size;
>> + u16 *alg_ptr;
>> + u8 *dgst_ptr;
>> +
>> + head = (struct tcg_pcr_event2_head *)log_buf;
>> + head->pcr_idx = pcr;
>> + head->event_type = event_type;
>> + total_size = sizeof(struct tcg_pcr_event2_head);
>> + alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
>> +
>> + for ( ; head->count < 2; head->count++) {
>> + if (!tpm_algs[head->count].alg_id)
>> + break;
>> +
>> + *alg_ptr = tpm_algs[head->count].alg_id;
>> + dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
>> +
>> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
>> + length) {
>> + sha256_init(&sctx256);
>> + sha256_update(&sctx256, data, length);
>> + sha256_final(&sctx256, &sha256_hash[0]);
>> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
>> + length) {
>> + sha1(data, length, &sha1_hash[0]);
>> + }
>> +
>> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
>> + memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
>> + total_size += SHA256_DIGEST_SIZE + sizeof(u16);
>> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
>> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
>> + memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
>> + total_size += SHA1_DIGEST_SIZE + sizeof(u16);
>> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
>> + } else {
>> + sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
>> + }
>> + }
>> +
>> + event = (struct tcg_event_field *)(log_buf + total_size);
>> + event->event_size = event_size;
>> + if (event_size > 0)
>> + memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
>> + total_size += sizeof(struct tcg_event_field) + event_size;
>> +
>> + if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
>> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
>> + const u8 *data, u32 length, const char *desc)
>> +{
>> + if (tpm_log_ver == SL_TPM20_LOG)
>> + sl_tpm20_log_event(pcr, type, data, length,
>> + (const u8 *)desc, strlen(desc));
>> + else
>> + sl_tpm12_log_event(pcr, type, data, length,
>> + (const u8 *)desc, strlen(desc));
>> +}
>> +
>> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
>> + struct slr_policy_entry *entry)
>> +{
>> + struct setup_indirect *ind;
>> + struct setup_data *next;
>> +
>> + if (!curr)
>> + return NULL;
>> +
>> + next = (struct setup_data *)(unsigned long)curr->next;
>> +
>> + /* SETUP_INDIRECT instances have to be handled differently */
>> + if (curr->type == SETUP_INDIRECT) {
>> + ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
>> +
>> + sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)ind->addr, ind->len,
>> + entry->evt_info);
>> +
>> + return next;
>> + }
>> +
>> + sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
>> + curr->len, true);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + ((u8 *)curr) + sizeof(struct setup_data),
>> + curr->len,
>> + entry->evt_info);
>> +
>> + return next;
>> +}
>> +
>> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
>> +{
>> + struct setup_data *data;
>> +
>> + /*
>> + * Measuring the boot params measured the fixed e820 memory map.
>> + * Measure any setup_data entries including e820 extended entries.
>> + */
>> + data = (struct setup_data *)(unsigned long)entry->entity;
>> + while (data)
>> + data = sl_handle_setup_data(data, entry);
>> +}
>> +
>> +static void sl_extend_slrt(struct slr_policy_entry *entry)
>> +{
>> + struct slr_table *slrt = (struct slr_table *)entry->entity;
>> + struct slr_entry_intel_info *intel_info;
>> +
>> + /*
>> + * In revision one of the SLRT, the only table that needs to be
>> + * measured is the Intel info table. Everything else is meta-data,
>> + * addresses and sizes. Note the size of what to measure is not set.
>> + * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
>> + * to sort out.
>> + */
>> + if (slrt->revision == 1) {
>> + intel_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
>> + if (!intel_info)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)entry->entity, sizeof(struct slr_entry_intel_info),
>> + entry->evt_info);
>> + }
>> +}
>> +
>> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
>> +{
>> + struct txt_os_mle_data *os_mle_data;
>> + void *txt_heap;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + /*
>> + * Version 1 of the OS-MLE heap structure has no fields to measure. It just
>> + * has addresses and sizes and a scratch buffer.
>> + */
>> + if (os_mle_data->version == 1)
>> + return;
>> +}
>> +
>> +static void sl_process_extend_policy(struct slr_table *slrt)
>> +{
>> + struct slr_entry_policy *policy;
>> + u16 i;
>> +
>> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
>> + if (!policy)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + for (i = 0; i < policy->nr_entries; i++) {
>> + switch (policy->policy_entries[i].entity_type) {
>> + case SLR_ET_SETUP_DATA:
>> + sl_extend_setup_data(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_SLRT:
>> + sl_extend_slrt(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_TXT_OS2MLE:
>> + sl_extend_txt_os2mle(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_UNUSED:
>> + continue;
>> + default:
>> + sl_tpm_extend_evtlog(policy->policy_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)policy->policy_entries[i].entity,
>> + policy->policy_entries[i].size,
>> + policy->policy_entries[i].evt_info);
>> + }
>> + }
>> +}
>> +
>> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
>> +{
>> + struct slr_entry_uefi_config *uefi_config;
>> + u16 i;
>> +
>> + uefi_config = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
>> +
>> + /* Optionally here depending on how SL kernel was booted */
>> + if (!uefi_config)
>> + return;
>> +
>> + for (i = 0; i < uefi_config->nr_entries; i++) {
>> + sl_tpm_extend_evtlog(uefi_config->uefi_cfg_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)uefi_config->uefi_cfg_entries[i].cfg,
>> + uefi_config->uefi_cfg_entries[i].size,
>> + uefi_config->uefi_cfg_entries[i].evt_info);
>> + }
>> +}
>> +
>> +asmlinkage __visible void sl_check_region(void *base, u32 size)
>> +{
>> + sl_check_pmr_coverage(base, size, false);
>> +}
>> +
>> +asmlinkage __visible void sl_main(void *bootparams)
>> +{
>> + struct boot_params *bp = (struct boot_params *)bootparams;
>> + struct txt_os_mle_data *os_mle_data;
>> + struct slr_table *slrt;
>> + void *txt_heap;
>> +
>> + /*
>> + * Ensure loadflags do not indicate a secure launch was done
>> + * unless it really was.
>> + */
>> + bp->hdr.loadflags &= ~SLAUNCH_FLAG;
>> +
>> + /*
>> + * Currently only Intel TXT is supported for Secure Launch. Testing
>> + * this value also indicates that the kernel was booted successfully
>> + * through the Secure Launch entry point and is in SMX mode.
>> + */
>> + if (!(sl_cpu_type & SL_CPU_INTEL))
>> + return;
>> +
>> + slrt = sl_locate_and_validate_slrt();
>> +
>> + /* Locate the TPM event log. */
>> + sl_find_drtm_event_log(slrt);
>> +
>> + /* Validate the location of the event log buffer before using it */
>> + sl_validate_event_log_buffer();
>> +
>> + /*
>> + * Find the TPM hash algorithms used by the ACM and recorded in the
>> + * event log.
>> + */
>> + if (tpm_log_ver == SL_TPM20_LOG)
>> + sl_find_event_log_algorithms();
>> +
>> + /*
>> + * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
>> + * anything fails, the system will reset anyway.
>> + */
>> + sanitize_boot_params(bp);
>> + bp->hdr.loadflags |= SLAUNCH_FLAG;
>> +
>> + sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
>> +
>> + /* Place event log SL specific tags before and after measurements */
>> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
>> +
>> + /* Process all policy entries and extend the measurements to the evtlog */
>> + sl_process_extend_policy(slrt);
>> +
>> + /* Process all EFI config entries and extend the measurements to the evtlog */
>> + sl_process_extend_uefi_config(slrt);
>> +
>> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
>> +
>> + /* No PMR check is needed, the TXT heap is covered by the DPR */
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + /*
>> + * Now that the OS-MLE data is measured, ensure the MTRR and
>> + * misc enable MSRs are what we expect.
>> + */
>> + sl_txt_validate_msrs(os_mle_data);
>> +}
>> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
>> new file mode 100644
>> index 000000000000..24b8f23d5dcc
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_stub.S
>> @@ -0,0 +1,725 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +/*
>> + * Secure Launch protected mode entry point.
>> + *
>> + * Copyright (c) 2024, Oracle and/or its affiliates.
>> + */
>> + .code32
>> + .text
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/msr.h>
>> +#include <asm/apicdef.h>
>> +#include <asm/trapnr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/page_types.h>
>> +#include <asm/irq_vectors.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +
>> +/* CPUID: leaf 1, ECX, SMX feature bit */
>> +#define X86_FEATURE_BIT_SMX (1 << 6)
>> +
>> +#define IDT_VECTOR_LO_BITS 0
>> +#define IDT_VECTOR_HI_BITS 6
>> +
>> +/*
>> + * See the comment in head_64.S for detailed information on what this macro
>> + * and others like it are used for. The comment appears right at the top of
>> + * the file.
>> + */
>> +#define rva(X) ((X) - sl_stub_entry)
>> +
>> +/*
>> + * The GETSEC op code is open coded because older versions of
>> + * GCC do not support the getsec mnemonic.
>> + */
>> +.macro GETSEC leaf
>> + pushl %ebx
>> + xorl %ebx, %ebx /* Must be zero for SMCTRL */
>> + movl \leaf, %eax /* Leaf function */
>> + .byte 0x0f, 0x37 /* GETSEC opcode */
>> + popl %ebx
>> +.endm
>> +
>> +.macro TXT_RESET error
>> + /*
>> + * Set a sticky error value and reset. Note the movs to %eax act as
>> + * TXT register barriers.
>> + */
>> + movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
>> +1:
>> + hlt
>> + jmp 1b
>> +.endm
>> +
>> + .code32
>> +SYM_FUNC_START(sl_stub_entry)
>> + cli
>> + cld
>> +
>> + /*
>> + * On entry, %ebx has the entry abs offset to sl_stub_entry. This
>> + * will be correctly scaled using the rva macro and avoid causing
>> + * relocations. Only %cs and %ds segments are known good.
>
> Could you please clarify this? 'scaling' is unidiomatic in this
> context, and actually means something different in my book. AIUI, %ebx
> is guaranteed to carry the actual address of sl_stub_entry(), and
> rva() is used to generate relative references using %ebx as a base, as
> to avoid /absolute/ relocations, which would require fixups at
> runtime.
Yes, we will reword this to be clearer.
>
>
>> + */
>> +
>> + /* Load GDT, set segment regs and lret to __SL32_CS */
>> + leal rva(sl_gdt_desc)(%ebx), %eax
>> + addl %eax, 2(%eax)
>> + lgdt (%eax)
>> +
>> + movl $(__SL32_DS), %eax
>> + movw %ax, %ds
>> + movw %ax, %es
>> + movw %ax, %fs
>> + movw %ax, %gs
>> + movw %ax, %ss
>> +
>> + /*
>> + * Now that %ss is known good, take the first stack for the BSP. The
>> + * AP stacks are only used on Intel.
>> + */
>> + leal rva(sl_stacks_end)(%ebx), %esp
>> +
>> + leal rva(.Lsl_cs)(%ebx), %eax
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + lret
>> +
>> +.Lsl_cs:
>> + /* Save our base pointer reg and page table for MLE */
>> + pushl %ebx
>> + pushl %ecx
>> +
>> + /* See if SMX feature is supported. */
>> + movl $1, %eax
>> + cpuid
>> + testl $(X86_FEATURE_BIT_SMX), %ecx
>> + jz .Ldo_unknown_cpu
>> +
>> + popl %ecx
>> + popl %ebx
>> +
>> + /* Know it is Intel */
>> + movl $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
>> +
>> + /* Locate the base of the MLE using the page tables in %ecx */
>> + call sl_find_mle_base
>> +
>> + /* Increment CPU count for BSP */
>> + incl rva(sl_txt_cpu_count)(%ebx)
>> +
>> + /*
>> + * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
>> + * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
>> + * allow the mainline kernel re-enable them in the normal course of
>> + * booting.
>> + */
>> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
>> +
>> + /* Clear the TXT error registers for a clean start of day */
>> + movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> + movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
>> +
>> + /* On Intel, the zero page address is passed in the TXT heap */
>> + /* Read physical base of heap into EAX */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> + movl (%eax), %ecx
>> + /* Skip over BIOS data and size of OS to MLE data section */
>> + leal 8(%eax, %ecx), %eax
>> +
>> + /* Need to verify the values in the OS-MLE struct passed in */
>> + call sl_txt_verify_os_mle_struct
>> +
>> + /*
>> + * Get the boot params address from the heap. Note %esi and %ebx MUST
>> + * be preserved across calls and operations.
>> + */
>> + movl SL_boot_params_addr(%eax), %esi
>> +
>> + /* Save %ebx so the APs can find their way home */
>> + movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
>> +
>> + /* Fetch the AP wake code block address from the heap */
>> + movl SL_ap_wake_block(%eax), %edi
>> + movl %edi, rva(sl_txt_ap_wake_block)(%ebx)
>> +
>> + /* Store the offset in the AP wake block to the jmp address */
>> + movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
>> + (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
>> +
>> + /* Store the offset in the AP wake block to the AP stacks block */
>> + movl $(sl_stacks - sl_txt_ap_wake_begin), \
>> + (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
>> +
>> + /* %eax still is the base of the OS-MLE block, save it */
>> + pushl %eax
>> +
>> + /* Relocate the AP wake code to the safe block */
>> + call sl_txt_reloc_ap_wake
>> +
>> + /*
>> + * Wake up all APs that are blocked in the ACM and wait for them to
>> + * halt. This should be done before restoring the MTRRs so the ACM is
>> + * still properly in WB memory.
>> + */
>> + call sl_txt_wake_aps
>> +
>> + /* Restore OS-MLE in %eax */
>> + popl %eax
>> +
>> + /*
>> + * %edi is used by this routine to find the MTRRs which are in the SLRT
>> + * in the Intel info.
>> + */
>> + movl SL_txt_info(%eax), %edi
>> + call sl_txt_load_regs
>> +
>> + jmp .Lcpu_setup_done
>> +
>> +.Ldo_unknown_cpu:
>> + /* Non-Intel CPUs are not yet supported */
>> + ud2
>> +
>> +.Lcpu_setup_done:
>> + /*
>> + * Don't enable MCE at this point. The kernel will enable
>> + * it on the BSP later when it is ready.
>> + */
>> +
>> + /* Done, jump to normal 32b pm entry */
>> + jmp startup_32
>> +SYM_FUNC_END(sl_stub_entry)
>> +
>> +SYM_FUNC_START(sl_find_mle_base)
>> + /* %ecx has PDPT, get first PD */
>> + movl (%ecx), %eax
>> + andl $(PAGE_MASK), %eax
>> + /* Get first PT from first PDE */
>> + movl (%eax), %eax
>> + andl $(PAGE_MASK), %eax
>> + /* Get MLE base from first PTE */
>> + movl (%eax), %eax
>> + andl $(PAGE_MASK), %eax
>> +
>> + movl %eax, rva(sl_mle_start)(%ebx)
>> + ret
>> +SYM_FUNC_END(sl_find_mle_base)
>> +
>> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
>> + /* %ecx: buffer begin %edx: buffer end */
>> + /* %ebx: MLE begin %edi: MLE end */
>> + /* %eax: region may be inside MLE */
>> +
>> + cmpl %edi, %ecx
>> + jb .Lnext_check
>> + cmpl %edi, %edx
>> + jbe .Lnext_check
>> + jmp .Lvalid /* Buffer above MLE */
>> +
>> +.Lnext_check:
>> + cmpl %ebx, %edx
>> + ja .Linside_check
>> + cmpl %ebx, %ecx
>> + jae .Linside_check
>> + jmp .Lvalid /* Buffer below MLE */
>> +
>> +.Linside_check:
>> + cmpl $0, %eax
>> + jz .Linvalid
>> + cmpl %ebx, %ecx
>> + jb .Linvalid
>> + cmpl %edi, %edx
>> + ja .Linvalid
>> + jmp .Lvalid /* Buffer in MLE */
>> +
>> +.Linvalid:
>> + TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
>> +
>> +.Lvalid:
>> + ret
>> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
>> +
>> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
>> + pushl %ebx
>> + /*
>> + * %eax points to the base of the OS-MLE struct. Need to also
>> + * read some values from the OS-SINIT struct too.
>> + */
>> + movl -8(%eax), %ecx
>> + /* Skip over OS to MLE data section and size of OS-SINIT structure */
>> + leal (%eax, %ecx), %edx
>> +
>> + /* Load MLE image base absolute offset */
>> + movl rva(sl_mle_start)(%ebx), %ebx
>> +
>> + /* Verify the value of the low PMR base. It should always be 0. */
>> + movl SL_vtd_pmr_lo_base(%edx), %esi
>> + cmpl $0, %esi
>> + jz .Lvalid_pmr_base
>> + TXT_RESET $(SL_ERROR_LO_PMR_BASE)
>> +
>> +.Lvalid_pmr_base:
>> + /* Grab some values from OS-SINIT structure */
>> + movl SL_mle_size(%edx), %edi
>> + addl %ebx, %edi
>> + jc .Loverflow_detected
>> + movl SL_vtd_pmr_lo_size(%edx), %esi
>> +
>> + /* Check the AP wake block */
>> + movl SL_ap_wake_block(%eax), %ecx
>> + movl SL_ap_wake_block_size(%eax), %edx
>> + addl %ecx, %edx
>> + jc .Loverflow_detected
>> + pushl %eax
>> + xorl %eax, %eax
>> + call sl_check_buffer_mle_overlap
>> + popl %eax
>> + cmpl %esi, %edx
>> + ja .Lbuffer_beyond_pmr
>> +
>> + /*
>> + * Check the boot params. Note during a UEFI boot, the boot
>> + * params will be inside the MLE image. Test for this case
>> + * in the overlap case.
>> + */
>> + movl SL_boot_params_addr(%eax), %ecx
>> + movl $(PAGE_SIZE), %edx
>> + addl %ecx, %edx
>> + jc .Loverflow_detected
>> + pushl %eax
>> + movl $1, %eax
>> + call sl_check_buffer_mle_overlap
>> + popl %eax
>> + cmpl %esi, %edx
>> + ja .Lbuffer_beyond_pmr
>> +
>> + /* Check that the AP wake block is big enough */
>> + cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
>> + SL_ap_wake_block_size(%eax)
>> + jae .Lwake_block_ok
>> + TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
>> +
>> +.Lwake_block_ok:
>> + popl %ebx
>> + ret
>> +
>> +.Loverflow_detected:
>> + TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
>> +
>> +.Lbuffer_beyond_pmr:
>> + TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
>> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
>> +
>> +SYM_FUNC_START(sl_txt_ap_entry)
>> + cli
>> + cld
>> + /*
>> + * The %cs and %ds segments are known good after waking the AP.
>> + * First order of business is to find where we are and
>> + * save it in %ebx.
>> + */
>> +
>> + /* Read physical base of heap into EAX */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> + movl (%eax), %ecx
>> + /* Skip over BIOS data and size of OS to MLE data section */
>> + leal 8(%eax, %ecx), %eax
>> +
>> + /* Saved %ebx from the BSP and stash OS-MLE pointer */
>> + movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
>> +
>> + /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
>> + movl SL_txt_info(%eax), %edi
>> +
>> + /* Lock and get our stack index */
>> + movl $1, %ecx
>> +.Lspin:
>> + xorl %eax, %eax
>> + lock cmpxchgl %ecx, rva(sl_txt_spin_lock)(%ebx)
>> + pause
>> + jnz .Lspin
>> +
>> + /* Increment the stack index and use the next value inside lock */
>> + incl rva(sl_txt_stack_index)(%ebx)
>> + movl rva(sl_txt_stack_index)(%ebx), %eax
>> +
>> + /* Unlock */
>> + movl $0, rva(sl_txt_spin_lock)(%ebx)
>> +
>> + /* Location of the relocated AP wake block */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> +
>> + /* Load reloc GDT, set segment regs and lret to __SL32_CS */
>> + lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> + movl $(__SL32_DS), %edx
>> + movw %dx, %ds
>> + movw %dx, %es
>> + movw %dx, %fs
>> + movw %dx, %gs
>> + movw %dx, %ss
>> +
>> + /* Load our reloc AP stack */
>> + movl $(TXT_BOOT_STACK_SIZE), %edx
>> + mull %edx
>> + leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
>> + subl %eax, %esp
>> +
>> + /* Switch to AP code segment */
>> + leal rva(.Lsl_ap_cs)(%ebx), %eax
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + lret
>> +
>> +.Lsl_ap_cs:
>> + /* Load the relocated AP IDT */
>> + lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> + /* Fixup MTRRs and misc enable MSR on APs too */
>> + call sl_txt_load_regs
>> +
>> + /* Enable SMI with GETSEC[SMCTRL] */
>> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
>> +
>> + /* IRET-to-self can be used to enable NMIs which SENTER disabled */
>> + leal rva(.Lnmi_enabled_ap)(%ebx), %eax
>> + pushfl
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + iret
>> +
>> +.Lnmi_enabled_ap:
>> + /* Put APs in X2APIC mode like the BSP */
>> + movl $(MSR_IA32_APICBASE), %ecx
>> + rdmsr
>> + orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
>> + wrmsr
>> +
>> + /*
>> + * Basically done, increment the CPU count and jump off to the AP
>> + * wake block to wait.
>> + */
>> + lock incl rva(sl_txt_cpu_count)(%ebx)
>> +
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
>> + jmp *%eax
>> +SYM_FUNC_END(sl_txt_ap_entry)
>> +
>> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
>> + /* Save boot params register */
>> + pushl %esi
>> +
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %edi
>> +
>> + /* Fixup AP IDT and GDT descriptor before relocating */
>> + leal rva(sl_ap_idt_desc)(%ebx), %eax
>> + addl %edi, 2(%eax)
>> + leal rva(sl_ap_gdt_desc)(%ebx), %eax
>> + addl %edi, 2(%eax)
>> +
>> + /*
>> + * Copy the AP wake code and AP GDT/IDT to the protected wake block
>> + * provided by the loader. Destination already in %edi.
>> + */
>> + movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
>> + leal rva(sl_txt_ap_wake_begin)(%ebx), %esi
>> + rep movsb
>> +
>> + /* Setup the IDT for the APs to use in the relocation block */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> + addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
>> + xorl %edx, %edx
>> +
>> + /* Form the default reset vector relocation address */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %esi
>> + addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
>> +
>> +1:
>> + cmpw $(NR_VECTORS), %dx
>> + jz .Lap_idt_done
>> +
>> + cmpw $(X86_TRAP_NMI), %dx
>> + jz 2f
>> +
>> + /* Load all other fixed vectors with reset handler */
>> + movl %esi, %eax
>> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> + shrl $16, %eax
>> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> + jmp 3f
>> +
>> +2:
>> + /* Load single wake NMI IPI vector at the relocation address */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
>> + addl $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
>> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> + shrl $16, %eax
>> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> +
>> +3:
>> + incw %dx
>> + addl $8, %ecx
>> + jmp 1b
>> +
>> +.Lap_idt_done:
>> + popl %esi
>> + ret
>> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
>> +
>> +SYM_FUNC_START(sl_txt_load_regs)
>> + /* Save base pointer register */
>> + pushl %ebx
>> +
>> + /*
>> + * On Intel, the original variable MTRRs and Misc Enable MSR are
>> + * restored on the BSP at early boot. Each AP will also restore
>> + * its MTRRs and Misc Enable MSR.
>> + */
>> + pushl %edi
>> + addl $(SL_saved_bsp_mtrrs), %edi
>> + movl (%edi), %ebx
>> + pushl %ebx /* default_mem_type lo */
>> + addl $4, %edi
>> + movl (%edi), %ebx
>> + pushl %ebx /* default_mem_type hi */
>> + addl $4, %edi
>> + movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
>> + addl $8, %edi /* now at MTRR pair array */
>> + /* Write the variable MTRRs */
>> + movl $(MSR_MTRRphysBase0), %ecx
>> +1:
>> + cmpl $0, %ebx
>> + jz 2f
>> +
>> + movl (%edi), %eax /* MTRRphysBaseX lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* MTRRphysBaseX hi */
>> + wrmsr
>> + addl $4, %edi
>> + incl %ecx
>> + movl (%edi), %eax /* MTRRphysMaskX lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* MTRRphysMaskX hi */
>> + wrmsr
>> + addl $4, %edi
>> + incl %ecx
>> +
>> + decl %ebx
>> + jmp 1b
>> +2:
>> + /* Write the default MTRR register */
>> + popl %edx
>> + popl %eax
>> + movl $(MSR_MTRRdefType), %ecx
>> + wrmsr
>> +
>> + /* Return to beginning and write the misc enable msr */
>> + popl %edi
>> + addl $(SL_saved_misc_enable_msr), %edi
>> + movl (%edi), %eax /* saved_misc_enable_msr lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* saved_misc_enable_msr hi */
>> + movl $(MSR_IA32_MISC_ENABLE), %ecx
>> + wrmsr
>> +
>> + popl %ebx
>> + ret
>> +SYM_FUNC_END(sl_txt_load_regs)
>> +
>> +SYM_FUNC_START(sl_txt_wake_aps)
>> + /* Save boot params register */
>> + pushl %esi
>> +
>> + /* First setup the MLE join structure and load it into TXT reg */
>> + leal rva(sl_gdt)(%ebx), %eax
>> + leal rva(sl_txt_ap_entry)(%ebx), %ecx
>> + leal rva(sl_smx_rlp_mle_join)(%ebx), %edx
>> + movl %eax, SL_rlp_gdt_base(%edx)
>> + movl %ecx, SL_rlp_entry_point(%edx)
>> + movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
>> +
>> + /* Another TXT heap walk to find various values needed to wake APs */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* At BIOS data size, find the number of logical processors */
>> + movl (SL_num_logical_procs + 8)(%eax), %edx
>> + /* Skip over BIOS data */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* Skip over OS to MLE */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* At OS-SNIT size, get capabilities to know how to wake up the APs */
>> + movl (SL_capabilities + 8)(%eax), %esi
>> + /* Skip over OS to SNIT */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* At SINIT-MLE size, get the AP wake MONITOR address */
>> + movl (SL_rlp_wakeup_addr + 8)(%eax), %edi
>> +
>> + /* Determine how to wake up the APs */
>> + testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
>> + jz .Lwake_getsec
>> +
>> + /* Wake using MWAIT MONITOR */
>> + movl $1, (%edi)
>> + jmp .Laps_awake
>> +
>> +.Lwake_getsec:
>> + /* Wake using GETSEC(WAKEUP) */
>> + GETSEC $(SMX_X86_GETSEC_WAKEUP)
>> +
>> +.Laps_awake:
>> + /*
>> + * All of the APs are woken up and rendesvous in the relocated wake
>> + * block starting at sl_txt_ap_wake_begin. Wait for all of them to
>> + * halt.
>> + */
>> + pause
>> + cmpl rva(sl_txt_cpu_count)(%ebx), %edx
>> + jne .Laps_awake
>> +
>> + popl %esi
>> + ret
>> +SYM_FUNC_END(sl_txt_wake_aps)
>> +
>> +/* This is the beginning of the relocated AP wake code block */
>> + .global sl_txt_ap_wake_begin
>> +sl_txt_ap_wake_begin:
>> +
>> + /* Get the LAPIC ID for each AP and stash it on the stack */
>> + movl $(MSR_IA32_X2APIC_APICID), %ecx
>> + rdmsr
>> + pushl %eax
>> +
>> + /*
>> + * Get a pointer to the monitor location on this APs stack to test below
>> + * after mwait returns. Currently %esp points to just past the pushed APIC
>> + * ID value.
>> + */
>> + movl %esp, %eax
>> + subl $(TXT_BOOT_STACK_SIZE - 4), %eax
>> + movl $0, (%eax)
>> +
>> + /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
>> + xorl %ecx, %ecx
>> + xorl %edx, %edx
>> +
>> + /*
>> + * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
>> + * instruction can return for a number of reasons. Test to see if it returned
>> + * because the monitor was written to.
>> + */
>> + monitor
>> +
>> +1:
>> + mfence
>> + mwait
>> + movl (%eax), %edx
>> + testl %edx, %edx
>> + jz 1b
>> +
>> + /*
>> + * This is the long absolute jump to the 32b Secure Launch protected mode stub
>> + * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
>> + * fixed in the SMP boot code when the first AP is brought up. This whole area
>> + * is provided and protected in the memory map by the prelaunch code.
>> + */
>> + .byte 0xea
>> +sl_ap_jmp_offset:
>> + .long 0x00000000
>> + .word __SL32_CS
>> +
>> +SYM_FUNC_START(sl_txt_int_nmi)
>> + /* NMI context, just IRET */
>> + iret
>> +SYM_FUNC_END(sl_txt_int_nmi)
>> +
>> +SYM_FUNC_START(sl_txt_int_reset)
>> + TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
>> +SYM_FUNC_END(sl_txt_int_reset)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
>> + .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */
>> + .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */
>> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt)
>> + .rept NR_VECTORS
>> + .word 0x0000 /* Offset 15 to 0 */
>> + .word __SL32_CS /* Segment selector */
>> + .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */
>> + .word 0x0000 /* Offset 31 to 16 */
>> + .endr
>> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
>> + .word sl_ap_gdt_end - sl_ap_gdt - 1
>> + .long sl_ap_gdt - sl_txt_ap_wake_begin
>> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt)
>> + .quad 0x0000000000000000 /* NULL */
>> + .quad 0x00cf9a000000ffff /* __SL32_CS */
>> + .quad 0x00cf92000000ffff /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
>> +
>> + /* Small stacks for BSP and APs to work with */
>> + .balign 64
>> +SYM_DATA_START_LOCAL(sl_stacks)
>> + .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
>> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
>> +
>> +/* This is the end of the relocated AP wake code block */
>> + .global sl_txt_ap_wake_end
>> +sl_txt_ap_wake_end:
>> +
>> + .data
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt_desc)
>> + .word sl_gdt_end - sl_gdt - 1
>> + .long sl_gdt - sl_gdt_desc
>> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt)
>> + .quad 0x0000000000000000 /* NULL */
>> + .quad 0x00cf9a000000ffff /* __SL32_CS */
>> + .quad 0x00cf92000000ffff /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
>> + .long sl_gdt_end - sl_gdt - 1 /* GDT limit */
>> + .long 0x00000000 /* GDT base */
>> + .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
>> + .long 0x00000000 /* Entry point physical address */
>> +SYM_DATA_END(sl_smx_rlp_mle_join)
>> +
>> +SYM_DATA(sl_cpu_type, .long 0x00000000)
>> +
>> +SYM_DATA(sl_mle_start, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
>> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
>> index e022e6eb766c..37f6167f28ba 100644
>> --- a/arch/x86/include/asm/msr-index.h
>> +++ b/arch/x86/include/asm/msr-index.h
>> @@ -348,6 +348,9 @@
>> #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
>> #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561
>>
>> +#define MSR_MTRRphysBase0 0x00000200
>> +#define MSR_MTRRphysMask0 0x00000201
>> +
>> #define MSR_MTRRfix64K_00000 0x00000250
>> #define MSR_MTRRfix16K_80000 0x00000258
>> #define MSR_MTRRfix16K_A0000 0x00000259
>> @@ -849,6 +852,8 @@
>> #define MSR_IA32_APICBASE_ENABLE (1<<11)
>> #define MSR_IA32_APICBASE_BASE (0xfffff<<12)
>>
>> +#define MSR_IA32_X2APIC_APICID 0x00000802
>> +
>> #define MSR_IA32_UCODE_WRITE 0x00000079
>> #define MSR_IA32_UCODE_REV 0x0000008b
>>
>> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
>> index 9b82eebd7add..7ce283a22d6b 100644
>> --- a/arch/x86/include/uapi/asm/bootparam.h
>> +++ b/arch/x86/include/uapi/asm/bootparam.h
>> @@ -12,6 +12,7 @@
>> /* loadflags */
>> #define LOADED_HIGH (1<<0)
>> #define KASLR_FLAG (1<<1)
>> +#define SLAUNCH_FLAG (1<<2)
>> #define QUIET_FLAG (1<<5)
>> #define KEEP_SEGMENTS (1<<6)
>> #define CAN_USE_HEAP (1<<7)
>> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
>> index a98020bf31bb..925adce6e2c7 100644
>> --- a/arch/x86/kernel/asm-offsets.c
>> +++ b/arch/x86/kernel/asm-offsets.c
>> @@ -13,6 +13,8 @@
>> #include <linux/hardirq.h>
>> #include <linux/suspend.h>
>> #include <linux/kbuild.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> #include <asm/processor.h>
>> #include <asm/thread_info.h>
>> #include <asm/sigframe.h>
>> @@ -120,4 +122,22 @@ static void __used common(void)
>> OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
>> #endif
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + BLANK();
>> + OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
>> + OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
>> + OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
>> + OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
>> + OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
>> + OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
>> + OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
>> + OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
>> + OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
>> + OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
>> + OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
>> + OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
>> + OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
>> + OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
>> + OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
>> +#endif
>> }
>> --
>> 2.39.3
>>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-05-31 1:03 ` [PATCH v9 08/19] x86: Secure Launch kernel early boot stub Ross Philipson
2024-05-31 11:00 ` Ard Biesheuvel
@ 2024-06-04 19:56 ` Jarkko Sakkinen
2024-06-04 21:09 ` ross.philipson
1 sibling, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 19:56 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
> later AMD SKINIT) to vector to during the late launch. The symbol
> sl_stub_entry is that entry point and its offset into the kernel is
> conveyed to the launching code using the MLE (Measured Launch
> Environment) header in the structure named mle_header. The offset of the
> MLE header is set in the kernel_info. The routine sl_stub contains the
> very early late launch setup code responsible for setting up the basic
> environment to allow the normal kernel startup_32 code to proceed. It is
> also responsible for properly waking and handling the APs on Intel
> platforms. The routine sl_main which runs after entering 64b mode is
> responsible for measuring configuration and module information before
> it is used like the boot params, the kernel command line, the TXT heap,
> an external initramfs, etc.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> Documentation/arch/x86/boot.rst | 21 +
> arch/x86/boot/compressed/Makefile | 3 +-
> arch/x86/boot/compressed/head_64.S | 30 +
> arch/x86/boot/compressed/kernel_info.S | 34 ++
> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
> arch/x86/include/asm/msr-index.h | 5 +
> arch/x86/include/uapi/asm/bootparam.h | 1 +
> arch/x86/kernel/asm-offsets.c | 20 +
> 9 files changed, 1415 insertions(+), 1 deletion(-)
> create mode 100644 arch/x86/boot/compressed/sl_main.c
> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>
> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
> index 4fd492cb4970..295cdf9bcbdb 100644
> --- a/Documentation/arch/x86/boot.rst
> +++ b/Documentation/arch/x86/boot.rst
> @@ -482,6 +482,14 @@ Protocol: 2.00+
> - If 1, KASLR enabled.
> - If 0, KASLR disabled.
>
> + Bit 2 (kernel internal): SLAUNCH_FLAG
> +
> + - Used internally by the setup kernel to communicate
> + Secure Launch status to kernel proper.
> +
> + - If 1, Secure Launch enabled.
> + - If 0, Secure Launch disabled.
> +
> Bit 5 (write): QUIET_FLAG
>
> - If 0, print early messages.
> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>
> This field contains maximal allowed type for setup_data and setup_indirect structs.
>
> +============ =================
> +Field name: mle_header_offset
> +Offset/size: 0x0010/4
> +============ =================
> +
> + This field contains the offset to the Secure Launch Measured Launch Environment
> + (MLE) header. This offset is used to locate information needed during a secure
> + late launch using Intel TXT. If the offset is zero, the kernel does not have
> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
> + following a success measured launch. The specific state of the processors is
> + outlined in the TXT Software Development Guide, the latest can be found here:
> + https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf
> +
>
> The Image Checksum
> ==================
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index 9189a0e28686..9076a248d4b4 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>
> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
> + $(obj)/sl_main.o $(obj)/sl_stub.o
>
> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
> $(call if_changed,ld)
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index 1dcb794c5479..803c9e2e6d85 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
> pushq $0
> popfq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + /* Ensure the relocation region is coverd by a PMR */
> + movq %rbx, %rdi
> + movl $(_bss - startup_32), %esi
> + callq sl_check_region
> +#endif
> +
> /*
> * Copy the compressed kernel to the end of our buffer
> * where decompression in place becomes safe.
> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
> shrq $3, %rcx
> rep stosq
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + /*
> + * Have to do the final early sl stub work in 64b area.
> + *
> + * *********** NOTE ***********
> + *
> + * Several boot params get used before we get a chance to measure
> + * them in this call. This is a known issue and we currently don't
> + * have a solution. The scratch field doesn't matter. There is no
> + * obvious way to do anything about the use of kernel_alignment or
> + * init_size though these seem low risk with all the PMR and overlap
> + * checks in place.
> + */
> + movq %r15, %rdi
> + callq sl_main
> +
> + /* Ensure the decompression location is covered by a PMR */
> + movq %rbp, %rdi
> + movq output_len(%rip), %rsi
> + callq sl_check_region
> +#endif
> +
> + pushq %rsi
> call load_stage2_idt
>
> /* Pass boot_params to initialize_identity_maps() */
> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
> index c18f07181dd5..e199b87764e9 100644
> --- a/arch/x86/boot/compressed/kernel_info.S
> +++ b/arch/x86/boot/compressed/kernel_info.S
> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
> /* Maximal allowed type for setup_data and setup_indirect structs. */
> .long SETUP_TYPE_MAX
>
> + /* Offset to the MLE header structure */
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> + .long rva(mle_header)
> +#else
> + .long 0
> +#endif
> +
> kernel_info_var_len_data:
> /* Empty for time being... */
> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
> +
> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
> + /*
> + * The MLE Header per the TXT Specification, section 2.1
> + * MLE capabilities, see table 4. Capabilities set:
> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
> + * bit 1: Support for RLP wakeup using MONITOR address
> + * bit 2: The ECX register will contain the pointer to the MLE page table
> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
> + */
> +SYM_DATA_START(mle_header)
> + .long 0x9082ac5a /* UUID0 */
> + .long 0x74a7476f /* UUID1 */
> + .long 0xa2555c0f /* UUID2 */
> + .long 0x42b651cb /* UUID3 */
> + .long 0x00000034 /* MLE header size */
> + .long 0x00020002 /* MLE version 2.2 */
> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
> + .long 0x00000000 /* First valid page of MLE */
> + .long 0x00000000 /* Offset within binary of first byte of MLE */
> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
> + .long 0x00000227 /* Bit vector of MLE-supported capabilities */
> + .long 0x00000000 /* Starting linear address of command line (unused) */
> + .long 0x00000000 /* Ending linear address of command line (unused) */
> +SYM_DATA_END(mle_header)
> +#endif
> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
> new file mode 100644
> index 000000000000..61e9baf410fd
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_main.c
> @@ -0,0 +1,577 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Secure Launch early measurement and validation routines.
> + *
> + * Copyright (c) 2024, Oracle and/or its affiliates.
> + */
> +
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/boot.h>
> +#include <asm/msr.h>
> +#include <asm/mtrr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/bootparam_utils.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +#include <crypto/sha1.h>
> +#include <crypto/sha2.h>
> +
> +#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff
> +
> +#define SL_TPM12_LOG 1
> +#define SL_TPM20_LOG 2
> +
> +#define SL_TPM20_MAX_ALGS 2
> +
> +#define SL_MAX_EVENT_DATA 64
> +#define SL_TPM12_LOG_SIZE (sizeof(struct tcg_pcr_event) + \
> + SL_MAX_EVENT_DATA)
> +#define SL_TPM20_LOG_SIZE (sizeof(struct tcg_pcr_event2_head) + \
> + SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
> + sizeof(struct tcg_event_field) + \
> + SL_MAX_EVENT_DATA)
> +
> +static void *evtlog_base;
> +static u32 evtlog_size;
> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
> +static u32 tpm_log_ver = SL_TPM12_LOG;
> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
> +
> +extern u32 sl_cpu_type;
> +extern u32 sl_mle_start;
> +
> +static u64 sl_txt_read(u32 reg)
> +{
> + return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void sl_txt_write(u32 reg, u64 val)
> +{
> + writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
> +}
> +
> +static void __noreturn sl_txt_reset(u64 error)
> +{
> + /* Reading the E2STS register acts as a barrier for TXT registers */
> + sl_txt_write(TXT_CR_ERRORCODE, error);
> + sl_txt_read(TXT_CR_E2STS);
> + sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
> + sl_txt_read(TXT_CR_E2STS);
> + sl_txt_write(TXT_CR_CMD_RESET, 1);
> +
> + for ( ; ; )
> + asm volatile ("hlt");
> +
> + unreachable();
> +}
> +
> +static u64 sl_rdmsr(u32 reg)
> +{
> + u64 lo, hi;
> +
> + asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
> +
> + return (hi << 32) | lo;
> +}
> +
> +static struct slr_table *sl_locate_and_validate_slrt(void)
> +{
> + struct txt_os_mle_data *os_mle_data;
> + struct slr_table *slrt;
> + void *txt_heap;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + if (!os_mle_data->slrt)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + slrt = (struct slr_table *)os_mle_data->slrt;
> +
> + if (slrt->magic != SLR_TABLE_MAGIC)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + if (slrt->architecture != SLR_INTEL_TXT)
> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
> +
> + return slrt;
> +}
> +
> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + void *end = base + size;
> + void *txt_heap;
> +
> + if (!(sl_cpu_type & SL_CPU_INTEL))
> + return;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
> + sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
> +
> + /*
> + * Note that the late stub code validates that the hi PMR covers
> + * all memory above 4G. At this point the code can only check that
> + * regions are within the hi PMR but that is sufficient.
> + */
> + if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
> + if (allow_hi) {
> + if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
> + os_sinit_data->vtd_pmr_hi_size))
> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> + } else {
> + sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
> + }
> + }
> +
> + if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
> +}
> +
> +/*
> + * Some MSRs are modified by the pre-launch code including the MTRRs.
> + * The early MLE code has to restore these values. This code validates
> + * the values after they are measured.
> + */
> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
> +{
> + struct slr_txt_mtrr_state *saved_bsp_mtrrs;
> + u64 mtrr_caps, mtrr_def_type, mtrr_var;
> + struct slr_entry_intel_info *txt_info;
> + u64 misc_en_msr;
> + u32 vcnt, i;
> +
> + txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
> + saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
> +
> + mtrr_caps = sl_rdmsr(MSR_MTRRcap);
> + vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
> +
> + if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> + if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
> +
> + mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
> + if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
> + sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
> +
> + for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
> + mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
> + sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
> + mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
> + sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
> + }
> +
> + misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
> + if (txt_info->saved_misc_enable_msr != misc_en_msr)
> + sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
> +}
> +
> +static void sl_find_drtm_event_log(struct slr_table *slrt)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + struct slr_entry_log_info *log_info;
> + void *txt_heap;
> +
> + log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
> + if (!log_info)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + evtlog_base = (void *)log_info->addr;
> + evtlog_size = log_info->size;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> +
> + /*
> + * For TPM 2.0, the event log 2.1 extended data structure has to also
> + * be located and fixed up.
> + */
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + /*
> + * Only support version 6 and later that properly handle the
> + * list of ExtDataElements in the OS-SINIT structure.
> + */
> + if (os_sinit_data->version < 6)
> + sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
> +
> + /* Find the TPM2.0 logging extended heap element */
> + log20_elem = tpm20_find_log2_1_element(os_sinit_data);
s/tpm20/tpm2/
> +
> + /* If found, this implies TPM20 log and family */
> + if (log20_elem)
> + tpm_log_ver = SL_TPM20_LOG;
> +}
> +
> +static void sl_validate_event_log_buffer(void)
> +{
> + struct txt_os_sinit_data *os_sinit_data;
> + void *txt_heap, *txt_end;
> + void *mle_base, *mle_end;
> + void *evtlog_end;
> +
> + if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
> + sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
> + evtlog_end = evtlog_base + evtlog_size;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
> +
> + mle_base = (void *)(u64)sl_mle_start;
> + mle_end = mle_base + os_sinit_data->mle_size;
> +
> + /*
> + * This check is to ensure the event log buffer does not overlap with
> + * the MLE image.
> + */
> + if (evtlog_base >= mle_end && evtlog_end > mle_end)
> + goto pmr_check; /* above */
> +
> + if (evtlog_end <= mle_base && evtlog_base < mle_base)
> + goto pmr_check; /* below */
> +
> + sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
> +
> +pmr_check:
> + /*
> + * The TXT heap is protected by the DPR. If the TPM event log is
> + * inside the TXT heap, there is no need for a PMR check.
> + */
> + if (evtlog_base > txt_heap && evtlog_end < txt_end)
> + return;
> +
> + sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
> +}
> +
> +static void sl_find_event_log_algorithms(void)
> +{
> + struct tcg_efi_specid_event_head *efi_head =
> + (struct tcg_efi_specid_event_head *)(evtlog_base +
> + log20_elem->first_record_offset +
> + sizeof(struct tcg_pcr_event));
> +
> + if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
> + sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
> +
> + memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
> + sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
> +}
> +
> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
> + const u8 *data, u32 length,
> + const u8 *event_data, u32 event_size)
> +{
> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> + u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
> + struct tcg_pcr_event *pcr_event;
> + u32 total_size;
> +
> + pcr_event = (struct tcg_pcr_event *)log_buf;
> + pcr_event->pcr_idx = pcr;
> + pcr_event->event_type = event_type;
> + if (length > 0) {
> + sha1(data, length, &sha1_hash[0]);
> + memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
> + }
> + pcr_event->event_size = event_size;
> + if (event_size > 0)
> + memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
> + event_data, event_size);
> +
> + total_size = sizeof(struct tcg_pcr_event) + event_size;
> +
> + if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
> + const u8 *data, u32 length,
> + const u8 *event_data, u32 event_size)
> +{
> + u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
> + u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
> + struct sha256_state sctx256 = {0};
> + struct tcg_pcr_event2_head *head;
> + struct tcg_event_field *event;
> + u32 total_size;
> + u16 *alg_ptr;
> + u8 *dgst_ptr;
> +
> + head = (struct tcg_pcr_event2_head *)log_buf;
> + head->pcr_idx = pcr;
> + head->event_type = event_type;
> + total_size = sizeof(struct tcg_pcr_event2_head);
> + alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
> +
> + for ( ; head->count < 2; head->count++) {
> + if (!tpm_algs[head->count].alg_id)
> + break;
> +
> + *alg_ptr = tpm_algs[head->count].alg_id;
> + dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
> +
> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
> + length) {
> + sha256_init(&sctx256);
> + sha256_update(&sctx256, data, length);
> + sha256_final(&sctx256, &sha256_hash[0]);
> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
> + length) {
> + sha1(data, length, &sha1_hash[0]);
> + }
> +
> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
> + memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
> + total_size += SHA256_DIGEST_SIZE + sizeof(u16);
> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
> + memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
> + total_size += SHA1_DIGEST_SIZE + sizeof(u16);
> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
> + } else {
> + sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
> + }
> + }
> +
> + event = (struct tcg_event_field *)(log_buf + total_size);
> + event->event_size = event_size;
> + if (event_size > 0)
> + memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
> + total_size += sizeof(struct tcg_event_field) + event_size;
> +
> + if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
> +}
> +
> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
> + const u8 *data, u32 length, const char *desc)
> +{
> + if (tpm_log_ver == SL_TPM20_LOG)
> + sl_tpm20_log_event(pcr, type, data, length,
> + (const u8 *)desc, strlen(desc));
> + else
> + sl_tpm12_log_event(pcr, type, data, length,
> + (const u8 *)desc, strlen(desc));
> +}
> +
> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
> + struct slr_policy_entry *entry)
> +{
> + struct setup_indirect *ind;
> + struct setup_data *next;
> +
> + if (!curr)
> + return NULL;
> +
> + next = (struct setup_data *)(unsigned long)curr->next;
> +
> + /* SETUP_INDIRECT instances have to be handled differently */
> + if (curr->type == SETUP_INDIRECT) {
> + ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
> +
> + sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)ind->addr, ind->len,
> + entry->evt_info);
> +
> + return next;
> + }
> +
> + sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
> + curr->len, true);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + ((u8 *)curr) + sizeof(struct setup_data),
> + curr->len,
> + entry->evt_info);
> +
> + return next;
> +}
> +
> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
> +{
> + struct setup_data *data;
> +
> + /*
> + * Measuring the boot params measured the fixed e820 memory map.
> + * Measure any setup_data entries including e820 extended entries.
> + */
> + data = (struct setup_data *)(unsigned long)entry->entity;
> + while (data)
> + data = sl_handle_setup_data(data, entry);
> +}
> +
> +static void sl_extend_slrt(struct slr_policy_entry *entry)
> +{
> + struct slr_table *slrt = (struct slr_table *)entry->entity;
> + struct slr_entry_intel_info *intel_info;
> +
> + /*
> + * In revision one of the SLRT, the only table that needs to be
> + * measured is the Intel info table. Everything else is meta-data,
> + * addresses and sizes. Note the size of what to measure is not set.
> + * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
> + * to sort out.
> + */
> + if (slrt->revision == 1) {
> + intel_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
> + if (!intel_info)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)entry->entity, sizeof(struct slr_entry_intel_info),
> + entry->evt_info);
> + }
> +}
> +
> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
> +{
> + struct txt_os_mle_data *os_mle_data;
> + void *txt_heap;
> +
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + /*
> + * Version 1 of the OS-MLE heap structure has no fields to measure. It just
> + * has addresses and sizes and a scratch buffer.
> + */
> + if (os_mle_data->version == 1)
> + return;
> +}
> +
> +static void sl_process_extend_policy(struct slr_table *slrt)
> +{
> + struct slr_entry_policy *policy;
> + u16 i;
> +
> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
> + if (!policy)
> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
> +
> + for (i = 0; i < policy->nr_entries; i++) {
> + switch (policy->policy_entries[i].entity_type) {
> + case SLR_ET_SETUP_DATA:
> + sl_extend_setup_data(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_SLRT:
> + sl_extend_slrt(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_TXT_OS2MLE:
> + sl_extend_txt_os2mle(&policy->policy_entries[i]);
> + break;
> + case SLR_ET_UNUSED:
> + continue;
> + default:
> + sl_tpm_extend_evtlog(policy->policy_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)policy->policy_entries[i].entity,
> + policy->policy_entries[i].size,
> + policy->policy_entries[i].evt_info);
> + }
> + }
> +}
> +
> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
> +{
> + struct slr_entry_uefi_config *uefi_config;
> + u16 i;
> +
> + uefi_config = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
> +
> + /* Optionally here depending on how SL kernel was booted */
> + if (!uefi_config)
> + return;
> +
> + for (i = 0; i < uefi_config->nr_entries; i++) {
> + sl_tpm_extend_evtlog(uefi_config->uefi_cfg_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
> + (void *)uefi_config->uefi_cfg_entries[i].cfg,
> + uefi_config->uefi_cfg_entries[i].size,
> + uefi_config->uefi_cfg_entries[i].evt_info);
> + }
> +}
> +
> +asmlinkage __visible void sl_check_region(void *base, u32 size)
> +{
> + sl_check_pmr_coverage(base, size, false);
> +}
> +
> +asmlinkage __visible void sl_main(void *bootparams)
> +{
> + struct boot_params *bp = (struct boot_params *)bootparams;
> + struct txt_os_mle_data *os_mle_data;
> + struct slr_table *slrt;
> + void *txt_heap;
> +
> + /*
> + * Ensure loadflags do not indicate a secure launch was done
> + * unless it really was.
> + */
> + bp->hdr.loadflags &= ~SLAUNCH_FLAG;
> +
> + /*
> + * Currently only Intel TXT is supported for Secure Launch. Testing
> + * this value also indicates that the kernel was booted successfully
> + * through the Secure Launch entry point and is in SMX mode.
> + */
> + if (!(sl_cpu_type & SL_CPU_INTEL))
> + return;
> +
> + slrt = sl_locate_and_validate_slrt();
> +
> + /* Locate the TPM event log. */
> + sl_find_drtm_event_log(slrt);
> +
> + /* Validate the location of the event log buffer before using it */
> + sl_validate_event_log_buffer();
> +
> + /*
> + * Find the TPM hash algorithms used by the ACM and recorded in the
> + * event log.
> + */
> + if (tpm_log_ver == SL_TPM20_LOG)
> + sl_find_event_log_algorithms();
> +
> + /*
> + * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
> + * anything fails, the system will reset anyway.
> + */
> + sanitize_boot_params(bp);
> + bp->hdr.loadflags |= SLAUNCH_FLAG;
> +
> + sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
> +
> + /* Place event log SL specific tags before and after measurements */
> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
> +
> + /* Process all policy entries and extend the measurements to the evtlog */
These comments obfuscate code here but would make a lot more sense
in the beginning of each corresponding function.
/*
* Process all policy entries and extend the measurements to the evtlog
*/
static void sl_process_extend_policy(struct slr_table *slrt)
{
/* ... */
}
BTW what good that "process" does here? Why not just sl_extend_policy()?
> + sl_process_extend_policy(slrt);
> +
> + /* Process all EFI config entries and extend the measurements to the evtlog */
> + sl_process_extend_uefi_config(slrt);
Ditto.
> +
> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
> +
> + /* No PMR check is needed, the TXT heap is covered by the DPR */
> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
> + os_mle_data = txt_os_mle_data_start(txt_heap);
> +
> + /*
> + * Now that the OS-MLE data is measured, ensure the MTRR and
> + * misc enable MSRs are what we expect.
> + */
> + sl_txt_validate_msrs(os_mle_data);
> +}
> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
> new file mode 100644
> index 000000000000..24b8f23d5dcc
> --- /dev/null
> +++ b/arch/x86/boot/compressed/sl_stub.S
> @@ -0,0 +1,725 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/*
> + * Secure Launch protected mode entry point.
> + *
> + * Copyright (c) 2024, Oracle and/or its affiliates.
> + */
> + .code32
> + .text
> +#include <linux/linkage.h>
> +#include <asm/segment.h>
> +#include <asm/msr.h>
> +#include <asm/apicdef.h>
> +#include <asm/trapnr.h>
> +#include <asm/processor-flags.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/bootparam.h>
> +#include <asm/page_types.h>
> +#include <asm/irq_vectors.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> +
> +/* CPUID: leaf 1, ECX, SMX feature bit */
> +#define X86_FEATURE_BIT_SMX (1 << 6)
> +
> +#define IDT_VECTOR_LO_BITS 0
> +#define IDT_VECTOR_HI_BITS 6
> +
> +/*
> + * See the comment in head_64.S for detailed information on what this macro
> + * and others like it are used for. The comment appears right at the top of
> + * the file.
> + */
> +#define rva(X) ((X) - sl_stub_entry)
> +
> +/*
> + * The GETSEC op code is open coded because older versions of
> + * GCC do not support the getsec mnemonic.
> + */
> +.macro GETSEC leaf
> + pushl %ebx
> + xorl %ebx, %ebx /* Must be zero for SMCTRL */
> + movl \leaf, %eax /* Leaf function */
> + .byte 0x0f, 0x37 /* GETSEC opcode */
> + popl %ebx
> +.endm
> +
> +.macro TXT_RESET error
> + /*
> + * Set a sticky error value and reset. Note the movs to %eax act as
> + * TXT register barriers.
> + */
> + movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
> +1:
> + hlt
> + jmp 1b
> +.endm
> +
> + .code32
> +SYM_FUNC_START(sl_stub_entry)
> + cli
> + cld
> +
> + /*
> + * On entry, %ebx has the entry abs offset to sl_stub_entry. This
> + * will be correctly scaled using the rva macro and avoid causing
> + * relocations. Only %cs and %ds segments are known good.
> + */
> +
> + /* Load GDT, set segment regs and lret to __SL32_CS */
> + leal rva(sl_gdt_desc)(%ebx), %eax
> + addl %eax, 2(%eax)
> + lgdt (%eax)
> +
> + movl $(__SL32_DS), %eax
> + movw %ax, %ds
> + movw %ax, %es
> + movw %ax, %fs
> + movw %ax, %gs
> + movw %ax, %ss
> +
> + /*
> + * Now that %ss is known good, take the first stack for the BSP. The
> + * AP stacks are only used on Intel.
> + */
> + leal rva(sl_stacks_end)(%ebx), %esp
> +
> + leal rva(.Lsl_cs)(%ebx), %eax
> + pushl $(__SL32_CS)
> + pushl %eax
> + lret
> +
> +.Lsl_cs:
> + /* Save our base pointer reg and page table for MLE */
> + pushl %ebx
> + pushl %ecx
> +
> + /* See if SMX feature is supported. */
> + movl $1, %eax
> + cpuid
> + testl $(X86_FEATURE_BIT_SMX), %ecx
> + jz .Ldo_unknown_cpu
> +
> + popl %ecx
> + popl %ebx
> +
> + /* Know it is Intel */
> + movl $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
> +
> + /* Locate the base of the MLE using the page tables in %ecx */
> + call sl_find_mle_base
> +
> + /* Increment CPU count for BSP */
> + incl rva(sl_txt_cpu_count)(%ebx)
> +
> + /*
> + * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
> + * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
> + * allow the mainline kernel re-enable them in the normal course of
> + * booting.
> + */
> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
> +
> + /* Clear the TXT error registers for a clean start of day */
> + movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
> + movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
> +
> + /* On Intel, the zero page address is passed in the TXT heap */
> + /* Read physical base of heap into EAX */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
> + movl (%eax), %ecx
> + /* Skip over BIOS data and size of OS to MLE data section */
> + leal 8(%eax, %ecx), %eax
> +
> + /* Need to verify the values in the OS-MLE struct passed in */
> + call sl_txt_verify_os_mle_struct
> +
> + /*
> + * Get the boot params address from the heap. Note %esi and %ebx MUST
> + * be preserved across calls and operations.
> + */
> + movl SL_boot_params_addr(%eax), %esi
> +
> + /* Save %ebx so the APs can find their way home */
> + movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
> +
> + /* Fetch the AP wake code block address from the heap */
> + movl SL_ap_wake_block(%eax), %edi
> + movl %edi, rva(sl_txt_ap_wake_block)(%ebx)
> +
> + /* Store the offset in the AP wake block to the jmp address */
> + movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
> + (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
> +
> + /* Store the offset in the AP wake block to the AP stacks block */
> + movl $(sl_stacks - sl_txt_ap_wake_begin), \
> + (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
> +
> + /* %eax still is the base of the OS-MLE block, save it */
> + pushl %eax
> +
> + /* Relocate the AP wake code to the safe block */
> + call sl_txt_reloc_ap_wake
> +
> + /*
> + * Wake up all APs that are blocked in the ACM and wait for them to
> + * halt. This should be done before restoring the MTRRs so the ACM is
> + * still properly in WB memory.
> + */
> + call sl_txt_wake_aps
> +
> + /* Restore OS-MLE in %eax */
> + popl %eax
> +
> + /*
> + * %edi is used by this routine to find the MTRRs which are in the SLRT
> + * in the Intel info.
> + */
> + movl SL_txt_info(%eax), %edi
> + call sl_txt_load_regs
> +
> + jmp .Lcpu_setup_done
> +
> +.Ldo_unknown_cpu:
> + /* Non-Intel CPUs are not yet supported */
> + ud2
> +
> +.Lcpu_setup_done:
> + /*
> + * Don't enable MCE at this point. The kernel will enable
> + * it on the BSP later when it is ready.
> + */
> +
> + /* Done, jump to normal 32b pm entry */
> + jmp startup_32
> +SYM_FUNC_END(sl_stub_entry)
> +
> +SYM_FUNC_START(sl_find_mle_base)
> + /* %ecx has PDPT, get first PD */
> + movl (%ecx), %eax
> + andl $(PAGE_MASK), %eax
> + /* Get first PT from first PDE */
> + movl (%eax), %eax
> + andl $(PAGE_MASK), %eax
> + /* Get MLE base from first PTE */
> + movl (%eax), %eax
> + andl $(PAGE_MASK), %eax
> +
> + movl %eax, rva(sl_mle_start)(%ebx)
> + ret
> +SYM_FUNC_END(sl_find_mle_base)
> +
> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
> + /* %ecx: buffer begin %edx: buffer end */
> + /* %ebx: MLE begin %edi: MLE end */
> + /* %eax: region may be inside MLE */
> +
> + cmpl %edi, %ecx
> + jb .Lnext_check
> + cmpl %edi, %edx
> + jbe .Lnext_check
> + jmp .Lvalid /* Buffer above MLE */
> +
> +.Lnext_check:
> + cmpl %ebx, %edx
> + ja .Linside_check
> + cmpl %ebx, %ecx
> + jae .Linside_check
> + jmp .Lvalid /* Buffer below MLE */
> +
> +.Linside_check:
> + cmpl $0, %eax
> + jz .Linvalid
> + cmpl %ebx, %ecx
> + jb .Linvalid
> + cmpl %edi, %edx
> + ja .Linvalid
> + jmp .Lvalid /* Buffer in MLE */
> +
> +.Linvalid:
> + TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
> +
> +.Lvalid:
> + ret
> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
> +
> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
> + pushl %ebx
> + /*
> + * %eax points to the base of the OS-MLE struct. Need to also
> + * read some values from the OS-SINIT struct too.
> + */
> + movl -8(%eax), %ecx
> + /* Skip over OS to MLE data section and size of OS-SINIT structure */
> + leal (%eax, %ecx), %edx
> +
> + /* Load MLE image base absolute offset */
> + movl rva(sl_mle_start)(%ebx), %ebx
> +
> + /* Verify the value of the low PMR base. It should always be 0. */
> + movl SL_vtd_pmr_lo_base(%edx), %esi
> + cmpl $0, %esi
> + jz .Lvalid_pmr_base
> + TXT_RESET $(SL_ERROR_LO_PMR_BASE)
> +
> +.Lvalid_pmr_base:
> + /* Grab some values from OS-SINIT structure */
> + movl SL_mle_size(%edx), %edi
> + addl %ebx, %edi
> + jc .Loverflow_detected
> + movl SL_vtd_pmr_lo_size(%edx), %esi
> +
> + /* Check the AP wake block */
> + movl SL_ap_wake_block(%eax), %ecx
> + movl SL_ap_wake_block_size(%eax), %edx
> + addl %ecx, %edx
> + jc .Loverflow_detected
> + pushl %eax
> + xorl %eax, %eax
> + call sl_check_buffer_mle_overlap
> + popl %eax
> + cmpl %esi, %edx
> + ja .Lbuffer_beyond_pmr
> +
> + /*
> + * Check the boot params. Note during a UEFI boot, the boot
> + * params will be inside the MLE image. Test for this case
> + * in the overlap case.
> + */
> + movl SL_boot_params_addr(%eax), %ecx
> + movl $(PAGE_SIZE), %edx
> + addl %ecx, %edx
> + jc .Loverflow_detected
> + pushl %eax
> + movl $1, %eax
> + call sl_check_buffer_mle_overlap
> + popl %eax
> + cmpl %esi, %edx
> + ja .Lbuffer_beyond_pmr
> +
> + /* Check that the AP wake block is big enough */
> + cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
> + SL_ap_wake_block_size(%eax)
> + jae .Lwake_block_ok
> + TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
> +
> +.Lwake_block_ok:
> + popl %ebx
> + ret
> +
> +.Loverflow_detected:
> + TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
> +
> +.Lbuffer_beyond_pmr:
> + TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
> +
> +SYM_FUNC_START(sl_txt_ap_entry)
> + cli
> + cld
> + /*
> + * The %cs and %ds segments are known good after waking the AP.
> + * First order of business is to find where we are and
> + * save it in %ebx.
> + */
> +
> + /* Read physical base of heap into EAX */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
> + movl (%eax), %ecx
> + /* Skip over BIOS data and size of OS to MLE data section */
> + leal 8(%eax, %ecx), %eax
> +
> + /* Saved %ebx from the BSP and stash OS-MLE pointer */
> + movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
> +
> + /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
> + movl SL_txt_info(%eax), %edi
> +
> + /* Lock and get our stack index */
> + movl $1, %ecx
> +.Lspin:
> + xorl %eax, %eax
> + lock cmpxchgl %ecx, rva(sl_txt_spin_lock)(%ebx)
> + pause
> + jnz .Lspin
> +
> + /* Increment the stack index and use the next value inside lock */
> + incl rva(sl_txt_stack_index)(%ebx)
> + movl rva(sl_txt_stack_index)(%ebx), %eax
> +
> + /* Unlock */
> + movl $0, rva(sl_txt_spin_lock)(%ebx)
> +
> + /* Location of the relocated AP wake block */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
> +
> + /* Load reloc GDT, set segment regs and lret to __SL32_CS */
> + lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> + movl $(__SL32_DS), %edx
> + movw %dx, %ds
> + movw %dx, %es
> + movw %dx, %fs
> + movw %dx, %gs
> + movw %dx, %ss
> +
> + /* Load our reloc AP stack */
> + movl $(TXT_BOOT_STACK_SIZE), %edx
> + mull %edx
> + leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
> + subl %eax, %esp
> +
> + /* Switch to AP code segment */
> + leal rva(.Lsl_ap_cs)(%ebx), %eax
> + pushl $(__SL32_CS)
> + pushl %eax
> + lret
> +
> +.Lsl_ap_cs:
> + /* Load the relocated AP IDT */
> + lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
> +
> + /* Fixup MTRRs and misc enable MSR on APs too */
> + call sl_txt_load_regs
> +
> + /* Enable SMI with GETSEC[SMCTRL] */
> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
> +
> + /* IRET-to-self can be used to enable NMIs which SENTER disabled */
> + leal rva(.Lnmi_enabled_ap)(%ebx), %eax
> + pushfl
> + pushl $(__SL32_CS)
> + pushl %eax
> + iret
> +
> +.Lnmi_enabled_ap:
> + /* Put APs in X2APIC mode like the BSP */
> + movl $(MSR_IA32_APICBASE), %ecx
> + rdmsr
> + orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
> + wrmsr
> +
> + /*
> + * Basically done, increment the CPU count and jump off to the AP
> + * wake block to wait.
> + */
> + lock incl rva(sl_txt_cpu_count)(%ebx)
> +
> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
> + jmp *%eax
> +SYM_FUNC_END(sl_txt_ap_entry)
> +
> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
> + /* Save boot params register */
> + pushl %esi
> +
> + movl rva(sl_txt_ap_wake_block)(%ebx), %edi
> +
> + /* Fixup AP IDT and GDT descriptor before relocating */
> + leal rva(sl_ap_idt_desc)(%ebx), %eax
> + addl %edi, 2(%eax)
> + leal rva(sl_ap_gdt_desc)(%ebx), %eax
> + addl %edi, 2(%eax)
> +
> + /*
> + * Copy the AP wake code and AP GDT/IDT to the protected wake block
> + * provided by the loader. Destination already in %edi.
> + */
> + movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
> + leal rva(sl_txt_ap_wake_begin)(%ebx), %esi
> + rep movsb
> +
> + /* Setup the IDT for the APs to use in the relocation block */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
> + addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
> + xorl %edx, %edx
> +
> + /* Form the default reset vector relocation address */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %esi
> + addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
> +
> +1:
> + cmpw $(NR_VECTORS), %dx
> + jz .Lap_idt_done
> +
> + cmpw $(X86_TRAP_NMI), %dx
> + jz 2f
> +
> + /* Load all other fixed vectors with reset handler */
> + movl %esi, %eax
> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> + shrl $16, %eax
> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> + jmp 3f
> +
> +2:
> + /* Load single wake NMI IPI vector at the relocation address */
> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
> + addl $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
> + shrl $16, %eax
> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
> +
> +3:
> + incw %dx
> + addl $8, %ecx
> + jmp 1b
> +
> +.Lap_idt_done:
> + popl %esi
> + ret
> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
> +
> +SYM_FUNC_START(sl_txt_load_regs)
> + /* Save base pointer register */
> + pushl %ebx
> +
> + /*
> + * On Intel, the original variable MTRRs and Misc Enable MSR are
> + * restored on the BSP at early boot. Each AP will also restore
> + * its MTRRs and Misc Enable MSR.
> + */
> + pushl %edi
> + addl $(SL_saved_bsp_mtrrs), %edi
> + movl (%edi), %ebx
> + pushl %ebx /* default_mem_type lo */
> + addl $4, %edi
> + movl (%edi), %ebx
> + pushl %ebx /* default_mem_type hi */
> + addl $4, %edi
> + movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
> + addl $8, %edi /* now at MTRR pair array */
> + /* Write the variable MTRRs */
> + movl $(MSR_MTRRphysBase0), %ecx
> +1:
> + cmpl $0, %ebx
> + jz 2f
> +
> + movl (%edi), %eax /* MTRRphysBaseX lo */
> + addl $4, %edi
> + movl (%edi), %edx /* MTRRphysBaseX hi */
> + wrmsr
> + addl $4, %edi
> + incl %ecx
> + movl (%edi), %eax /* MTRRphysMaskX lo */
> + addl $4, %edi
> + movl (%edi), %edx /* MTRRphysMaskX hi */
> + wrmsr
> + addl $4, %edi
> + incl %ecx
> +
> + decl %ebx
> + jmp 1b
> +2:
> + /* Write the default MTRR register */
> + popl %edx
> + popl %eax
> + movl $(MSR_MTRRdefType), %ecx
> + wrmsr
> +
> + /* Return to beginning and write the misc enable msr */
> + popl %edi
> + addl $(SL_saved_misc_enable_msr), %edi
> + movl (%edi), %eax /* saved_misc_enable_msr lo */
> + addl $4, %edi
> + movl (%edi), %edx /* saved_misc_enable_msr hi */
> + movl $(MSR_IA32_MISC_ENABLE), %ecx
> + wrmsr
> +
> + popl %ebx
> + ret
> +SYM_FUNC_END(sl_txt_load_regs)
> +
> +SYM_FUNC_START(sl_txt_wake_aps)
> + /* Save boot params register */
> + pushl %esi
> +
> + /* First setup the MLE join structure and load it into TXT reg */
> + leal rva(sl_gdt)(%ebx), %eax
> + leal rva(sl_txt_ap_entry)(%ebx), %ecx
> + leal rva(sl_smx_rlp_mle_join)(%ebx), %edx
> + movl %eax, SL_rlp_gdt_base(%edx)
> + movl %ecx, SL_rlp_entry_point(%edx)
> + movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
> +
> + /* Another TXT heap walk to find various values needed to wake APs */
> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
> + /* At BIOS data size, find the number of logical processors */
> + movl (SL_num_logical_procs + 8)(%eax), %edx
> + /* Skip over BIOS data */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* Skip over OS to MLE */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* At OS-SNIT size, get capabilities to know how to wake up the APs */
> + movl (SL_capabilities + 8)(%eax), %esi
> + /* Skip over OS to SNIT */
> + movl (%eax), %ecx
> + addl %ecx, %eax
> + /* At SINIT-MLE size, get the AP wake MONITOR address */
> + movl (SL_rlp_wakeup_addr + 8)(%eax), %edi
> +
> + /* Determine how to wake up the APs */
> + testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
> + jz .Lwake_getsec
> +
> + /* Wake using MWAIT MONITOR */
> + movl $1, (%edi)
> + jmp .Laps_awake
> +
> +.Lwake_getsec:
> + /* Wake using GETSEC(WAKEUP) */
> + GETSEC $(SMX_X86_GETSEC_WAKEUP)
> +
> +.Laps_awake:
> + /*
> + * All of the APs are woken up and rendesvous in the relocated wake
> + * block starting at sl_txt_ap_wake_begin. Wait for all of them to
> + * halt.
> + */
> + pause
> + cmpl rva(sl_txt_cpu_count)(%ebx), %edx
> + jne .Laps_awake
> +
> + popl %esi
> + ret
> +SYM_FUNC_END(sl_txt_wake_aps)
> +
> +/* This is the beginning of the relocated AP wake code block */
> + .global sl_txt_ap_wake_begin
> +sl_txt_ap_wake_begin:
> +
> + /* Get the LAPIC ID for each AP and stash it on the stack */
> + movl $(MSR_IA32_X2APIC_APICID), %ecx
> + rdmsr
> + pushl %eax
> +
> + /*
> + * Get a pointer to the monitor location on this APs stack to test below
> + * after mwait returns. Currently %esp points to just past the pushed APIC
> + * ID value.
> + */
> + movl %esp, %eax
> + subl $(TXT_BOOT_STACK_SIZE - 4), %eax
> + movl $0, (%eax)
> +
> + /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
> + xorl %ecx, %ecx
> + xorl %edx, %edx
> +
> + /*
> + * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
> + * instruction can return for a number of reasons. Test to see if it returned
> + * because the monitor was written to.
> + */
> + monitor
> +
> +1:
> + mfence
> + mwait
> + movl (%eax), %edx
> + testl %edx, %edx
> + jz 1b
> +
> + /*
> + * This is the long absolute jump to the 32b Secure Launch protected mode stub
> + * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
> + * fixed in the SMP boot code when the first AP is brought up. This whole area
> + * is provided and protected in the memory map by the prelaunch code.
> + */
> + .byte 0xea
> +sl_ap_jmp_offset:
> + .long 0x00000000
> + .word __SL32_CS
> +
> +SYM_FUNC_START(sl_txt_int_nmi)
> + /* NMI context, just IRET */
> + iret
> +SYM_FUNC_END(sl_txt_int_nmi)
> +
> +SYM_FUNC_START(sl_txt_int_reset)
> + TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
> +SYM_FUNC_END(sl_txt_int_reset)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
> + .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */
> + .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */
> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_idt)
> + .rept NR_VECTORS
> + .word 0x0000 /* Offset 15 to 0 */
> + .word __SL32_CS /* Segment selector */
> + .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */
> + .word 0x0000 /* Offset 31 to 16 */
> + .endr
> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
> + .word sl_ap_gdt_end - sl_ap_gdt - 1
> + .long sl_ap_gdt - sl_txt_ap_wake_begin
> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_ap_gdt)
> + .quad 0x0000000000000000 /* NULL */
> + .quad 0x00cf9a000000ffff /* __SL32_CS */
> + .quad 0x00cf92000000ffff /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
> +
> + /* Small stacks for BSP and APs to work with */
> + .balign 64
> +SYM_DATA_START_LOCAL(sl_stacks)
> + .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
> +
> +/* This is the end of the relocated AP wake code block */
> + .global sl_txt_ap_wake_end
> +sl_txt_ap_wake_end:
> +
> + .data
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt_desc)
> + .word sl_gdt_end - sl_gdt - 1
> + .long sl_gdt - sl_gdt_desc
> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_gdt)
> + .quad 0x0000000000000000 /* NULL */
> + .quad 0x00cf9a000000ffff /* __SL32_CS */
> + .quad 0x00cf92000000ffff /* __SL32_DS */
> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
> +
> + .balign 8
> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
> + .long sl_gdt_end - sl_gdt - 1 /* GDT limit */
> + .long 0x00000000 /* GDT base */
> + .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
> + .long 0x00000000 /* Entry point physical address */
> +SYM_DATA_END(sl_smx_rlp_mle_join)
> +
> +SYM_DATA(sl_cpu_type, .long 0x00000000)
> +
> +SYM_DATA(sl_mle_start, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
> +
> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
> index e022e6eb766c..37f6167f28ba 100644
> --- a/arch/x86/include/asm/msr-index.h
> +++ b/arch/x86/include/asm/msr-index.h
> @@ -348,6 +348,9 @@
> #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
> #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561
>
> +#define MSR_MTRRphysBase0 0x00000200
> +#define MSR_MTRRphysMask0 0x00000201
> +
> #define MSR_MTRRfix64K_00000 0x00000250
> #define MSR_MTRRfix16K_80000 0x00000258
> #define MSR_MTRRfix16K_A0000 0x00000259
> @@ -849,6 +852,8 @@
> #define MSR_IA32_APICBASE_ENABLE (1<<11)
> #define MSR_IA32_APICBASE_BASE (0xfffff<<12)
>
> +#define MSR_IA32_X2APIC_APICID 0x00000802
> +
> #define MSR_IA32_UCODE_WRITE 0x00000079
> #define MSR_IA32_UCODE_REV 0x0000008b
>
MSR updates are better to be split to their own patch.
> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
> index 9b82eebd7add..7ce283a22d6b 100644
> --- a/arch/x86/include/uapi/asm/bootparam.h
> +++ b/arch/x86/include/uapi/asm/bootparam.h
> @@ -12,6 +12,7 @@
> /* loadflags */
> #define LOADED_HIGH (1<<0)
> #define KASLR_FLAG (1<<1)
> +#define SLAUNCH_FLAG (1<<2)
> #define QUIET_FLAG (1<<5)
> #define KEEP_SEGMENTS (1<<6)
> #define CAN_USE_HEAP (1<<7)
> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
> index a98020bf31bb..925adce6e2c7 100644
> --- a/arch/x86/kernel/asm-offsets.c
> +++ b/arch/x86/kernel/asm-offsets.c
> @@ -13,6 +13,8 @@
> #include <linux/hardirq.h>
> #include <linux/suspend.h>
> #include <linux/kbuild.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
> #include <asm/processor.h>
> #include <asm/thread_info.h>
> #include <asm/sigframe.h>
> @@ -120,4 +122,22 @@ static void __used common(void)
> OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
> #endif
>
> +#ifdef CONFIG_SECURE_LAUNCH
> + BLANK();
> + OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
> + OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
> + OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
> + OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
> + OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
> + OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
> + OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
> + OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
> + OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
> + OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
> + OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
> + OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
> + OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
> + OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
> + OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
> +#endif
> }
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 19:56 ` Jarkko Sakkinen
@ 2024-06-04 21:09 ` ross.philipson
2024-06-04 22:43 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:09 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 12:56 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> The Secure Launch (SL) stub provides the entry point for Intel TXT (and
>> later AMD SKINIT) to vector to during the late launch. The symbol
>> sl_stub_entry is that entry point and its offset into the kernel is
>> conveyed to the launching code using the MLE (Measured Launch
>> Environment) header in the structure named mle_header. The offset of the
>> MLE header is set in the kernel_info. The routine sl_stub contains the
>> very early late launch setup code responsible for setting up the basic
>> environment to allow the normal kernel startup_32 code to proceed. It is
>> also responsible for properly waking and handling the APs on Intel
>> platforms. The routine sl_main which runs after entering 64b mode is
>> responsible for measuring configuration and module information before
>> it is used like the boot params, the kernel command line, the TXT heap,
>> an external initramfs, etc.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> Documentation/arch/x86/boot.rst | 21 +
>> arch/x86/boot/compressed/Makefile | 3 +-
>> arch/x86/boot/compressed/head_64.S | 30 +
>> arch/x86/boot/compressed/kernel_info.S | 34 ++
>> arch/x86/boot/compressed/sl_main.c | 577 ++++++++++++++++++++
>> arch/x86/boot/compressed/sl_stub.S | 725 +++++++++++++++++++++++++
>> arch/x86/include/asm/msr-index.h | 5 +
>> arch/x86/include/uapi/asm/bootparam.h | 1 +
>> arch/x86/kernel/asm-offsets.c | 20 +
>> 9 files changed, 1415 insertions(+), 1 deletion(-)
>> create mode 100644 arch/x86/boot/compressed/sl_main.c
>> create mode 100644 arch/x86/boot/compressed/sl_stub.S
>>
>> diff --git a/Documentation/arch/x86/boot.rst b/Documentation/arch/x86/boot.rst
>> index 4fd492cb4970..295cdf9bcbdb 100644
>> --- a/Documentation/arch/x86/boot.rst
>> +++ b/Documentation/arch/x86/boot.rst
>> @@ -482,6 +482,14 @@ Protocol: 2.00+
>> - If 1, KASLR enabled.
>> - If 0, KASLR disabled.
>>
>> + Bit 2 (kernel internal): SLAUNCH_FLAG
>> +
>> + - Used internally by the setup kernel to communicate
>> + Secure Launch status to kernel proper.
>> +
>> + - If 1, Secure Launch enabled.
>> + - If 0, Secure Launch disabled.
>> +
>> Bit 5 (write): QUIET_FLAG
>>
>> - If 0, print early messages.
>> @@ -1028,6 +1036,19 @@ Offset/size: 0x000c/4
>>
>> This field contains maximal allowed type for setup_data and setup_indirect structs.
>>
>> +============ =================
>> +Field name: mle_header_offset
>> +Offset/size: 0x0010/4
>> +============ =================
>> +
>> + This field contains the offset to the Secure Launch Measured Launch Environment
>> + (MLE) header. This offset is used to locate information needed during a secure
>> + late launch using Intel TXT. If the offset is zero, the kernel does not have
>> + Secure Launch capabilities. The MLE entry point is called from TXT on the BSP
>> + following a success measured launch. The specific state of the processors is
>> + outlined in the TXT Software Development Guide, the latest can be found here:
>> + https://urldefense.com/v3/__https://www.intel.com/content/dam/www/public/us/en/documents/guides/intel-txt-software-development-guide.pdf__;!!ACWV5N9M2RV99hQ!KPXGsFBxHXv1-jmHhyS3xHCC_3EnOUbN697TXyjlZlNw9YPQG9tQKo2s-6cn-HEv3gP_PpQqGwTYYQT3jxE$
>> +
>>
>> The Image Checksum
>> ==================
>> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
>> index 9189a0e28686..9076a248d4b4 100644
>> --- a/arch/x86/boot/compressed/Makefile
>> +++ b/arch/x86/boot/compressed/Makefile
>> @@ -118,7 +118,8 @@ vmlinux-objs-$(CONFIG_EFI) += $(obj)/efi.o
>> vmlinux-objs-$(CONFIG_EFI_MIXED) += $(obj)/efi_mixed.o
>> vmlinux-objs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
>>
>> -vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o
>> +vmlinux-objs-$(CONFIG_SECURE_LAUNCH) += $(obj)/early_sha1.o $(obj)/early_sha256.o \
>> + $(obj)/sl_main.o $(obj)/sl_stub.o
>>
>> $(obj)/vmlinux: $(vmlinux-objs-y) FORCE
>> $(call if_changed,ld)
>> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
>> index 1dcb794c5479..803c9e2e6d85 100644
>> --- a/arch/x86/boot/compressed/head_64.S
>> +++ b/arch/x86/boot/compressed/head_64.S
>> @@ -420,6 +420,13 @@ SYM_CODE_START(startup_64)
>> pushq $0
>> popfq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + /* Ensure the relocation region is coverd by a PMR */
>> + movq %rbx, %rdi
>> + movl $(_bss - startup_32), %esi
>> + callq sl_check_region
>> +#endif
>> +
>> /*
>> * Copy the compressed kernel to the end of our buffer
>> * where decompression in place becomes safe.
>> @@ -462,6 +469,29 @@ SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
>> shrq $3, %rcx
>> rep stosq
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + /*
>> + * Have to do the final early sl stub work in 64b area.
>> + *
>> + * *********** NOTE ***********
>> + *
>> + * Several boot params get used before we get a chance to measure
>> + * them in this call. This is a known issue and we currently don't
>> + * have a solution. The scratch field doesn't matter. There is no
>> + * obvious way to do anything about the use of kernel_alignment or
>> + * init_size though these seem low risk with all the PMR and overlap
>> + * checks in place.
>> + */
>> + movq %r15, %rdi
>> + callq sl_main
>> +
>> + /* Ensure the decompression location is covered by a PMR */
>> + movq %rbp, %rdi
>> + movq output_len(%rip), %rsi
>> + callq sl_check_region
>> +#endif
>> +
>> + pushq %rsi
>> call load_stage2_idt
>>
>> /* Pass boot_params to initialize_identity_maps() */
>> diff --git a/arch/x86/boot/compressed/kernel_info.S b/arch/x86/boot/compressed/kernel_info.S
>> index c18f07181dd5..e199b87764e9 100644
>> --- a/arch/x86/boot/compressed/kernel_info.S
>> +++ b/arch/x86/boot/compressed/kernel_info.S
>> @@ -28,6 +28,40 @@ SYM_DATA_START(kernel_info)
>> /* Maximal allowed type for setup_data and setup_indirect structs. */
>> .long SETUP_TYPE_MAX
>>
>> + /* Offset to the MLE header structure */
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> + .long rva(mle_header)
>> +#else
>> + .long 0
>> +#endif
>> +
>> kernel_info_var_len_data:
>> /* Empty for time being... */
>> SYM_DATA_END_LABEL(kernel_info, SYM_L_LOCAL, kernel_info_end)
>> +
>> +#if IS_ENABLED(CONFIG_SECURE_LAUNCH)
>> + /*
>> + * The MLE Header per the TXT Specification, section 2.1
>> + * MLE capabilities, see table 4. Capabilities set:
>> + * bit 0: Support for GETSEC[WAKEUP] for RLP wakeup
>> + * bit 1: Support for RLP wakeup using MONITOR address
>> + * bit 2: The ECX register will contain the pointer to the MLE page table
>> + * bit 5: TPM 1.2 family: Details/authorities PCR usage support
>> + * bit 9: Supported format of TPM 2.0 event log - TCG compliant
>> + */
>> +SYM_DATA_START(mle_header)
>> + .long 0x9082ac5a /* UUID0 */
>> + .long 0x74a7476f /* UUID1 */
>> + .long 0xa2555c0f /* UUID2 */
>> + .long 0x42b651cb /* UUID3 */
>> + .long 0x00000034 /* MLE header size */
>> + .long 0x00020002 /* MLE version 2.2 */
>> + .long rva(sl_stub_entry) /* Linear entry point of MLE (virt. address) */
>> + .long 0x00000000 /* First valid page of MLE */
>> + .long 0x00000000 /* Offset within binary of first byte of MLE */
>> + .long rva(_edata) /* Offset within binary of last byte + 1 of MLE */
>> + .long 0x00000227 /* Bit vector of MLE-supported capabilities */
>> + .long 0x00000000 /* Starting linear address of command line (unused) */
>> + .long 0x00000000 /* Ending linear address of command line (unused) */
>> +SYM_DATA_END(mle_header)
>> +#endif
>> diff --git a/arch/x86/boot/compressed/sl_main.c b/arch/x86/boot/compressed/sl_main.c
>> new file mode 100644
>> index 000000000000..61e9baf410fd
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_main.c
>> @@ -0,0 +1,577 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Secure Launch early measurement and validation routines.
>> + *
>> + * Copyright (c) 2024, Oracle and/or its affiliates.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/string.h>
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/boot.h>
>> +#include <asm/msr.h>
>> +#include <asm/mtrr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/bootparam_utils.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +#include <crypto/sha1.h>
>> +#include <crypto/sha2.h>
>> +
>> +#define CAPS_VARIABLE_MTRR_COUNT_MASK 0xff
>> +
>> +#define SL_TPM12_LOG 1
>> +#define SL_TPM20_LOG 2
>> +
>> +#define SL_TPM20_MAX_ALGS 2
>> +
>> +#define SL_MAX_EVENT_DATA 64
>> +#define SL_TPM12_LOG_SIZE (sizeof(struct tcg_pcr_event) + \
>> + SL_MAX_EVENT_DATA)
>> +#define SL_TPM20_LOG_SIZE (sizeof(struct tcg_pcr_event2_head) + \
>> + SHA1_DIGEST_SIZE + SHA256_DIGEST_SIZE + \
>> + sizeof(struct tcg_event_field) + \
>> + SL_MAX_EVENT_DATA)
>> +
>> +static void *evtlog_base;
>> +static u32 evtlog_size;
>> +static struct txt_heap_event_log_pointer2_1_element *log20_elem;
>> +static u32 tpm_log_ver = SL_TPM12_LOG;
>> +static struct tcg_efi_specid_event_algs tpm_algs[SL_TPM20_MAX_ALGS] = {0};
>> +
>> +extern u32 sl_cpu_type;
>> +extern u32 sl_mle_start;
>> +
>> +static u64 sl_txt_read(u32 reg)
>> +{
>> + return readq((void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void sl_txt_write(u32 reg, u64 val)
>> +{
>> + writeq(val, (void *)(u64)(TXT_PRIV_CONFIG_REGS_BASE + reg));
>> +}
>> +
>> +static void __noreturn sl_txt_reset(u64 error)
>> +{
>> + /* Reading the E2STS register acts as a barrier for TXT registers */
>> + sl_txt_write(TXT_CR_ERRORCODE, error);
>> + sl_txt_read(TXT_CR_E2STS);
>> + sl_txt_write(TXT_CR_CMD_UNLOCK_MEM_CONFIG, 1);
>> + sl_txt_read(TXT_CR_E2STS);
>> + sl_txt_write(TXT_CR_CMD_RESET, 1);
>> +
>> + for ( ; ; )
>> + asm volatile ("hlt");
>> +
>> + unreachable();
>> +}
>> +
>> +static u64 sl_rdmsr(u32 reg)
>> +{
>> + u64 lo, hi;
>> +
>> + asm volatile ("rdmsr" : "=a" (lo), "=d" (hi) : "c" (reg));
>> +
>> + return (hi << 32) | lo;
>> +}
>> +
>> +static struct slr_table *sl_locate_and_validate_slrt(void)
>> +{
>> + struct txt_os_mle_data *os_mle_data;
>> + struct slr_table *slrt;
>> + void *txt_heap;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + if (!os_mle_data->slrt)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + slrt = (struct slr_table *)os_mle_data->slrt;
>> +
>> + if (slrt->magic != SLR_TABLE_MAGIC)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + if (slrt->architecture != SLR_INTEL_TXT)
>> + sl_txt_reset(SL_ERROR_INVALID_SLRT);
>> +
>> + return slrt;
>> +}
>> +
>> +static void sl_check_pmr_coverage(void *base, u32 size, bool allow_hi)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + void *end = base + size;
>> + void *txt_heap;
>> +
>> + if (!(sl_cpu_type & SL_CPU_INTEL))
>> + return;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + if ((end >= (void *)0x100000000ULL) && (base < (void *)0x100000000ULL))
>> + sl_txt_reset(SL_ERROR_REGION_STRADDLE_4GB);
>> +
>> + /*
>> + * Note that the late stub code validates that the hi PMR covers
>> + * all memory above 4G. At this point the code can only check that
>> + * regions are within the hi PMR but that is sufficient.
>> + */
>> + if ((end > (void *)0x100000000ULL) && (base >= (void *)0x100000000ULL)) {
>> + if (allow_hi) {
>> + if (end >= (void *)(os_sinit_data->vtd_pmr_hi_base +
>> + os_sinit_data->vtd_pmr_hi_size))
>> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> + } else {
>> + sl_txt_reset(SL_ERROR_REGION_ABOVE_4GB);
>> + }
>> + }
>> +
>> + if (end >= (void *)os_sinit_data->vtd_pmr_lo_size)
>> + sl_txt_reset(SL_ERROR_BUFFER_BEYOND_PMR);
>> +}
>> +
>> +/*
>> + * Some MSRs are modified by the pre-launch code including the MTRRs.
>> + * The early MLE code has to restore these values. This code validates
>> + * the values after they are measured.
>> + */
>> +static void sl_txt_validate_msrs(struct txt_os_mle_data *os_mle_data)
>> +{
>> + struct slr_txt_mtrr_state *saved_bsp_mtrrs;
>> + u64 mtrr_caps, mtrr_def_type, mtrr_var;
>> + struct slr_entry_intel_info *txt_info;
>> + u64 misc_en_msr;
>> + u32 vcnt, i;
>> +
>> + txt_info = (struct slr_entry_intel_info *)os_mle_data->txt_info;
>> + saved_bsp_mtrrs = &txt_info->saved_bsp_mtrrs;
>> +
>> + mtrr_caps = sl_rdmsr(MSR_MTRRcap);
>> + vcnt = (u32)(mtrr_caps & CAPS_VARIABLE_MTRR_COUNT_MASK);
>> +
>> + if (saved_bsp_mtrrs->mtrr_vcnt > vcnt)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> + if (saved_bsp_mtrrs->mtrr_vcnt > TXT_OS_MLE_MAX_VARIABLE_MTRRS)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_VCNT);
>> +
>> + mtrr_def_type = sl_rdmsr(MSR_MTRRdefType);
>> + if (saved_bsp_mtrrs->default_mem_type != mtrr_def_type)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_DEF_TYPE);
>> +
>> + for (i = 0; i < saved_bsp_mtrrs->mtrr_vcnt; i++) {
>> + mtrr_var = sl_rdmsr(MTRRphysBase_MSR(i));
>> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physbase != mtrr_var)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_BASE);
>> + mtrr_var = sl_rdmsr(MTRRphysMask_MSR(i));
>> + if (saved_bsp_mtrrs->mtrr_pair[i].mtrr_physmask != mtrr_var)
>> + sl_txt_reset(SL_ERROR_MTRR_INV_MASK);
>> + }
>> +
>> + misc_en_msr = sl_rdmsr(MSR_IA32_MISC_ENABLE);
>> + if (txt_info->saved_misc_enable_msr != misc_en_msr)
>> + sl_txt_reset(SL_ERROR_MSR_INV_MISC_EN);
>> +}
>> +
>> +static void sl_find_drtm_event_log(struct slr_table *slrt)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + struct slr_entry_log_info *log_info;
>> + void *txt_heap;
>> +
>> + log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
>> + if (!log_info)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + evtlog_base = (void *)log_info->addr;
>> + evtlog_size = log_info->size;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> +
>> + /*
>> + * For TPM 2.0, the event log 2.1 extended data structure has to also
>> + * be located and fixed up.
>> + */
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + /*
>> + * Only support version 6 and later that properly handle the
>> + * list of ExtDataElements in the OS-SINIT structure.
>> + */
>> + if (os_sinit_data->version < 6)
>> + sl_txt_reset(SL_ERROR_OS_SINIT_BAD_VERSION);
>> +
>> + /* Find the TPM2.0 logging extended heap element */
>> + log20_elem = tpm20_find_log2_1_element(os_sinit_data);
>
> s/tpm20/tpm2/
Reasonable. We can change it.
>
>> +
>> + /* If found, this implies TPM20 log and family */
>> + if (log20_elem)
>> + tpm_log_ver = SL_TPM20_LOG;
>> +}
>> +
>> +static void sl_validate_event_log_buffer(void)
>> +{
>> + struct txt_os_sinit_data *os_sinit_data;
>> + void *txt_heap, *txt_end;
>> + void *mle_base, *mle_end;
>> + void *evtlog_end;
>> +
>> + if ((u64)evtlog_size > (LLONG_MAX - (u64)evtlog_base))
>> + sl_txt_reset(SL_ERROR_INTEGER_OVERFLOW);
>> + evtlog_end = evtlog_base + evtlog_size;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + txt_end = txt_heap + sl_txt_read(TXT_CR_HEAP_SIZE);
>> + os_sinit_data = txt_os_sinit_data_start(txt_heap);
>> +
>> + mle_base = (void *)(u64)sl_mle_start;
>> + mle_end = mle_base + os_sinit_data->mle_size;
>> +
>> + /*
>> + * This check is to ensure the event log buffer does not overlap with
>> + * the MLE image.
>> + */
>> + if (evtlog_base >= mle_end && evtlog_end > mle_end)
>> + goto pmr_check; /* above */
>> +
>> + if (evtlog_end <= mle_base && evtlog_base < mle_base)
>> + goto pmr_check; /* below */
>> +
>> + sl_txt_reset(SL_ERROR_MLE_BUFFER_OVERLAP);
>> +
>> +pmr_check:
>> + /*
>> + * The TXT heap is protected by the DPR. If the TPM event log is
>> + * inside the TXT heap, there is no need for a PMR check.
>> + */
>> + if (evtlog_base > txt_heap && evtlog_end < txt_end)
>> + return;
>> +
>> + sl_check_pmr_coverage(evtlog_base, evtlog_size, true);
>> +}
>> +
>> +static void sl_find_event_log_algorithms(void)
>> +{
>> + struct tcg_efi_specid_event_head *efi_head =
>> + (struct tcg_efi_specid_event_head *)(evtlog_base +
>> + log20_elem->first_record_offset +
>> + sizeof(struct tcg_pcr_event));
>> +
>> + if (efi_head->num_algs == 0 || efi_head->num_algs > 2)
>> + sl_txt_reset(SL_ERROR_TPM_NUMBER_ALGS);
>> +
>> + memcpy(&tpm_algs[0], &efi_head->digest_sizes[0],
>> + sizeof(struct tcg_efi_specid_event_algs) * efi_head->num_algs);
>> +}
>> +
>> +static void sl_tpm12_log_event(u32 pcr, u32 event_type,
>> + const u8 *data, u32 length,
>> + const u8 *event_data, u32 event_size)
>> +{
>> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> + u8 log_buf[SL_TPM12_LOG_SIZE] = {0};
>> + struct tcg_pcr_event *pcr_event;
>> + u32 total_size;
>> +
>> + pcr_event = (struct tcg_pcr_event *)log_buf;
>> + pcr_event->pcr_idx = pcr;
>> + pcr_event->event_type = event_type;
>> + if (length > 0) {
>> + sha1(data, length, &sha1_hash[0]);
>> + memcpy(&pcr_event->digest[0], &sha1_hash[0], SHA1_DIGEST_SIZE);
>> + }
>> + pcr_event->event_size = event_size;
>> + if (event_size > 0)
>> + memcpy((u8 *)pcr_event + sizeof(struct tcg_pcr_event),
>> + event_data, event_size);
>> +
>> + total_size = sizeof(struct tcg_pcr_event) + event_size;
>> +
>> + if (tpm12_log_event(evtlog_base, evtlog_size, total_size, pcr_event))
>> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm20_log_event(u32 pcr, u32 event_type,
>> + const u8 *data, u32 length,
>> + const u8 *event_data, u32 event_size)
>> +{
>> + u8 sha256_hash[SHA256_DIGEST_SIZE] = {0};
>> + u8 sha1_hash[SHA1_DIGEST_SIZE] = {0};
>> + u8 log_buf[SL_TPM20_LOG_SIZE] = {0};
>> + struct sha256_state sctx256 = {0};
>> + struct tcg_pcr_event2_head *head;
>> + struct tcg_event_field *event;
>> + u32 total_size;
>> + u16 *alg_ptr;
>> + u8 *dgst_ptr;
>> +
>> + head = (struct tcg_pcr_event2_head *)log_buf;
>> + head->pcr_idx = pcr;
>> + head->event_type = event_type;
>> + total_size = sizeof(struct tcg_pcr_event2_head);
>> + alg_ptr = (u16 *)(log_buf + sizeof(struct tcg_pcr_event2_head));
>> +
>> + for ( ; head->count < 2; head->count++) {
>> + if (!tpm_algs[head->count].alg_id)
>> + break;
>> +
>> + *alg_ptr = tpm_algs[head->count].alg_id;
>> + dgst_ptr = (u8 *)alg_ptr + sizeof(u16);
>> +
>> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256 &&
>> + length) {
>> + sha256_init(&sctx256);
>> + sha256_update(&sctx256, data, length);
>> + sha256_final(&sctx256, &sha256_hash[0]);
>> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1 &&
>> + length) {
>> + sha1(data, length, &sha1_hash[0]);
>> + }
>> +
>> + if (tpm_algs[head->count].alg_id == TPM_ALG_SHA256) {
>> + memcpy(dgst_ptr, &sha256_hash[0], SHA256_DIGEST_SIZE);
>> + total_size += SHA256_DIGEST_SIZE + sizeof(u16);
>> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA256_DIGEST_SIZE + sizeof(u16));
>> + } else if (tpm_algs[head->count].alg_id == TPM_ALG_SHA1) {
>> + memcpy(dgst_ptr, &sha1_hash[0], SHA1_DIGEST_SIZE);
>> + total_size += SHA1_DIGEST_SIZE + sizeof(u16);
>> + alg_ptr = (u16 *)((u8 *)alg_ptr + SHA1_DIGEST_SIZE + sizeof(u16));
>> + } else {
>> + sl_txt_reset(SL_ERROR_TPM_UNKNOWN_DIGEST);
>> + }
>> + }
>> +
>> + event = (struct tcg_event_field *)(log_buf + total_size);
>> + event->event_size = event_size;
>> + if (event_size > 0)
>> + memcpy((u8 *)event + sizeof(struct tcg_event_field), event_data, event_size);
>> + total_size += sizeof(struct tcg_event_field) + event_size;
>> +
>> + if (tpm20_log_event(log20_elem, evtlog_base, evtlog_size, total_size, &log_buf[0]))
>> + sl_txt_reset(SL_ERROR_TPM_LOGGING_FAILED);
>> +}
>> +
>> +static void sl_tpm_extend_evtlog(u32 pcr, u32 type,
>> + const u8 *data, u32 length, const char *desc)
>> +{
>> + if (tpm_log_ver == SL_TPM20_LOG)
>> + sl_tpm20_log_event(pcr, type, data, length,
>> + (const u8 *)desc, strlen(desc));
>> + else
>> + sl_tpm12_log_event(pcr, type, data, length,
>> + (const u8 *)desc, strlen(desc));
>> +}
>> +
>> +static struct setup_data *sl_handle_setup_data(struct setup_data *curr,
>> + struct slr_policy_entry *entry)
>> +{
>> + struct setup_indirect *ind;
>> + struct setup_data *next;
>> +
>> + if (!curr)
>> + return NULL;
>> +
>> + next = (struct setup_data *)(unsigned long)curr->next;
>> +
>> + /* SETUP_INDIRECT instances have to be handled differently */
>> + if (curr->type == SETUP_INDIRECT) {
>> + ind = (struct setup_indirect *)((u8 *)curr + offsetof(struct setup_data, data));
>> +
>> + sl_check_pmr_coverage((void *)ind->addr, ind->len, true);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)ind->addr, ind->len,
>> + entry->evt_info);
>> +
>> + return next;
>> + }
>> +
>> + sl_check_pmr_coverage(((u8 *)curr) + sizeof(struct setup_data),
>> + curr->len, true);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + ((u8 *)curr) + sizeof(struct setup_data),
>> + curr->len,
>> + entry->evt_info);
>> +
>> + return next;
>> +}
>> +
>> +static void sl_extend_setup_data(struct slr_policy_entry *entry)
>> +{
>> + struct setup_data *data;
>> +
>> + /*
>> + * Measuring the boot params measured the fixed e820 memory map.
>> + * Measure any setup_data entries including e820 extended entries.
>> + */
>> + data = (struct setup_data *)(unsigned long)entry->entity;
>> + while (data)
>> + data = sl_handle_setup_data(data, entry);
>> +}
>> +
>> +static void sl_extend_slrt(struct slr_policy_entry *entry)
>> +{
>> + struct slr_table *slrt = (struct slr_table *)entry->entity;
>> + struct slr_entry_intel_info *intel_info;
>> +
>> + /*
>> + * In revision one of the SLRT, the only table that needs to be
>> + * measured is the Intel info table. Everything else is meta-data,
>> + * addresses and sizes. Note the size of what to measure is not set.
>> + * The flag SLR_POLICY_IMPLICIT_SIZE leaves it to the measuring code
>> + * to sort out.
>> + */
>> + if (slrt->revision == 1) {
>> + intel_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
>> + if (!intel_info)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + sl_tpm_extend_evtlog(entry->pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)entry->entity, sizeof(struct slr_entry_intel_info),
>> + entry->evt_info);
>> + }
>> +}
>> +
>> +static void sl_extend_txt_os2mle(struct slr_policy_entry *entry)
>> +{
>> + struct txt_os_mle_data *os_mle_data;
>> + void *txt_heap;
>> +
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + /*
>> + * Version 1 of the OS-MLE heap structure has no fields to measure. It just
>> + * has addresses and sizes and a scratch buffer.
>> + */
>> + if (os_mle_data->version == 1)
>> + return;
>> +}
>> +
>> +static void sl_process_extend_policy(struct slr_table *slrt)
>> +{
>> + struct slr_entry_policy *policy;
>> + u16 i;
>> +
>> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
>> + if (!policy)
>> + sl_txt_reset(SL_ERROR_SLRT_MISSING_ENTRY);
>> +
>> + for (i = 0; i < policy->nr_entries; i++) {
>> + switch (policy->policy_entries[i].entity_type) {
>> + case SLR_ET_SETUP_DATA:
>> + sl_extend_setup_data(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_SLRT:
>> + sl_extend_slrt(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_TXT_OS2MLE:
>> + sl_extend_txt_os2mle(&policy->policy_entries[i]);
>> + break;
>> + case SLR_ET_UNUSED:
>> + continue;
>> + default:
>> + sl_tpm_extend_evtlog(policy->policy_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)policy->policy_entries[i].entity,
>> + policy->policy_entries[i].size,
>> + policy->policy_entries[i].evt_info);
>> + }
>> + }
>> +}
>> +
>> +static void sl_process_extend_uefi_config(struct slr_table *slrt)
>> +{
>> + struct slr_entry_uefi_config *uefi_config;
>> + u16 i;
>> +
>> + uefi_config = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_UEFI_CONFIG);
>> +
>> + /* Optionally here depending on how SL kernel was booted */
>> + if (!uefi_config)
>> + return;
>> +
>> + for (i = 0; i < uefi_config->nr_entries; i++) {
>> + sl_tpm_extend_evtlog(uefi_config->uefi_cfg_entries[i].pcr, TXT_EVTYPE_SLAUNCH,
>> + (void *)uefi_config->uefi_cfg_entries[i].cfg,
>> + uefi_config->uefi_cfg_entries[i].size,
>> + uefi_config->uefi_cfg_entries[i].evt_info);
>> + }
>> +}
>> +
>> +asmlinkage __visible void sl_check_region(void *base, u32 size)
>> +{
>> + sl_check_pmr_coverage(base, size, false);
>> +}
>> +
>> +asmlinkage __visible void sl_main(void *bootparams)
>> +{
>> + struct boot_params *bp = (struct boot_params *)bootparams;
>> + struct txt_os_mle_data *os_mle_data;
>> + struct slr_table *slrt;
>> + void *txt_heap;
>> +
>> + /*
>> + * Ensure loadflags do not indicate a secure launch was done
>> + * unless it really was.
>> + */
>> + bp->hdr.loadflags &= ~SLAUNCH_FLAG;
>> +
>> + /*
>> + * Currently only Intel TXT is supported for Secure Launch. Testing
>> + * this value also indicates that the kernel was booted successfully
>> + * through the Secure Launch entry point and is in SMX mode.
>> + */
>> + if (!(sl_cpu_type & SL_CPU_INTEL))
>> + return;
>> +
>> + slrt = sl_locate_and_validate_slrt();
>> +
>> + /* Locate the TPM event log. */
>> + sl_find_drtm_event_log(slrt);
>> +
>> + /* Validate the location of the event log buffer before using it */
>> + sl_validate_event_log_buffer();
>> +
>> + /*
>> + * Find the TPM hash algorithms used by the ACM and recorded in the
>> + * event log.
>> + */
>> + if (tpm_log_ver == SL_TPM20_LOG)
>> + sl_find_event_log_algorithms();
>> +
>> + /*
>> + * Sanitize them before measuring. Set the SLAUNCH_FLAG early since if
>> + * anything fails, the system will reset anyway.
>> + */
>> + sanitize_boot_params(bp);
>> + bp->hdr.loadflags |= SLAUNCH_FLAG;
>> +
>> + sl_check_pmr_coverage(bootparams, PAGE_SIZE, false);
>> +
>> + /* Place event log SL specific tags before and after measurements */
>> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_START, NULL, 0, "");
>> +
>> + /* Process all policy entries and extend the measurements to the evtlog */
>
> These comments obfuscate code here but would make a lot more sense
> in the beginning of each corresponding function.
>
> /*
> * Process all policy entries and extend the measurements to the evtlog
> */
> static void sl_process_extend_policy(struct slr_table *slrt)
> {
> /* ... */
> }
Sure that sounds like a good idea.
>
> BTW what good that "process" does here? Why not just sl_extend_policy()?
Because the entities in the SLR table have to be processed then
extended. They are not just fed into the extend routine as they are when
fetched from the SLR table.
>
>
>> + sl_process_extend_policy(slrt);
>> +
>> + /* Process all EFI config entries and extend the measurements to the evtlog */
>> + sl_process_extend_uefi_config(slrt);
>
> Ditto.
>
>> +
>> + sl_tpm_extend_evtlog(17, TXT_EVTYPE_SLAUNCH_END, NULL, 0, "");
>> +
>> + /* No PMR check is needed, the TXT heap is covered by the DPR */
>> + txt_heap = (void *)sl_txt_read(TXT_CR_HEAP_BASE);
>> + os_mle_data = txt_os_mle_data_start(txt_heap);
>> +
>> + /*
>> + * Now that the OS-MLE data is measured, ensure the MTRR and
>> + * misc enable MSRs are what we expect.
>> + */
>> + sl_txt_validate_msrs(os_mle_data);
>> +}
>> diff --git a/arch/x86/boot/compressed/sl_stub.S b/arch/x86/boot/compressed/sl_stub.S
>> new file mode 100644
>> index 000000000000..24b8f23d5dcc
>> --- /dev/null
>> +++ b/arch/x86/boot/compressed/sl_stub.S
>> @@ -0,0 +1,725 @@
>> +/* SPDX-License-Identifier: GPL-2.0 */
>> +
>> +/*
>> + * Secure Launch protected mode entry point.
>> + *
>> + * Copyright (c) 2024, Oracle and/or its affiliates.
>> + */
>> + .code32
>> + .text
>> +#include <linux/linkage.h>
>> +#include <asm/segment.h>
>> +#include <asm/msr.h>
>> +#include <asm/apicdef.h>
>> +#include <asm/trapnr.h>
>> +#include <asm/processor-flags.h>
>> +#include <asm/asm-offsets.h>
>> +#include <asm/bootparam.h>
>> +#include <asm/page_types.h>
>> +#include <asm/irq_vectors.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> +
>> +/* CPUID: leaf 1, ECX, SMX feature bit */
>> +#define X86_FEATURE_BIT_SMX (1 << 6)
>> +
>> +#define IDT_VECTOR_LO_BITS 0
>> +#define IDT_VECTOR_HI_BITS 6
>> +
>> +/*
>> + * See the comment in head_64.S for detailed information on what this macro
>> + * and others like it are used for. The comment appears right at the top of
>> + * the file.
>> + */
>> +#define rva(X) ((X) - sl_stub_entry)
>> +
>> +/*
>> + * The GETSEC op code is open coded because older versions of
>> + * GCC do not support the getsec mnemonic.
>> + */
>> +.macro GETSEC leaf
>> + pushl %ebx
>> + xorl %ebx, %ebx /* Must be zero for SMCTRL */
>> + movl \leaf, %eax /* Leaf function */
>> + .byte 0x0f, 0x37 /* GETSEC opcode */
>> + popl %ebx
>> +.endm
>> +
>> +.macro TXT_RESET error
>> + /*
>> + * Set a sticky error value and reset. Note the movs to %eax act as
>> + * TXT register barriers.
>> + */
>> + movl \error, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_NO_SECRETS)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_UNLOCK_MEM_CONFIG)
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_E2STS), %eax
>> + movl $1, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_CMD_RESET)
>> +1:
>> + hlt
>> + jmp 1b
>> +.endm
>> +
>> + .code32
>> +SYM_FUNC_START(sl_stub_entry)
>> + cli
>> + cld
>> +
>> + /*
>> + * On entry, %ebx has the entry abs offset to sl_stub_entry. This
>> + * will be correctly scaled using the rva macro and avoid causing
>> + * relocations. Only %cs and %ds segments are known good.
>> + */
>> +
>> + /* Load GDT, set segment regs and lret to __SL32_CS */
>> + leal rva(sl_gdt_desc)(%ebx), %eax
>> + addl %eax, 2(%eax)
>> + lgdt (%eax)
>> +
>> + movl $(__SL32_DS), %eax
>> + movw %ax, %ds
>> + movw %ax, %es
>> + movw %ax, %fs
>> + movw %ax, %gs
>> + movw %ax, %ss
>> +
>> + /*
>> + * Now that %ss is known good, take the first stack for the BSP. The
>> + * AP stacks are only used on Intel.
>> + */
>> + leal rva(sl_stacks_end)(%ebx), %esp
>> +
>> + leal rva(.Lsl_cs)(%ebx), %eax
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + lret
>> +
>> +.Lsl_cs:
>> + /* Save our base pointer reg and page table for MLE */
>> + pushl %ebx
>> + pushl %ecx
>> +
>> + /* See if SMX feature is supported. */
>> + movl $1, %eax
>> + cpuid
>> + testl $(X86_FEATURE_BIT_SMX), %ecx
>> + jz .Ldo_unknown_cpu
>> +
>> + popl %ecx
>> + popl %ebx
>> +
>> + /* Know it is Intel */
>> + movl $(SL_CPU_INTEL), rva(sl_cpu_type)(%ebx)
>> +
>> + /* Locate the base of the MLE using the page tables in %ecx */
>> + call sl_find_mle_base
>> +
>> + /* Increment CPU count for BSP */
>> + incl rva(sl_txt_cpu_count)(%ebx)
>> +
>> + /*
>> + * Enable SMI with GETSEC[SMCTRL] which were disabled by SENTER.
>> + * NMIs were also disabled by SENTER. Since there is no IDT for the BSP,
>> + * allow the mainline kernel re-enable them in the normal course of
>> + * booting.
>> + */
>> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
>> +
>> + /* Clear the TXT error registers for a clean start of day */
>> + movl $0, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ERRORCODE)
>> + movl $0xffffffff, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_ESTS)
>> +
>> + /* On Intel, the zero page address is passed in the TXT heap */
>> + /* Read physical base of heap into EAX */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> + movl (%eax), %ecx
>> + /* Skip over BIOS data and size of OS to MLE data section */
>> + leal 8(%eax, %ecx), %eax
>> +
>> + /* Need to verify the values in the OS-MLE struct passed in */
>> + call sl_txt_verify_os_mle_struct
>> +
>> + /*
>> + * Get the boot params address from the heap. Note %esi and %ebx MUST
>> + * be preserved across calls and operations.
>> + */
>> + movl SL_boot_params_addr(%eax), %esi
>> +
>> + /* Save %ebx so the APs can find their way home */
>> + movl %ebx, (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax)
>> +
>> + /* Fetch the AP wake code block address from the heap */
>> + movl SL_ap_wake_block(%eax), %edi
>> + movl %edi, rva(sl_txt_ap_wake_block)(%ebx)
>> +
>> + /* Store the offset in the AP wake block to the jmp address */
>> + movl $(sl_ap_jmp_offset - sl_txt_ap_wake_begin), \
>> + (SL_mle_scratch + SL_SCRATCH_AP_JMP_OFFSET)(%eax)
>> +
>> + /* Store the offset in the AP wake block to the AP stacks block */
>> + movl $(sl_stacks - sl_txt_ap_wake_begin), \
>> + (SL_mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET)(%eax)
>> +
>> + /* %eax still is the base of the OS-MLE block, save it */
>> + pushl %eax
>> +
>> + /* Relocate the AP wake code to the safe block */
>> + call sl_txt_reloc_ap_wake
>> +
>> + /*
>> + * Wake up all APs that are blocked in the ACM and wait for them to
>> + * halt. This should be done before restoring the MTRRs so the ACM is
>> + * still properly in WB memory.
>> + */
>> + call sl_txt_wake_aps
>> +
>> + /* Restore OS-MLE in %eax */
>> + popl %eax
>> +
>> + /*
>> + * %edi is used by this routine to find the MTRRs which are in the SLRT
>> + * in the Intel info.
>> + */
>> + movl SL_txt_info(%eax), %edi
>> + call sl_txt_load_regs
>> +
>> + jmp .Lcpu_setup_done
>> +
>> +.Ldo_unknown_cpu:
>> + /* Non-Intel CPUs are not yet supported */
>> + ud2
>> +
>> +.Lcpu_setup_done:
>> + /*
>> + * Don't enable MCE at this point. The kernel will enable
>> + * it on the BSP later when it is ready.
>> + */
>> +
>> + /* Done, jump to normal 32b pm entry */
>> + jmp startup_32
>> +SYM_FUNC_END(sl_stub_entry)
>> +
>> +SYM_FUNC_START(sl_find_mle_base)
>> + /* %ecx has PDPT, get first PD */
>> + movl (%ecx), %eax
>> + andl $(PAGE_MASK), %eax
>> + /* Get first PT from first PDE */
>> + movl (%eax), %eax
>> + andl $(PAGE_MASK), %eax
>> + /* Get MLE base from first PTE */
>> + movl (%eax), %eax
>> + andl $(PAGE_MASK), %eax
>> +
>> + movl %eax, rva(sl_mle_start)(%ebx)
>> + ret
>> +SYM_FUNC_END(sl_find_mle_base)
>> +
>> +SYM_FUNC_START(sl_check_buffer_mle_overlap)
>> + /* %ecx: buffer begin %edx: buffer end */
>> + /* %ebx: MLE begin %edi: MLE end */
>> + /* %eax: region may be inside MLE */
>> +
>> + cmpl %edi, %ecx
>> + jb .Lnext_check
>> + cmpl %edi, %edx
>> + jbe .Lnext_check
>> + jmp .Lvalid /* Buffer above MLE */
>> +
>> +.Lnext_check:
>> + cmpl %ebx, %edx
>> + ja .Linside_check
>> + cmpl %ebx, %ecx
>> + jae .Linside_check
>> + jmp .Lvalid /* Buffer below MLE */
>> +
>> +.Linside_check:
>> + cmpl $0, %eax
>> + jz .Linvalid
>> + cmpl %ebx, %ecx
>> + jb .Linvalid
>> + cmpl %edi, %edx
>> + ja .Linvalid
>> + jmp .Lvalid /* Buffer in MLE */
>> +
>> +.Linvalid:
>> + TXT_RESET $(SL_ERROR_MLE_BUFFER_OVERLAP)
>> +
>> +.Lvalid:
>> + ret
>> +SYM_FUNC_END(sl_check_buffer_mle_overlap)
>> +
>> +SYM_FUNC_START(sl_txt_verify_os_mle_struct)
>> + pushl %ebx
>> + /*
>> + * %eax points to the base of the OS-MLE struct. Need to also
>> + * read some values from the OS-SINIT struct too.
>> + */
>> + movl -8(%eax), %ecx
>> + /* Skip over OS to MLE data section and size of OS-SINIT structure */
>> + leal (%eax, %ecx), %edx
>> +
>> + /* Load MLE image base absolute offset */
>> + movl rva(sl_mle_start)(%ebx), %ebx
>> +
>> + /* Verify the value of the low PMR base. It should always be 0. */
>> + movl SL_vtd_pmr_lo_base(%edx), %esi
>> + cmpl $0, %esi
>> + jz .Lvalid_pmr_base
>> + TXT_RESET $(SL_ERROR_LO_PMR_BASE)
>> +
>> +.Lvalid_pmr_base:
>> + /* Grab some values from OS-SINIT structure */
>> + movl SL_mle_size(%edx), %edi
>> + addl %ebx, %edi
>> + jc .Loverflow_detected
>> + movl SL_vtd_pmr_lo_size(%edx), %esi
>> +
>> + /* Check the AP wake block */
>> + movl SL_ap_wake_block(%eax), %ecx
>> + movl SL_ap_wake_block_size(%eax), %edx
>> + addl %ecx, %edx
>> + jc .Loverflow_detected
>> + pushl %eax
>> + xorl %eax, %eax
>> + call sl_check_buffer_mle_overlap
>> + popl %eax
>> + cmpl %esi, %edx
>> + ja .Lbuffer_beyond_pmr
>> +
>> + /*
>> + * Check the boot params. Note during a UEFI boot, the boot
>> + * params will be inside the MLE image. Test for this case
>> + * in the overlap case.
>> + */
>> + movl SL_boot_params_addr(%eax), %ecx
>> + movl $(PAGE_SIZE), %edx
>> + addl %ecx, %edx
>> + jc .Loverflow_detected
>> + pushl %eax
>> + movl $1, %eax
>> + call sl_check_buffer_mle_overlap
>> + popl %eax
>> + cmpl %esi, %edx
>> + ja .Lbuffer_beyond_pmr
>> +
>> + /* Check that the AP wake block is big enough */
>> + cmpl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), \
>> + SL_ap_wake_block_size(%eax)
>> + jae .Lwake_block_ok
>> + TXT_RESET $(SL_ERROR_WAKE_BLOCK_TOO_SMALL)
>> +
>> +.Lwake_block_ok:
>> + popl %ebx
>> + ret
>> +
>> +.Loverflow_detected:
>> + TXT_RESET $(SL_ERROR_INTEGER_OVERFLOW)
>> +
>> +.Lbuffer_beyond_pmr:
>> + TXT_RESET $(SL_ERROR_BUFFER_BEYOND_PMR)
>> +SYM_FUNC_END(sl_txt_verify_os_mle_struct)
>> +
>> +SYM_FUNC_START(sl_txt_ap_entry)
>> + cli
>> + cld
>> + /*
>> + * The %cs and %ds segments are known good after waking the AP.
>> + * First order of business is to find where we are and
>> + * save it in %ebx.
>> + */
>> +
>> + /* Read physical base of heap into EAX */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* Read the size of the BIOS data into ECX (first 8 bytes) */
>> + movl (%eax), %ecx
>> + /* Skip over BIOS data and size of OS to MLE data section */
>> + leal 8(%eax, %ecx), %eax
>> +
>> + /* Saved %ebx from the BSP and stash OS-MLE pointer */
>> + movl (SL_mle_scratch + SL_SCRATCH_AP_EBX)(%eax), %ebx
>> +
>> + /* Save TXT info ptr in %edi for call to sl_txt_load_regs */
>> + movl SL_txt_info(%eax), %edi
>> +
>> + /* Lock and get our stack index */
>> + movl $1, %ecx
>> +.Lspin:
>> + xorl %eax, %eax
>> + lock cmpxchgl %ecx, rva(sl_txt_spin_lock)(%ebx)
>> + pause
>> + jnz .Lspin
>> +
>> + /* Increment the stack index and use the next value inside lock */
>> + incl rva(sl_txt_stack_index)(%ebx)
>> + movl rva(sl_txt_stack_index)(%ebx), %eax
>> +
>> + /* Unlock */
>> + movl $0, rva(sl_txt_spin_lock)(%ebx)
>> +
>> + /* Location of the relocated AP wake block */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> +
>> + /* Load reloc GDT, set segment regs and lret to __SL32_CS */
>> + lgdt (sl_ap_gdt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> + movl $(__SL32_DS), %edx
>> + movw %dx, %ds
>> + movw %dx, %es
>> + movw %dx, %fs
>> + movw %dx, %gs
>> + movw %dx, %ss
>> +
>> + /* Load our reloc AP stack */
>> + movl $(TXT_BOOT_STACK_SIZE), %edx
>> + mull %edx
>> + leal (sl_stacks_end - sl_txt_ap_wake_begin)(%ecx), %esp
>> + subl %eax, %esp
>> +
>> + /* Switch to AP code segment */
>> + leal rva(.Lsl_ap_cs)(%ebx), %eax
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + lret
>> +
>> +.Lsl_ap_cs:
>> + /* Load the relocated AP IDT */
>> + lidt (sl_ap_idt_desc - sl_txt_ap_wake_begin)(%ecx)
>> +
>> + /* Fixup MTRRs and misc enable MSR on APs too */
>> + call sl_txt_load_regs
>> +
>> + /* Enable SMI with GETSEC[SMCTRL] */
>> + GETSEC $(SMX_X86_GETSEC_SMCTRL)
>> +
>> + /* IRET-to-self can be used to enable NMIs which SENTER disabled */
>> + leal rva(.Lnmi_enabled_ap)(%ebx), %eax
>> + pushfl
>> + pushl $(__SL32_CS)
>> + pushl %eax
>> + iret
>> +
>> +.Lnmi_enabled_ap:
>> + /* Put APs in X2APIC mode like the BSP */
>> + movl $(MSR_IA32_APICBASE), %ecx
>> + rdmsr
>> + orl $(XAPIC_ENABLE | X2APIC_ENABLE), %eax
>> + wrmsr
>> +
>> + /*
>> + * Basically done, increment the CPU count and jump off to the AP
>> + * wake block to wait.
>> + */
>> + lock incl rva(sl_txt_cpu_count)(%ebx)
>> +
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
>> + jmp *%eax
>> +SYM_FUNC_END(sl_txt_ap_entry)
>> +
>> +SYM_FUNC_START(sl_txt_reloc_ap_wake)
>> + /* Save boot params register */
>> + pushl %esi
>> +
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %edi
>> +
>> + /* Fixup AP IDT and GDT descriptor before relocating */
>> + leal rva(sl_ap_idt_desc)(%ebx), %eax
>> + addl %edi, 2(%eax)
>> + leal rva(sl_ap_gdt_desc)(%ebx), %eax
>> + addl %edi, 2(%eax)
>> +
>> + /*
>> + * Copy the AP wake code and AP GDT/IDT to the protected wake block
>> + * provided by the loader. Destination already in %edi.
>> + */
>> + movl $(sl_txt_ap_wake_end - sl_txt_ap_wake_begin), %ecx
>> + leal rva(sl_txt_ap_wake_begin)(%ebx), %esi
>> + rep movsb
>> +
>> + /* Setup the IDT for the APs to use in the relocation block */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %ecx
>> + addl $(sl_ap_idt - sl_txt_ap_wake_begin), %ecx
>> + xorl %edx, %edx
>> +
>> + /* Form the default reset vector relocation address */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %esi
>> + addl $(sl_txt_int_reset - sl_txt_ap_wake_begin), %esi
>> +
>> +1:
>> + cmpw $(NR_VECTORS), %dx
>> + jz .Lap_idt_done
>> +
>> + cmpw $(X86_TRAP_NMI), %dx
>> + jz 2f
>> +
>> + /* Load all other fixed vectors with reset handler */
>> + movl %esi, %eax
>> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> + shrl $16, %eax
>> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> + jmp 3f
>> +
>> +2:
>> + /* Load single wake NMI IPI vector at the relocation address */
>> + movl rva(sl_txt_ap_wake_block)(%ebx), %eax
>> + addl $(sl_txt_int_nmi - sl_txt_ap_wake_begin), %eax
>> + movw %ax, (IDT_VECTOR_LO_BITS)(%ecx)
>> + shrl $16, %eax
>> + movw %ax, (IDT_VECTOR_HI_BITS)(%ecx)
>> +
>> +3:
>> + incw %dx
>> + addl $8, %ecx
>> + jmp 1b
>> +
>> +.Lap_idt_done:
>> + popl %esi
>> + ret
>> +SYM_FUNC_END(sl_txt_reloc_ap_wake)
>> +
>> +SYM_FUNC_START(sl_txt_load_regs)
>> + /* Save base pointer register */
>> + pushl %ebx
>> +
>> + /*
>> + * On Intel, the original variable MTRRs and Misc Enable MSR are
>> + * restored on the BSP at early boot. Each AP will also restore
>> + * its MTRRs and Misc Enable MSR.
>> + */
>> + pushl %edi
>> + addl $(SL_saved_bsp_mtrrs), %edi
>> + movl (%edi), %ebx
>> + pushl %ebx /* default_mem_type lo */
>> + addl $4, %edi
>> + movl (%edi), %ebx
>> + pushl %ebx /* default_mem_type hi */
>> + addl $4, %edi
>> + movl (%edi), %ebx /* mtrr_vcnt lo, don't care about hi part */
>> + addl $8, %edi /* now at MTRR pair array */
>> + /* Write the variable MTRRs */
>> + movl $(MSR_MTRRphysBase0), %ecx
>> +1:
>> + cmpl $0, %ebx
>> + jz 2f
>> +
>> + movl (%edi), %eax /* MTRRphysBaseX lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* MTRRphysBaseX hi */
>> + wrmsr
>> + addl $4, %edi
>> + incl %ecx
>> + movl (%edi), %eax /* MTRRphysMaskX lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* MTRRphysMaskX hi */
>> + wrmsr
>> + addl $4, %edi
>> + incl %ecx
>> +
>> + decl %ebx
>> + jmp 1b
>> +2:
>> + /* Write the default MTRR register */
>> + popl %edx
>> + popl %eax
>> + movl $(MSR_MTRRdefType), %ecx
>> + wrmsr
>> +
>> + /* Return to beginning and write the misc enable msr */
>> + popl %edi
>> + addl $(SL_saved_misc_enable_msr), %edi
>> + movl (%edi), %eax /* saved_misc_enable_msr lo */
>> + addl $4, %edi
>> + movl (%edi), %edx /* saved_misc_enable_msr hi */
>> + movl $(MSR_IA32_MISC_ENABLE), %ecx
>> + wrmsr
>> +
>> + popl %ebx
>> + ret
>> +SYM_FUNC_END(sl_txt_load_regs)
>> +
>> +SYM_FUNC_START(sl_txt_wake_aps)
>> + /* Save boot params register */
>> + pushl %esi
>> +
>> + /* First setup the MLE join structure and load it into TXT reg */
>> + leal rva(sl_gdt)(%ebx), %eax
>> + leal rva(sl_txt_ap_entry)(%ebx), %ecx
>> + leal rva(sl_smx_rlp_mle_join)(%ebx), %edx
>> + movl %eax, SL_rlp_gdt_base(%edx)
>> + movl %ecx, SL_rlp_entry_point(%edx)
>> + movl %edx, (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_MLE_JOIN)
>> +
>> + /* Another TXT heap walk to find various values needed to wake APs */
>> + movl (TXT_PRIV_CONFIG_REGS_BASE + TXT_CR_HEAP_BASE), %eax
>> + /* At BIOS data size, find the number of logical processors */
>> + movl (SL_num_logical_procs + 8)(%eax), %edx
>> + /* Skip over BIOS data */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* Skip over OS to MLE */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* At OS-SNIT size, get capabilities to know how to wake up the APs */
>> + movl (SL_capabilities + 8)(%eax), %esi
>> + /* Skip over OS to SNIT */
>> + movl (%eax), %ecx
>> + addl %ecx, %eax
>> + /* At SINIT-MLE size, get the AP wake MONITOR address */
>> + movl (SL_rlp_wakeup_addr + 8)(%eax), %edi
>> +
>> + /* Determine how to wake up the APs */
>> + testl $(1 << TXT_SINIT_MLE_CAP_WAKE_MONITOR), %esi
>> + jz .Lwake_getsec
>> +
>> + /* Wake using MWAIT MONITOR */
>> + movl $1, (%edi)
>> + jmp .Laps_awake
>> +
>> +.Lwake_getsec:
>> + /* Wake using GETSEC(WAKEUP) */
>> + GETSEC $(SMX_X86_GETSEC_WAKEUP)
>> +
>> +.Laps_awake:
>> + /*
>> + * All of the APs are woken up and rendesvous in the relocated wake
>> + * block starting at sl_txt_ap_wake_begin. Wait for all of them to
>> + * halt.
>> + */
>> + pause
>> + cmpl rva(sl_txt_cpu_count)(%ebx), %edx
>> + jne .Laps_awake
>> +
>> + popl %esi
>> + ret
>> +SYM_FUNC_END(sl_txt_wake_aps)
>> +
>> +/* This is the beginning of the relocated AP wake code block */
>> + .global sl_txt_ap_wake_begin
>> +sl_txt_ap_wake_begin:
>> +
>> + /* Get the LAPIC ID for each AP and stash it on the stack */
>> + movl $(MSR_IA32_X2APIC_APICID), %ecx
>> + rdmsr
>> + pushl %eax
>> +
>> + /*
>> + * Get a pointer to the monitor location on this APs stack to test below
>> + * after mwait returns. Currently %esp points to just past the pushed APIC
>> + * ID value.
>> + */
>> + movl %esp, %eax
>> + subl $(TXT_BOOT_STACK_SIZE - 4), %eax
>> + movl $0, (%eax)
>> +
>> + /* Clear ecx/edx so no invalid extensions or hints are passed to monitor */
>> + xorl %ecx, %ecx
>> + xorl %edx, %edx
>> +
>> + /*
>> + * Arm the monitor and wait for it to be poked by he SMP bringup code. The mwait
>> + * instruction can return for a number of reasons. Test to see if it returned
>> + * because the monitor was written to.
>> + */
>> + monitor
>> +
>> +1:
>> + mfence
>> + mwait
>> + movl (%eax), %edx
>> + testl %edx, %edx
>> + jz 1b
>> +
>> + /*
>> + * This is the long absolute jump to the 32b Secure Launch protected mode stub
>> + * code in sl_trampoline_start32() in the rmpiggy. The jump address will be
>> + * fixed in the SMP boot code when the first AP is brought up. This whole area
>> + * is provided and protected in the memory map by the prelaunch code.
>> + */
>> + .byte 0xea
>> +sl_ap_jmp_offset:
>> + .long 0x00000000
>> + .word __SL32_CS
>> +
>> +SYM_FUNC_START(sl_txt_int_nmi)
>> + /* NMI context, just IRET */
>> + iret
>> +SYM_FUNC_END(sl_txt_int_nmi)
>> +
>> +SYM_FUNC_START(sl_txt_int_reset)
>> + TXT_RESET $(SL_ERROR_INV_AP_INTERRUPT)
>> +SYM_FUNC_END(sl_txt_int_reset)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt_desc)
>> + .word sl_ap_idt_end - sl_ap_idt - 1 /* Limit */
>> + .long sl_ap_idt - sl_txt_ap_wake_begin /* Base */
>> +SYM_DATA_END_LABEL(sl_ap_idt_desc, SYM_L_LOCAL, sl_ap_idt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_idt)
>> + .rept NR_VECTORS
>> + .word 0x0000 /* Offset 15 to 0 */
>> + .word __SL32_CS /* Segment selector */
>> + .word 0x8e00 /* Present, DPL=0, 32b Vector, Interrupt */
>> + .word 0x0000 /* Offset 31 to 16 */
>> + .endr
>> +SYM_DATA_END_LABEL(sl_ap_idt, SYM_L_LOCAL, sl_ap_idt_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt_desc)
>> + .word sl_ap_gdt_end - sl_ap_gdt - 1
>> + .long sl_ap_gdt - sl_txt_ap_wake_begin
>> +SYM_DATA_END_LABEL(sl_ap_gdt_desc, SYM_L_LOCAL, sl_ap_gdt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_ap_gdt)
>> + .quad 0x0000000000000000 /* NULL */
>> + .quad 0x00cf9a000000ffff /* __SL32_CS */
>> + .quad 0x00cf92000000ffff /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_ap_gdt, SYM_L_LOCAL, sl_ap_gdt_end)
>> +
>> + /* Small stacks for BSP and APs to work with */
>> + .balign 64
>> +SYM_DATA_START_LOCAL(sl_stacks)
>> + .fill (TXT_MAX_CPUS * TXT_BOOT_STACK_SIZE), 1, 0
>> +SYM_DATA_END_LABEL(sl_stacks, SYM_L_LOCAL, sl_stacks_end)
>> +
>> +/* This is the end of the relocated AP wake code block */
>> + .global sl_txt_ap_wake_end
>> +sl_txt_ap_wake_end:
>> +
>> + .data
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt_desc)
>> + .word sl_gdt_end - sl_gdt - 1
>> + .long sl_gdt - sl_gdt_desc
>> +SYM_DATA_END_LABEL(sl_gdt_desc, SYM_L_LOCAL, sl_gdt_desc_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_gdt)
>> + .quad 0x0000000000000000 /* NULL */
>> + .quad 0x00cf9a000000ffff /* __SL32_CS */
>> + .quad 0x00cf92000000ffff /* __SL32_DS */
>> +SYM_DATA_END_LABEL(sl_gdt, SYM_L_LOCAL, sl_gdt_end)
>> +
>> + .balign 8
>> +SYM_DATA_START_LOCAL(sl_smx_rlp_mle_join)
>> + .long sl_gdt_end - sl_gdt - 1 /* GDT limit */
>> + .long 0x00000000 /* GDT base */
>> + .long __SL32_CS /* Seg Sel - CS (DS, ES, SS = seg_sel+8) */
>> + .long 0x00000000 /* Entry point physical address */
>> +SYM_DATA_END(sl_smx_rlp_mle_join)
>> +
>> +SYM_DATA(sl_cpu_type, .long 0x00000000)
>> +
>> +SYM_DATA(sl_mle_start, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_spin_lock, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_stack_index, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_cpu_count, .long 0x00000000)
>> +
>> +SYM_DATA_LOCAL(sl_txt_ap_wake_block, .long 0x00000000)
>> diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
>> index e022e6eb766c..37f6167f28ba 100644
>> --- a/arch/x86/include/asm/msr-index.h
>> +++ b/arch/x86/include/asm/msr-index.h
>> @@ -348,6 +348,9 @@
>> #define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560
>> #define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561
>>
>> +#define MSR_MTRRphysBase0 0x00000200
>> +#define MSR_MTRRphysMask0 0x00000201
>> +
>> #define MSR_MTRRfix64K_00000 0x00000250
>> #define MSR_MTRRfix16K_80000 0x00000258
>> #define MSR_MTRRfix16K_A0000 0x00000259
>> @@ -849,6 +852,8 @@
>> #define MSR_IA32_APICBASE_ENABLE (1<<11)
>> #define MSR_IA32_APICBASE_BASE (0xfffff<<12)
>>
>> +#define MSR_IA32_X2APIC_APICID 0x00000802
>> +
>> #define MSR_IA32_UCODE_WRITE 0x00000079
>> #define MSR_IA32_UCODE_REV 0x0000008b
>>
>
> MSR updates are better to be split to their own patch.
Yes we can do that, it makes sense.
Thanks
>
>> diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
>> index 9b82eebd7add..7ce283a22d6b 100644
>> --- a/arch/x86/include/uapi/asm/bootparam.h
>> +++ b/arch/x86/include/uapi/asm/bootparam.h
>> @@ -12,6 +12,7 @@
>> /* loadflags */
>> #define LOADED_HIGH (1<<0)
>> #define KASLR_FLAG (1<<1)
>> +#define SLAUNCH_FLAG (1<<2)
>> #define QUIET_FLAG (1<<5)
>> #define KEEP_SEGMENTS (1<<6)
>> #define CAN_USE_HEAP (1<<7)
>> diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
>> index a98020bf31bb..925adce6e2c7 100644
>> --- a/arch/x86/kernel/asm-offsets.c
>> +++ b/arch/x86/kernel/asm-offsets.c
>> @@ -13,6 +13,8 @@
>> #include <linux/hardirq.h>
>> #include <linux/suspend.h>
>> #include <linux/kbuild.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>> #include <asm/processor.h>
>> #include <asm/thread_info.h>
>> #include <asm/sigframe.h>
>> @@ -120,4 +122,22 @@ static void __used common(void)
>> OFFSET(ARIA_CTX_rounds, aria_ctx, rounds);
>> #endif
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + BLANK();
>> + OFFSET(SL_txt_info, txt_os_mle_data, txt_info);
>> + OFFSET(SL_mle_scratch, txt_os_mle_data, mle_scratch);
>> + OFFSET(SL_boot_params_addr, txt_os_mle_data, boot_params_addr);
>> + OFFSET(SL_ap_wake_block, txt_os_mle_data, ap_wake_block);
>> + OFFSET(SL_ap_wake_block_size, txt_os_mle_data, ap_wake_block_size);
>> + OFFSET(SL_saved_misc_enable_msr, slr_entry_intel_info, saved_misc_enable_msr);
>> + OFFSET(SL_saved_bsp_mtrrs, slr_entry_intel_info, saved_bsp_mtrrs);
>> + OFFSET(SL_num_logical_procs, txt_bios_data, num_logical_procs);
>> + OFFSET(SL_capabilities, txt_os_sinit_data, capabilities);
>> + OFFSET(SL_mle_size, txt_os_sinit_data, mle_size);
>> + OFFSET(SL_vtd_pmr_lo_base, txt_os_sinit_data, vtd_pmr_lo_base);
>> + OFFSET(SL_vtd_pmr_lo_size, txt_os_sinit_data, vtd_pmr_lo_size);
>> + OFFSET(SL_rlp_wakeup_addr, txt_sinit_mle_data, rlp_wakeup_addr);
>> + OFFSET(SL_rlp_gdt_base, smx_rlp_mle_join, rlp_gdt_base);
>> + OFFSET(SL_rlp_entry_point, smx_rlp_mle_join, rlp_entry_point);
>> +#endif
>> }
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 08/19] x86: Secure Launch kernel early boot stub
2024-06-04 21:09 ` ross.philipson
@ 2024-06-04 22:43 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:43 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
> > s/tpm20/tpm2/
>
> Reasonable. We can change it.
For the sake of consistency. Anywhere else where we have code using TPM,
either "tpm_" or "tpm2_" is used.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (7 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 08/19] x86: Secure Launch kernel early boot stub Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 19:58 ` Jarkko Sakkinen
2024-06-04 19:59 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 10/19] x86: Secure Launch SMP bringup support Ross Philipson
` (9 subsequent siblings)
18 siblings, 2 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
The routine slaunch_setup is called out of the x86 specific setup_arch()
routine during early kernel boot. After determining what platform is
present, various operations specific to that platform occur. This
includes finalizing setting for the platform late launch and verifying
that memory protections are in place.
For TXT, this code also reserves the original compressed kernel setup
area where the APs were left looping so that this memory cannot be used.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/setup.c | 3 +
arch/x86/kernel/slaunch.c | 525 +++++++++++++++++++++++++++++++++++++
drivers/iommu/intel/dmar.c | 4 +
4 files changed, 533 insertions(+)
create mode 100644 arch/x86/kernel/slaunch.c
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 5d128167e2e2..b35ca99ab0a0 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o
obj-$(CONFIG_IA32_EMULATION) += tls.o
obj-y += step.o
obj-$(CONFIG_INTEL_TXT) += tboot.o
+obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
obj-$(CONFIG_ISA_DMA_API) += i8237.o
obj-y += stacktrace.o
obj-y += cpu/
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 55a1fc332e20..31d1e6b9bd36 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -21,6 +21,7 @@
#include <linux/root_dev.h>
#include <linux/hugetlb.h>
#include <linux/tboot.h>
+#include <linux/slaunch.h>
#include <linux/usb/xhci-dbgp.h>
#include <linux/static_call.h>
#include <linux/swiotlb.h>
@@ -936,6 +937,8 @@ void __init setup_arch(char **cmdline_p)
early_gart_iommu_check();
#endif
+ slaunch_setup_txt();
+
/*
* partially used pages are not usable - thus
* we are rounding upwards:
diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c
new file mode 100644
index 000000000000..48c9ca78e241
--- /dev/null
+++ b/arch/x86/kernel/slaunch.c
@@ -0,0 +1,525 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Secure Launch late validation/setup and finalization support.
+ *
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/security.h>
+#include <linux/memblock.h>
+#include <asm/segment.h>
+#include <asm/sections.h>
+#include <asm/tlbflush.h>
+#include <asm/e820/api.h>
+#include <asm/setup.h>
+#include <asm/realmode.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
+
+static u32 sl_flags __ro_after_init;
+static struct sl_ap_wake_info ap_wake_info __ro_after_init;
+static u64 evtlog_addr __ro_after_init;
+static u32 evtlog_size __ro_after_init;
+static u64 vtd_pmr_lo_size __ro_after_init;
+
+/* This should be plenty of room */
+static u8 txt_dmar[PAGE_SIZE] __aligned(16);
+
+/*
+ * Get the Secure Launch flags that indicate what kind of launch is being done.
+ * E.g. a TXT launch is in progress or no Secure Launch is happening.
+ */
+u32 slaunch_get_flags(void)
+{
+ return sl_flags;
+}
+
+/*
+ * Return the AP wakeup information used in the SMP boot code to start up
+ * the APs that are parked using MONITOR/MWAIT.
+ */
+struct sl_ap_wake_info *slaunch_get_ap_wake_info(void)
+{
+ return &ap_wake_info;
+}
+
+/*
+ * On Intel platforms, TXT passes a safe copy of the DMAR ACPI table to the
+ * DRTM. The DRTM is supposed to use this instead of the one found in the
+ * ACPI tables.
+ */
+struct acpi_table_header *slaunch_get_dmar_table(struct acpi_table_header *dmar)
+{
+ /* The DMAR is only stashed and provided via TXT on Intel systems */
+ if (memcmp(txt_dmar, "DMAR", 4))
+ return dmar;
+
+ return (struct acpi_table_header *)(txt_dmar);
+}
+
+/*
+ * If running within a TXT established DRTM, this is the proper way to reset
+ * the system if a failure occurs or a security issue is found.
+ */
+void __noreturn slaunch_txt_reset(void __iomem *txt,
+ const char *msg, u64 error)
+{
+ u64 one = 1, val;
+
+ pr_err("%s", msg);
+
+ /*
+ * This performs a TXT reset with a sticky error code. The reads of
+ * TXT_CR_E2STS act as barriers.
+ */
+ memcpy_toio(txt + TXT_CR_ERRORCODE, &error, sizeof(error));
+ memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(val));
+ memcpy_toio(txt + TXT_CR_CMD_NO_SECRETS, &one, sizeof(one));
+ memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(val));
+ memcpy_toio(txt + TXT_CR_CMD_UNLOCK_MEM_CONFIG, &one, sizeof(one));
+ memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(val));
+ memcpy_toio(txt + TXT_CR_CMD_RESET, &one, sizeof(one));
+
+ for ( ; ; )
+ asm volatile ("hlt");
+
+ unreachable();
+}
+
+/*
+ * The TXT heap is too big to map all at once with early_ioremap
+ * so it is done a table at a time.
+ */
+static void __init *txt_early_get_heap_table(void __iomem *txt, u32 type,
+ u32 bytes)
+{
+ u64 base, size, offset = 0;
+ void *heap;
+ int i;
+
+ if (type > TXT_SINIT_TABLE_MAX)
+ slaunch_txt_reset(txt, "Error invalid table type for early heap walk\n",
+ SL_ERROR_HEAP_WALK);
+
+ memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(base));
+ memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(size));
+
+ /* Iterate over heap tables looking for table of "type" */
+ for (i = 0; i < type; i++) {
+ base += offset;
+ heap = early_memremap(base, sizeof(u64));
+ if (!heap)
+ slaunch_txt_reset(txt, "Error early_memremap of heap for heap walk\n",
+ SL_ERROR_HEAP_MAP);
+
+ offset = *((u64 *)heap);
+
+ /*
+ * After the first iteration, any offset of zero is invalid and
+ * implies the TXT heap is corrupted.
+ */
+ if (!offset)
+ slaunch_txt_reset(txt, "Error invalid 0 offset in heap walk\n",
+ SL_ERROR_HEAP_ZERO_OFFSET);
+
+ early_memunmap(heap, sizeof(u64));
+ }
+
+ /* Skip the size field at the head of each table */
+ base += sizeof(u64);
+ heap = early_memremap(base, bytes);
+ if (!heap)
+ slaunch_txt_reset(txt, "Error early_memremap of heap section\n",
+ SL_ERROR_HEAP_MAP);
+
+ return heap;
+}
+
+static void __init txt_early_put_heap_table(void *addr, unsigned long size)
+{
+ early_memunmap(addr, size);
+}
+
+/*
+ * TXT uses a special set of VTd registers to protect all of memory from DMA
+ * until the IOMMU can be programmed to protect memory. There is the low
+ * memory PMR that can protect all memory up to 4G. The high memory PRM can
+ * be setup to protect all memory beyond 4Gb. Validate that these values cover
+ * what is expected.
+ */
+static void __init slaunch_verify_pmrs(void __iomem *txt)
+{
+ struct txt_os_sinit_data *os_sinit_data;
+ u32 field_offset, err = 0;
+ const char *errmsg = "";
+ unsigned long last_pfn;
+
+ field_offset = offsetof(struct txt_os_sinit_data, lcp_po_base);
+ os_sinit_data = txt_early_get_heap_table(txt, TXT_OS_SINIT_DATA_TABLE,
+ field_offset);
+
+ /* Save a copy */
+ vtd_pmr_lo_size = os_sinit_data->vtd_pmr_lo_size;
+
+ last_pfn = e820__end_of_ram_pfn();
+
+ /*
+ * First make sure the hi PMR covers all memory above 4G. In the
+ * unlikely case where there is < 4G on the system, the hi PMR will
+ * not be set.
+ */
+ if (os_sinit_data->vtd_pmr_hi_base != 0x0ULL) {
+ if (os_sinit_data->vtd_pmr_hi_base != 0x100000000ULL) {
+ err = SL_ERROR_HI_PMR_BASE;
+ errmsg = "Error hi PMR base\n";
+ goto out;
+ }
+
+ if (PFN_PHYS(last_pfn) > os_sinit_data->vtd_pmr_hi_base +
+ os_sinit_data->vtd_pmr_hi_size) {
+ err = SL_ERROR_HI_PMR_SIZE;
+ errmsg = "Error hi PMR size\n";
+ goto out;
+ }
+ }
+
+ /*
+ * Lo PMR base should always be 0. This was already checked in
+ * early stub.
+ */
+
+ /*
+ * Check that if the kernel was loaded below 4G, that it is protected
+ * by the lo PMR. Note this is the decompressed kernel. The ACM would
+ * have ensured the compressed kernel (the MLE image) was protected.
+ */
+ if (__pa_symbol(_end) < 0x100000000ULL && __pa_symbol(_end) > os_sinit_data->vtd_pmr_lo_size) {
+ err = SL_ERROR_LO_PMR_MLE;
+ errmsg = "Error lo PMR does not cover MLE kernel\n";
+ }
+
+ /*
+ * Other regions of interest like boot param, AP wake block, cmdline
+ * already checked for PMR coverage in the early stub code.
+ */
+
+out:
+ txt_early_put_heap_table(os_sinit_data, field_offset);
+
+ if (err)
+ slaunch_txt_reset(txt, errmsg, err);
+}
+
+static void __init slaunch_txt_reserve_range(u64 base, u64 size)
+{
+ int type;
+
+ type = e820__get_entry_type(base, base + size - 1);
+ if (type == E820_TYPE_RAM) {
+ pr_info("memblock reserve base: %llx size: %llx\n", base, size);
+ memblock_reserve(base, size);
+ }
+}
+
+/*
+ * For Intel, certain regions of memory must be marked as reserved by putting
+ * them on the memblock reserved list if they are not already e820 reserved.
+ * This includes:
+ * - The TXT HEAP
+ * - The ACM area
+ * - The TXT private register bank
+ * - The MDR list sent to the MLE by the ACM (see TXT specification)
+ * (Normally the above are properly reserved by firmware but if it was not
+ * done, reserve them now)
+ * - The AP wake block
+ * - TPM log external to the TXT heap
+ *
+ * Also if the low PMR doesn't cover all memory < 4G, any RAM regions above
+ * the low PMR must be reserved too.
+ */
+static void __init slaunch_txt_reserve(void __iomem *txt)
+{
+ struct txt_sinit_memory_descriptor_record *mdr;
+ struct txt_sinit_mle_data *sinit_mle_data;
+ u64 base, size, heap_base, heap_size;
+ u32 mdrnum, mdroffset, mdrslen;
+ u32 field_offset, i;
+ void *mdrs;
+
+ base = TXT_PRIV_CONFIG_REGS_BASE;
+ size = TXT_PUB_CONFIG_REGS_BASE - TXT_PRIV_CONFIG_REGS_BASE;
+ slaunch_txt_reserve_range(base, size);
+
+ memcpy_fromio(&heap_base, txt + TXT_CR_HEAP_BASE, sizeof(heap_base));
+ memcpy_fromio(&heap_size, txt + TXT_CR_HEAP_SIZE, sizeof(heap_size));
+ slaunch_txt_reserve_range(heap_base, heap_size);
+
+ memcpy_fromio(&base, txt + TXT_CR_SINIT_BASE, sizeof(base));
+ memcpy_fromio(&size, txt + TXT_CR_SINIT_SIZE, sizeof(size));
+ slaunch_txt_reserve_range(base, size);
+
+ field_offset = offsetof(struct txt_sinit_mle_data,
+ sinit_vtd_dmar_table_size);
+ sinit_mle_data = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE,
+ field_offset);
+
+ mdrnum = sinit_mle_data->num_of_sinit_mdrs;
+ mdroffset = sinit_mle_data->sinit_mdrs_table_offset;
+
+ txt_early_put_heap_table(sinit_mle_data, field_offset);
+
+ if (!mdrnum)
+ goto nomdr;
+
+ mdrslen = mdrnum * sizeof(struct txt_sinit_memory_descriptor_record);
+
+ mdrs = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE,
+ mdroffset + mdrslen - 8);
+
+ mdr = mdrs + mdroffset - 8;
+
+ for (i = 0; i < mdrnum; i++, mdr++) {
+ /* Spec says some entries can have length 0, ignore them */
+ if (mdr->type > 0 && mdr->length > 0)
+ slaunch_txt_reserve_range(mdr->address, mdr->length);
+ }
+
+ txt_early_put_heap_table(mdrs, mdroffset + mdrslen - 8);
+
+nomdr:
+ slaunch_txt_reserve_range(ap_wake_info.ap_wake_block,
+ ap_wake_info.ap_wake_block_size);
+
+ /*
+ * Earlier checks ensured that the event log was properly situated
+ * either inside the TXT heap or outside. This is a check to see if the
+ * event log needs to be reserved. If it is in the TXT heap, it is
+ * already reserved.
+ */
+ if (evtlog_addr < heap_base || evtlog_addr > (heap_base + heap_size))
+ slaunch_txt_reserve_range(evtlog_addr, evtlog_size);
+
+ for (i = 0; i < e820_table->nr_entries; i++) {
+ base = e820_table->entries[i].addr;
+ size = e820_table->entries[i].size;
+ if (base >= vtd_pmr_lo_size && base < 0x100000000ULL)
+ slaunch_txt_reserve_range(base, size);
+ else if (base < vtd_pmr_lo_size && base + size > vtd_pmr_lo_size)
+ slaunch_txt_reserve_range(vtd_pmr_lo_size,
+ base + size - vtd_pmr_lo_size);
+ }
+}
+
+/*
+ * TXT stashes a safe copy of the DMAR ACPI table to prevent tampering.
+ * It is stored in the TXT heap. Fetch it from there and make it available
+ * to the IOMMU driver.
+ */
+static void __init slaunch_copy_dmar_table(void __iomem *txt)
+{
+ struct txt_sinit_mle_data *sinit_mle_data;
+ u32 field_offset, dmar_size, dmar_offset;
+ void *dmar;
+
+ field_offset = offsetof(struct txt_sinit_mle_data,
+ processor_scrtm_status);
+ sinit_mle_data = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE,
+ field_offset);
+
+ dmar_size = sinit_mle_data->sinit_vtd_dmar_table_size;
+ dmar_offset = sinit_mle_data->sinit_vtd_dmar_table_offset;
+
+ txt_early_put_heap_table(sinit_mle_data, field_offset);
+
+ if (!dmar_size || !dmar_offset)
+ slaunch_txt_reset(txt, "Error invalid DMAR table values\n",
+ SL_ERROR_HEAP_INVALID_DMAR);
+
+ if (unlikely(dmar_size > PAGE_SIZE))
+ slaunch_txt_reset(txt, "Error DMAR too big to store\n",
+ SL_ERROR_HEAP_DMAR_SIZE);
+
+ dmar = txt_early_get_heap_table(txt, TXT_SINIT_MLE_DATA_TABLE,
+ dmar_offset + dmar_size - 8);
+ if (!dmar)
+ slaunch_txt_reset(txt, "Error early_ioremap of DMAR\n",
+ SL_ERROR_HEAP_DMAR_MAP);
+
+ memcpy(txt_dmar, dmar + dmar_offset - 8, dmar_size);
+
+ txt_early_put_heap_table(dmar, dmar_offset + dmar_size - 8);
+}
+
+/*
+ * The location of the safe AP wake code block is stored in the TXT heap.
+ * Fetch needed values here in the early init code for later use in SMP
+ * startup.
+ *
+ * Also get the TPM event log values are in the SLRT and have to be fetched.
+ * They will be put on the memblock reserve list later.
+ */
+static void __init slaunch_fetch_values(void __iomem *txt)
+{
+ struct txt_os_mle_data *os_mle_data;
+ struct slr_entry_log_info *log_info;
+ u8 *jmp_offset, *stacks_offset;
+ struct slr_table *slrt;
+ u32 size;
+
+ os_mle_data = txt_early_get_heap_table(txt, TXT_OS_MLE_DATA_TABLE,
+ sizeof(*os_mle_data));
+
+ ap_wake_info.ap_wake_block = os_mle_data->ap_wake_block;
+ ap_wake_info.ap_wake_block_size = os_mle_data->ap_wake_block_size;
+
+ jmp_offset = os_mle_data->mle_scratch + SL_SCRATCH_AP_JMP_OFFSET;
+ ap_wake_info.ap_jmp_offset = *((u32 *)jmp_offset);
+
+ stacks_offset = os_mle_data->mle_scratch + SL_SCRATCH_AP_STACKS_OFFSET;
+ ap_wake_info.ap_stacks_offset = *((u32 *)stacks_offset);
+
+ slrt = (struct slr_table *)early_memremap(os_mle_data->slrt, sizeof(*slrt));
+ if (!slrt)
+ slaunch_txt_reset(txt, "Error early_memremap of SLRT failed\n",
+ SL_ERROR_SLRT_MAP);
+
+ size = slrt->size;
+ early_memunmap(slrt, sizeof(*slrt));
+
+ slrt = (struct slr_table *)early_memremap(os_mle_data->slrt, size);
+ if (!slrt)
+ slaunch_txt_reset(txt, "Error early_memremap of SLRT failed\n",
+ SL_ERROR_SLRT_MAP);
+
+ log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
+
+ if (!log_info)
+ slaunch_txt_reset(txt, "SLRT missing logging info entry\n",
+ SL_ERROR_SLRT_MISSING_ENTRY);
+
+ evtlog_addr = log_info->addr;
+ evtlog_size = log_info->size;
+
+ early_memunmap(slrt, size);
+
+ txt_early_put_heap_table(os_mle_data, sizeof(*os_mle_data));
+}
+
+/*
+ * Called to fix the long jump address for the waiting APs to vector to
+ * the correct startup location in the Secure Launch stub in the rmpiggy.
+ */
+void __init slaunch_fixup_jump_vector(void)
+{
+ struct sl_ap_wake_info *ap_wake_info;
+ u32 *ap_jmp_ptr;
+
+ if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) !=
+ (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
+ return;
+
+ ap_wake_info = slaunch_get_ap_wake_info();
+
+ ap_jmp_ptr = (u32 *)__va(ap_wake_info->ap_wake_block +
+ ap_wake_info->ap_jmp_offset);
+
+ *ap_jmp_ptr = real_mode_header->sl_trampoline_start32;
+
+ pr_info("TXT AP startup vector address updated\n");
+}
+
+/*
+ * Intel TXT specific late stub setup and validation called from within
+ * x86 specific setup_arch().
+ */
+void __init slaunch_setup_txt(void)
+{
+ u64 one = TXT_REGVALUE_ONE, val;
+ void __iomem *txt;
+
+ if (!boot_cpu_has(X86_FEATURE_SMX))
+ return;
+
+ /*
+ * If booted through secure launch entry point, the loadflags
+ * option will be set.
+ */
+ if (!(boot_params.hdr.loadflags & SLAUNCH_FLAG))
+ return;
+
+ /*
+ * See if SENTER was done by reading the status register in the
+ * public space. If the public register space cannot be read, TXT may
+ * be disabled.
+ */
+ txt = early_ioremap(TXT_PUB_CONFIG_REGS_BASE,
+ TXT_NR_CONFIG_PAGES * PAGE_SIZE);
+ if (!txt)
+ panic("Error early_ioremap in TXT setup failed\n");
+
+ memcpy_fromio(&val, txt + TXT_CR_STS, sizeof(val));
+ early_iounmap(txt, TXT_NR_CONFIG_PAGES * PAGE_SIZE);
+
+ /* SENTER should have been done */
+ if (!(val & TXT_SENTER_DONE_STS))
+ panic("Error TXT.STS SENTER_DONE not set\n");
+
+ /* SEXIT should have been cleared */
+ if (val & TXT_SEXIT_DONE_STS)
+ panic("Error TXT.STS SEXIT_DONE set\n");
+
+ /* Now we want to use the private register space */
+ txt = early_ioremap(TXT_PRIV_CONFIG_REGS_BASE,
+ TXT_NR_CONFIG_PAGES * PAGE_SIZE);
+ if (!txt) {
+ /* This is really bad, no where to go from here */
+ panic("Error early_ioremap of TXT priv registers\n");
+ }
+
+ /*
+ * Try to read the Intel VID from the TXT private registers to see if
+ * TXT measured launch happened properly and the private space is
+ * available.
+ */
+ memcpy_fromio(&val, txt + TXT_CR_DIDVID, sizeof(val));
+ if ((val & 0xffff) != 0x8086) {
+ /*
+ * Can't do a proper TXT reset since it appears something is
+ * wrong even though SENTER happened and it should be in SMX
+ * mode.
+ */
+ panic("Invalid TXT vendor ID, not in SMX mode\n");
+ }
+
+ /* Set flags so subsequent code knows the status of the launch */
+ sl_flags |= (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT);
+
+ /*
+ * Reading the proper DIDVID from the private register space means we
+ * are in SMX mode and private registers are open for read/write.
+ */
+
+ /* On Intel, have to handle TPM localities via TXT */
+ memcpy_toio(txt + TXT_CR_CMD_SECRETS, &one, sizeof(one));
+ memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(val));
+ memcpy_toio(txt + TXT_CR_CMD_OPEN_LOCALITY1, &one, sizeof(one));
+ memcpy_fromio(&val, txt + TXT_CR_E2STS, sizeof(val));
+
+ slaunch_fetch_values(txt);
+
+ slaunch_verify_pmrs(txt);
+
+ slaunch_txt_reserve(txt);
+
+ slaunch_copy_dmar_table(txt);
+
+ early_iounmap(txt, TXT_NR_CONFIG_PAGES * PAGE_SIZE);
+
+ pr_info("Intel TXT setup complete\n");
+}
diff --git a/drivers/iommu/intel/dmar.c b/drivers/iommu/intel/dmar.c
index 36d7427b1202..4b185c3f8f4c 100644
--- a/drivers/iommu/intel/dmar.c
+++ b/drivers/iommu/intel/dmar.c
@@ -28,6 +28,7 @@
#include <linux/iommu.h>
#include <linux/numa.h>
#include <linux/limits.h>
+#include <linux/slaunch.h>
#include <asm/irq_remapping.h>
#include "iommu.h"
@@ -660,6 +661,9 @@ parse_dmar_table(void)
*/
dmar_tbl = tboot_get_dmar_table(dmar_tbl);
+ /* If Secure Launch is active, it has similar logic */
+ dmar_tbl = slaunch_get_dmar_table(dmar_tbl);
+
dmar = (struct acpi_table_dmar *)dmar_tbl;
if (!dmar)
return -ENODEV;
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-05-31 1:03 ` [PATCH v9 09/19] x86: Secure Launch kernel late " Ross Philipson
@ 2024-06-04 19:58 ` Jarkko Sakkinen
2024-06-04 21:16 ` ross.philipson
2024-06-04 19:59 ` Jarkko Sakkinen
1 sibling, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 19:58 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> The routine slaunch_setup is called out of the x86 specific setup_arch()
> routine during early kernel boot. After determining what platform is
> present, various operations specific to that platform occur. This
> includes finalizing setting for the platform late launch and verifying
> that memory protections are in place.
"memory protections" is not too helpful tbh.
Better to describe very briefly the VT-d usage.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-06-04 19:58 ` Jarkko Sakkinen
@ 2024-06-04 21:16 ` ross.philipson
2024-06-04 22:45 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:16 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 12:58 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> The routine slaunch_setup is called out of the x86 specific setup_arch()
>> routine during early kernel boot. After determining what platform is
>> present, various operations specific to that platform occur. This
>> includes finalizing setting for the platform late launch and verifying
>> that memory protections are in place.
>
> "memory protections" is not too helpful tbh.
>
> Better to describe very briefly the VT-d usage.
We can enhance the commit message and talk about VT-d usage and what
PMRs are and do.
Thanks
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-06-04 21:16 ` ross.philipson
@ 2024-06-04 22:45 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:45 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 12:16 AM EEST, wrote:
> On 6/4/24 12:58 PM, Jarkko Sakkinen wrote:
> > On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >> The routine slaunch_setup is called out of the x86 specific setup_arch()
> >> routine during early kernel boot. After determining what platform is
> >> present, various operations specific to that platform occur. This
> >> includes finalizing setting for the platform late launch and verifying
> >> that memory protections are in place.
> >
> > "memory protections" is not too helpful tbh.
> >
> > Better to describe very briefly the VT-d usage.
>
> We can enhance the commit message and talk about VT-d usage and what
> PMRs are and do.
Yep, pointing out exact things that you're dealing with is even more
useful once the feature has landed.
After some months one tends to start forgetting things, so it is good
to use commit messages as clues and reminders of essential concepts.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-05-31 1:03 ` [PATCH v9 09/19] x86: Secure Launch kernel late " Ross Philipson
2024-06-04 19:58 ` Jarkko Sakkinen
@ 2024-06-04 19:59 ` Jarkko Sakkinen
2024-06-04 21:17 ` ross.philipson
2024-08-12 19:02 ` ross.philipson
1 sibling, 2 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 19:59 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> The routine slaunch_setup is called out of the x86 specific setup_arch()
> routine during early kernel boot. After determining what platform is
> present, various operations specific to that platform occur. This
> includes finalizing setting for the platform late launch and verifying
> that memory protections are in place.
>
> For TXT, this code also reserves the original compressed kernel setup
> area where the APs were left looping so that this memory cannot be used.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> arch/x86/kernel/Makefile | 1 +
> arch/x86/kernel/setup.c | 3 +
> arch/x86/kernel/slaunch.c | 525 +++++++++++++++++++++++++++++++++++++
> drivers/iommu/intel/dmar.c | 4 +
> 4 files changed, 533 insertions(+)
> create mode 100644 arch/x86/kernel/slaunch.c
>
> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> index 5d128167e2e2..b35ca99ab0a0 100644
> --- a/arch/x86/kernel/Makefile
> +++ b/arch/x86/kernel/Makefile
> @@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o
> obj-$(CONFIG_IA32_EMULATION) += tls.o
> obj-y += step.o
> obj-$(CONFIG_INTEL_TXT) += tboot.o
> +obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
Hmm... should that be CONFIG_X86_SECURE_LAUNCH?
Just asking...
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-06-04 19:59 ` Jarkko Sakkinen
@ 2024-06-04 21:17 ` ross.philipson
2024-08-12 19:02 ` ross.philipson
1 sibling, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:17 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 12:59 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> The routine slaunch_setup is called out of the x86 specific setup_arch()
>> routine during early kernel boot. After determining what platform is
>> present, various operations specific to that platform occur. This
>> includes finalizing setting for the platform late launch and verifying
>> that memory protections are in place.
>>
>> For TXT, this code also reserves the original compressed kernel setup
>> area where the APs were left looping so that this memory cannot be used.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> arch/x86/kernel/Makefile | 1 +
>> arch/x86/kernel/setup.c | 3 +
>> arch/x86/kernel/slaunch.c | 525 +++++++++++++++++++++++++++++++++++++
>> drivers/iommu/intel/dmar.c | 4 +
>> 4 files changed, 533 insertions(+)
>> create mode 100644 arch/x86/kernel/slaunch.c
>>
>> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
>> index 5d128167e2e2..b35ca99ab0a0 100644
>> --- a/arch/x86/kernel/Makefile
>> +++ b/arch/x86/kernel/Makefile
>> @@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o
>> obj-$(CONFIG_IA32_EMULATION) += tls.o
>> obj-y += step.o
>> obj-$(CONFIG_INTEL_TXT) += tboot.o
>> +obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
>
> Hmm... should that be CONFIG_X86_SECURE_LAUNCH?
>
> Just asking...
It could be if you would like. I guess we just thought it was implied
given its location.
Ross
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-06-04 19:59 ` Jarkko Sakkinen
2024-06-04 21:17 ` ross.philipson
@ 2024-08-12 19:02 ` ross.philipson
2024-08-15 18:35 ` Jarkko Sakkinen
1 sibling, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-08-12 19:02 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On 6/4/24 3:59 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> The routine slaunch_setup is called out of the x86 specific setup_arch()
>> routine during early kernel boot. After determining what platform is
>> present, various operations specific to that platform occur. This
>> includes finalizing setting for the platform late launch and verifying
>> that memory protections are in place.
>>
>> For TXT, this code also reserves the original compressed kernel setup
>> area where the APs were left looping so that this memory cannot be used.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> arch/x86/kernel/Makefile | 1 +
>> arch/x86/kernel/setup.c | 3 +
>> arch/x86/kernel/slaunch.c | 525 +++++++++++++++++++++++++++++++++++++
>> drivers/iommu/intel/dmar.c | 4 +
>> 4 files changed, 533 insertions(+)
>> create mode 100644 arch/x86/kernel/slaunch.c
>>
>> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
>> index 5d128167e2e2..b35ca99ab0a0 100644
>> --- a/arch/x86/kernel/Makefile
>> +++ b/arch/x86/kernel/Makefile
>> @@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o
>> obj-$(CONFIG_IA32_EMULATION) += tls.o
>> obj-y += step.o
>> obj-$(CONFIG_INTEL_TXT) += tboot.o
>> +obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
>
> Hmm... should that be CONFIG_X86_SECURE_LAUNCH?
Further thoughts on this after discussions...
The Secure Launch feature will cover other architectures beyond x86 in
the future. We may have to rework/move the config settings at that point
but for now I don't think we want to change it.
Thanks
Ross
>
> Just asking...
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* Re: [PATCH v9 09/19] x86: Secure Launch kernel late boot stub
2024-08-12 19:02 ` ross.philipson
@ 2024-08-15 18:35 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-08-15 18:35 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Mon Aug 12, 2024 at 10:02 PM EEST, wrote:
> On 6/4/24 3:59 PM, Jarkko Sakkinen wrote:
> > On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >> The routine slaunch_setup is called out of the x86 specific setup_arch()
> >> routine during early kernel boot. After determining what platform is
> >> present, various operations specific to that platform occur. This
> >> includes finalizing setting for the platform late launch and verifying
> >> that memory protections are in place.
> >>
> >> For TXT, this code also reserves the original compressed kernel setup
> >> area where the APs were left looping so that this memory cannot be used.
> >>
> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >> ---
> >> arch/x86/kernel/Makefile | 1 +
> >> arch/x86/kernel/setup.c | 3 +
> >> arch/x86/kernel/slaunch.c | 525 +++++++++++++++++++++++++++++++++++++
> >> drivers/iommu/intel/dmar.c | 4 +
> >> 4 files changed, 533 insertions(+)
> >> create mode 100644 arch/x86/kernel/slaunch.c
> >>
> >> diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
> >> index 5d128167e2e2..b35ca99ab0a0 100644
> >> --- a/arch/x86/kernel/Makefile
> >> +++ b/arch/x86/kernel/Makefile
> >> @@ -76,6 +76,7 @@ obj-$(CONFIG_X86_32) += tls.o
> >> obj-$(CONFIG_IA32_EMULATION) += tls.o
> >> obj-y += step.o
> >> obj-$(CONFIG_INTEL_TXT) += tboot.o
> >> +obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
> >
> > Hmm... should that be CONFIG_X86_SECURE_LAUNCH?
>
> Further thoughts on this after discussions...
>
> The Secure Launch feature will cover other architectures beyond x86 in
> the future. We may have to rework/move the config settings at that point
> but for now I don't think we want to change it.
OK got it.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 10/19] x86: Secure Launch SMP bringup support
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (8 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 09/19] x86: Secure Launch kernel late " Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 20:05 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 11/19] kexec: Secure Launch kexec SEXIT support Ross Philipson
` (8 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
On Intel, the APs are left in a well documented state after TXT performs
the late launch. Specifically they cannot have #INIT asserted on them so
a standard startup via INIT/SIPI/SIPI cannot be performed. Instead the
early SL stub code uses MONITOR and MWAIT to park the APs. The realmode/init.c
code updates the jump address for the waiting APs with the location of the
Secure Launch entry point in the RM piggy after it is loaded and fixed up.
As the APs are woken up by writing the monitor, the APs jump to the Secure
Launch entry point in the RM piggy which mimics what the real mode code would
do then jumps to the standard RM piggy protected mode entry point.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/include/asm/realmode.h | 3 ++
arch/x86/kernel/smpboot.c | 58 +++++++++++++++++++++++++++-
arch/x86/realmode/init.c | 3 ++
| 3 ++
arch/x86/realmode/rm/trampoline_64.S | 32 +++++++++++++++
5 files changed, 97 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
index 87e5482acd0d..339b48e2543d 100644
--- a/arch/x86/include/asm/realmode.h
+++ b/arch/x86/include/asm/realmode.h
@@ -38,6 +38,9 @@ struct real_mode_header {
#ifdef CONFIG_X86_64
u32 machine_real_restart_seg;
#endif
+#ifdef CONFIG_SECURE_LAUNCH
+ u32 sl_trampoline_start32;
+#endif
};
/* This must match data at realmode/rm/trampoline_{32,64}.S */
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 0c35207320cb..adb521221d6c 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -60,6 +60,7 @@
#include <linux/stackprotector.h>
#include <linux/cpuhotplug.h>
#include <linux/mc146818rtc.h>
+#include <linux/slaunch.h>
#include <asm/acpi.h>
#include <asm/cacheinfo.h>
@@ -868,6 +869,56 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
return 0;
}
+#ifdef CONFIG_SECURE_LAUNCH
+
+static bool slaunch_is_txt_launch(void)
+{
+ if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) ==
+ (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
+ return true;
+
+ return false;
+}
+
+/*
+ * TXT AP startup is quite different than normal. The APs cannot have #INIT
+ * asserted on them or receive SIPIs. The early Secure Launch code has parked
+ * the APs using monitor/mwait. This will wake the APs by writing the monitor
+ * and have them jump to the protected mode code in the rmpiggy where the rest
+ * of the SMP boot of the AP will proceed normally.
+ */
+static void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
+{
+ struct sl_ap_wake_info *ap_wake_info;
+ struct sl_ap_stack_and_monitor *stack_monitor = NULL;
+
+ ap_wake_info = slaunch_get_ap_wake_info();
+
+ stack_monitor = (struct sl_ap_stack_and_monitor *)__va(ap_wake_info->ap_wake_block +
+ ap_wake_info->ap_stacks_offset);
+
+ for (unsigned int i = TXT_MAX_CPUS - 1; i >= 0; i--) {
+ if (stack_monitor[i].apicid == apicid) {
+ /* Write the monitor */
+ stack_monitor[i].monitor = 1;
+ break;
+ }
+ }
+}
+
+#else
+
+static inline bool slaunch_is_txt_launch(void)
+{
+ return false;
+}
+
+static inline void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
+{
+}
+
+#endif /* !CONFIG_SECURE_LAUNCH */
+
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
* (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -877,7 +928,7 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
{
unsigned long start_ip = real_mode_header->trampoline_start;
- int ret;
+ int ret = 0;
#ifdef CONFIG_X86_64
/* If 64-bit wakeup method exists, use the 64-bit mode trampoline IP */
@@ -922,12 +973,15 @@ static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
/*
* Wake up a CPU in difference cases:
+ * - Intel TXT DRTM launch uses its own method to wake the APs
* - Use a method from the APIC driver if one defined, with wakeup
* straight to 64-bit mode preferred over wakeup to RM.
* Otherwise,
* - Use an INIT boot APIC message
*/
- if (apic->wakeup_secondary_cpu_64)
+ if (slaunch_is_txt_launch())
+ slaunch_wakeup_cpu_from_txt(cpu, apicid);
+ else if (apic->wakeup_secondary_cpu_64)
ret = apic->wakeup_secondary_cpu_64(apicid, start_ip);
else if (apic->wakeup_secondary_cpu)
ret = apic->wakeup_secondary_cpu(apicid, start_ip);
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
index f9bc444a3064..d95776cb30d3 100644
--- a/arch/x86/realmode/init.c
+++ b/arch/x86/realmode/init.c
@@ -4,6 +4,7 @@
#include <linux/memblock.h>
#include <linux/cc_platform.h>
#include <linux/pgtable.h>
+#include <linux/slaunch.h>
#include <asm/set_memory.h>
#include <asm/realmode.h>
@@ -210,6 +211,8 @@ void __init init_real_mode(void)
setup_real_mode();
set_real_mode_permissions();
+
+ slaunch_fixup_jump_vector();
}
static int __init do_init_real_mode(void)
--git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 2eb62be6d256..3b5cbcbbfc90 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -37,6 +37,9 @@ SYM_DATA_START(real_mode_header)
#ifdef CONFIG_X86_64
.long __KERNEL32_CS
#endif
+#ifdef CONFIG_SECURE_LAUNCH
+ .long pa_sl_trampoline_start32
+#endif
SYM_DATA_END(real_mode_header)
/* End signature, used to verify integrity */
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
index 14d9c7daf90f..b0ce6205d7ea 100644
--- a/arch/x86/realmode/rm/trampoline_64.S
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -122,6 +122,38 @@ SYM_CODE_END(sev_es_trampoline_start)
.section ".text32","ax"
.code32
+#ifdef CONFIG_SECURE_LAUNCH
+ .balign 4
+SYM_CODE_START(sl_trampoline_start32)
+ /*
+ * The early secure launch stub AP wakeup code has taken care of all
+ * the vagaries of launching out of TXT. This bit just mimics what the
+ * 16b entry code does and jumps off to the real startup_32.
+ */
+ cli
+ wbinvd
+
+ /*
+ * The %ebx provided is not terribly useful since it is the physical
+ * address of tb_trampoline_start and not the base of the image.
+ * Use pa_real_mode_base, which is fixed up, to get a run time
+ * base register to use for offsets to location that do not have
+ * pa_ symbols.
+ */
+ movl $pa_real_mode_base, %ebx
+
+ LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
+
+ lgdt tr_gdt(%ebx)
+ lidt tr_idt(%ebx)
+
+ movw $__KERNEL_DS, %dx # Data segment descriptor
+
+ /* Jump to where the 16b code would have jumped */
+ ljmpl $__KERNEL32_CS, $pa_startup_32
+SYM_CODE_END(sl_trampoline_start32)
+#endif
+
.balign 4
SYM_CODE_START(startup_32)
movl %edx, %ss
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 10/19] x86: Secure Launch SMP bringup support
2024-05-31 1:03 ` [PATCH v9 10/19] x86: Secure Launch SMP bringup support Ross Philipson
@ 2024-06-04 20:05 ` Jarkko Sakkinen
2024-06-04 21:47 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 20:05 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> On Intel, the APs are left in a well documented state after TXT performs
> the late launch. Specifically they cannot have #INIT asserted on them so
> a standard startup via INIT/SIPI/SIPI cannot be performed. Instead the
> early SL stub code uses MONITOR and MWAIT to park the APs. The realmode/init.c
> code updates the jump address for the waiting APs with the location of the
> Secure Launch entry point in the RM piggy after it is loaded and fixed up.
> As the APs are woken up by writing the monitor, the APs jump to the Secure
> Launch entry point in the RM piggy which mimics what the real mode code would
> do then jumps to the standard RM piggy protected mode entry point.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> arch/x86/include/asm/realmode.h | 3 ++
> arch/x86/kernel/smpboot.c | 58 +++++++++++++++++++++++++++-
> arch/x86/realmode/init.c | 3 ++
> arch/x86/realmode/rm/header.S | 3 ++
> arch/x86/realmode/rm/trampoline_64.S | 32 +++++++++++++++
> 5 files changed, 97 insertions(+), 2 deletions(-)
>
> diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
> index 87e5482acd0d..339b48e2543d 100644
> --- a/arch/x86/include/asm/realmode.h
> +++ b/arch/x86/include/asm/realmode.h
> @@ -38,6 +38,9 @@ struct real_mode_header {
> #ifdef CONFIG_X86_64
> u32 machine_real_restart_seg;
> #endif
> +#ifdef CONFIG_SECURE_LAUNCH
> + u32 sl_trampoline_start32;
> +#endif
> };
>
> /* This must match data at realmode/rm/trampoline_{32,64}.S */
> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
> index 0c35207320cb..adb521221d6c 100644
> --- a/arch/x86/kernel/smpboot.c
> +++ b/arch/x86/kernel/smpboot.c
> @@ -60,6 +60,7 @@
> #include <linux/stackprotector.h>
> #include <linux/cpuhotplug.h>
> #include <linux/mc146818rtc.h>
> +#include <linux/slaunch.h>
>
> #include <asm/acpi.h>
> #include <asm/cacheinfo.h>
> @@ -868,6 +869,56 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
> return 0;
> }
>
> +#ifdef CONFIG_SECURE_LAUNCH
> +
> +static bool slaunch_is_txt_launch(void)
> +{
> + if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) ==
> + (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
> + return true;
> +
> + return false;
> +}
static inline bool slaunch_is_txt_launch(void)
{
u32 mask = SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT;
return slaunch_get_flags() & mask == mask;
}
> +
> +/*
> + * TXT AP startup is quite different than normal. The APs cannot have #INIT
> + * asserted on them or receive SIPIs. The early Secure Launch code has parked
> + * the APs using monitor/mwait. This will wake the APs by writing the monitor
> + * and have them jump to the protected mode code in the rmpiggy where the rest
> + * of the SMP boot of the AP will proceed normally.
> + */
> +static void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
> +{
> + struct sl_ap_wake_info *ap_wake_info;
> + struct sl_ap_stack_and_monitor *stack_monitor = NULL;
struct sl_ap_stack_and_monitor *stack_monitor; /* note: no initialization */
struct sl_ap_wake_info *ap_wake_info;
> +
> + ap_wake_info = slaunch_get_ap_wake_info();
> +
> + stack_monitor = (struct sl_ap_stack_and_monitor *)__va(ap_wake_info->ap_wake_block +
> + ap_wake_info->ap_stacks_offset);
> +
> + for (unsigned int i = TXT_MAX_CPUS - 1; i >= 0; i--) {
> + if (stack_monitor[i].apicid == apicid) {
> + /* Write the monitor */
I'd remove this comment.
> + stack_monitor[i].monitor = 1;
> + break;
> + }
> + }
> +}
> +
> +#else
> +
> +static inline bool slaunch_is_txt_launch(void)
> +{
> + return false;
> +}
> +
> +static inline void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
> +{
> +}
> +
> +#endif /* !CONFIG_SECURE_LAUNCH */
> +
> /*
> * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
> * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
> @@ -877,7 +928,7 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
> static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
> {
> unsigned long start_ip = real_mode_header->trampoline_start;
> - int ret;
> + int ret = 0;
>
> #ifdef CONFIG_X86_64
> /* If 64-bit wakeup method exists, use the 64-bit mode trampoline IP */
> @@ -922,12 +973,15 @@ static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
>
> /*
> * Wake up a CPU in difference cases:
> + * - Intel TXT DRTM launch uses its own method to wake the APs
> * - Use a method from the APIC driver if one defined, with wakeup
> * straight to 64-bit mode preferred over wakeup to RM.
> * Otherwise,
> * - Use an INIT boot APIC message
> */
> - if (apic->wakeup_secondary_cpu_64)
> + if (slaunch_is_txt_launch())
> + slaunch_wakeup_cpu_from_txt(cpu, apicid);
> + else if (apic->wakeup_secondary_cpu_64)
> ret = apic->wakeup_secondary_cpu_64(apicid, start_ip);
> else if (apic->wakeup_secondary_cpu)
> ret = apic->wakeup_secondary_cpu(apicid, start_ip);
> diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
> index f9bc444a3064..d95776cb30d3 100644
> --- a/arch/x86/realmode/init.c
> +++ b/arch/x86/realmode/init.c
> @@ -4,6 +4,7 @@
> #include <linux/memblock.h>
> #include <linux/cc_platform.h>
> #include <linux/pgtable.h>
> +#include <linux/slaunch.h>
>
> #include <asm/set_memory.h>
> #include <asm/realmode.h>
> @@ -210,6 +211,8 @@ void __init init_real_mode(void)
>
> setup_real_mode();
> set_real_mode_permissions();
> +
> + slaunch_fixup_jump_vector();
> }
>
> static int __init do_init_real_mode(void)
> diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
> index 2eb62be6d256..3b5cbcbbfc90 100644
> --- a/arch/x86/realmode/rm/header.S
> +++ b/arch/x86/realmode/rm/header.S
> @@ -37,6 +37,9 @@ SYM_DATA_START(real_mode_header)
> #ifdef CONFIG_X86_64
> .long __KERNEL32_CS
> #endif
> +#ifdef CONFIG_SECURE_LAUNCH
> + .long pa_sl_trampoline_start32
> +#endif
> SYM_DATA_END(real_mode_header)
>
> /* End signature, used to verify integrity */
> diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
> index 14d9c7daf90f..b0ce6205d7ea 100644
> --- a/arch/x86/realmode/rm/trampoline_64.S
> +++ b/arch/x86/realmode/rm/trampoline_64.S
> @@ -122,6 +122,38 @@ SYM_CODE_END(sev_es_trampoline_start)
>
> .section ".text32","ax"
> .code32
> +#ifdef CONFIG_SECURE_LAUNCH
> + .balign 4
> +SYM_CODE_START(sl_trampoline_start32)
> + /*
> + * The early secure launch stub AP wakeup code has taken care of all
> + * the vagaries of launching out of TXT. This bit just mimics what the
> + * 16b entry code does and jumps off to the real startup_32.
> + */
> + cli
> + wbinvd
> +
> + /*
> + * The %ebx provided is not terribly useful since it is the physical
> + * address of tb_trampoline_start and not the base of the image.
> + * Use pa_real_mode_base, which is fixed up, to get a run time
> + * base register to use for offsets to location that do not have
> + * pa_ symbols.
> + */
> + movl $pa_real_mode_base, %ebx
> +
> + LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
> +
> + lgdt tr_gdt(%ebx)
> + lidt tr_idt(%ebx)
> +
> + movw $__KERNEL_DS, %dx # Data segment descriptor
> +
> + /* Jump to where the 16b code would have jumped */
> + ljmpl $__KERNEL32_CS, $pa_startup_32
> +SYM_CODE_END(sl_trampoline_start32)
> +#endif
> +
> .balign 4
> SYM_CODE_START(startup_32)
> movl %edx, %ss
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 10/19] x86: Secure Launch SMP bringup support
2024-06-04 20:05 ` Jarkko Sakkinen
@ 2024-06-04 21:47 ` ross.philipson
2024-06-04 22:46 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 21:47 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 1:05 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> On Intel, the APs are left in a well documented state after TXT performs
>> the late launch. Specifically they cannot have #INIT asserted on them so
>> a standard startup via INIT/SIPI/SIPI cannot be performed. Instead the
>> early SL stub code uses MONITOR and MWAIT to park the APs. The realmode/init.c
>> code updates the jump address for the waiting APs with the location of the
>> Secure Launch entry point in the RM piggy after it is loaded and fixed up.
>> As the APs are woken up by writing the monitor, the APs jump to the Secure
>> Launch entry point in the RM piggy which mimics what the real mode code would
>> do then jumps to the standard RM piggy protected mode entry point.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> arch/x86/include/asm/realmode.h | 3 ++
>> arch/x86/kernel/smpboot.c | 58 +++++++++++++++++++++++++++-
>> arch/x86/realmode/init.c | 3 ++
>> arch/x86/realmode/rm/header.S | 3 ++
>> arch/x86/realmode/rm/trampoline_64.S | 32 +++++++++++++++
>> 5 files changed, 97 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h
>> index 87e5482acd0d..339b48e2543d 100644
>> --- a/arch/x86/include/asm/realmode.h
>> +++ b/arch/x86/include/asm/realmode.h
>> @@ -38,6 +38,9 @@ struct real_mode_header {
>> #ifdef CONFIG_X86_64
>> u32 machine_real_restart_seg;
>> #endif
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + u32 sl_trampoline_start32;
>> +#endif
>> };
>>
>> /* This must match data at realmode/rm/trampoline_{32,64}.S */
>> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
>> index 0c35207320cb..adb521221d6c 100644
>> --- a/arch/x86/kernel/smpboot.c
>> +++ b/arch/x86/kernel/smpboot.c
>> @@ -60,6 +60,7 @@
>> #include <linux/stackprotector.h>
>> #include <linux/cpuhotplug.h>
>> #include <linux/mc146818rtc.h>
>> +#include <linux/slaunch.h>
>>
>> #include <asm/acpi.h>
>> #include <asm/cacheinfo.h>
>> @@ -868,6 +869,56 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
>> return 0;
>> }
>>
>> +#ifdef CONFIG_SECURE_LAUNCH
>> +
>> +static bool slaunch_is_txt_launch(void)
>> +{
>> + if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) ==
>> + (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
>> + return true;
>> +
>> + return false;
>> +}
>
> static inline bool slaunch_is_txt_launch(void)
> {
> u32 mask = SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT;
>
> return slaunch_get_flags() & mask == mask;
> }
Actually I think I can take your suggested change and move this function
to the main header files since this check is done elsewhere. And later I
can make others like slaunch_is_skinit_launch(). Thanks.
>
>
>> +
>> +/*
>> + * TXT AP startup is quite different than normal. The APs cannot have #INIT
>> + * asserted on them or receive SIPIs. The early Secure Launch code has parked
>> + * the APs using monitor/mwait. This will wake the APs by writing the monitor
>> + * and have them jump to the protected mode code in the rmpiggy where the rest
>> + * of the SMP boot of the AP will proceed normally.
>> + */
>> +static void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
>> +{
>> + struct sl_ap_wake_info *ap_wake_info;
>> + struct sl_ap_stack_and_monitor *stack_monitor = NULL;
>
> struct sl_ap_stack_and_monitor *stack_monitor; /* note: no initialization */
> struct sl_ap_wake_info *ap_wake_info;
Will fix.
>
>
>> +
>> + ap_wake_info = slaunch_get_ap_wake_info();
>> +
>> + stack_monitor = (struct sl_ap_stack_and_monitor *)__va(ap_wake_info->ap_wake_block +
>> + ap_wake_info->ap_stacks_offset);
>> +
>> + for (unsigned int i = TXT_MAX_CPUS - 1; i >= 0; i--) {
>> + if (stack_monitor[i].apicid == apicid) {
>> + /* Write the monitor */
>
> I'd remove this comment.
Sure.
Ross
>
>> + stack_monitor[i].monitor = 1;
>> + break;
>> + }
>> + }
>> +}
>> +
>> +#else
>> +
>> +static inline bool slaunch_is_txt_launch(void)
>> +{
>> + return false;
>> +}
>> +
>> +static inline void slaunch_wakeup_cpu_from_txt(int cpu, int apicid)
>> +{
>> +}
>> +
>> +#endif /* !CONFIG_SECURE_LAUNCH */
>> +
>> /*
>> * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
>> * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
>> @@ -877,7 +928,7 @@ int common_cpu_up(unsigned int cpu, struct task_struct *idle)
>> static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
>> {
>> unsigned long start_ip = real_mode_header->trampoline_start;
>> - int ret;
>> + int ret = 0;
>>
>> #ifdef CONFIG_X86_64
>> /* If 64-bit wakeup method exists, use the 64-bit mode trampoline IP */
>> @@ -922,12 +973,15 @@ static int do_boot_cpu(u32 apicid, int cpu, struct task_struct *idle)
>>
>> /*
>> * Wake up a CPU in difference cases:
>> + * - Intel TXT DRTM launch uses its own method to wake the APs
>> * - Use a method from the APIC driver if one defined, with wakeup
>> * straight to 64-bit mode preferred over wakeup to RM.
>> * Otherwise,
>> * - Use an INIT boot APIC message
>> */
>> - if (apic->wakeup_secondary_cpu_64)
>> + if (slaunch_is_txt_launch())
>> + slaunch_wakeup_cpu_from_txt(cpu, apicid);
>> + else if (apic->wakeup_secondary_cpu_64)
>> ret = apic->wakeup_secondary_cpu_64(apicid, start_ip);
>> else if (apic->wakeup_secondary_cpu)
>> ret = apic->wakeup_secondary_cpu(apicid, start_ip);
>> diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c
>> index f9bc444a3064..d95776cb30d3 100644
>> --- a/arch/x86/realmode/init.c
>> +++ b/arch/x86/realmode/init.c
>> @@ -4,6 +4,7 @@
>> #include <linux/memblock.h>
>> #include <linux/cc_platform.h>
>> #include <linux/pgtable.h>
>> +#include <linux/slaunch.h>
>>
>> #include <asm/set_memory.h>
>> #include <asm/realmode.h>
>> @@ -210,6 +211,8 @@ void __init init_real_mode(void)
>>
>> setup_real_mode();
>> set_real_mode_permissions();
>> +
>> + slaunch_fixup_jump_vector();
>> }
>>
>> static int __init do_init_real_mode(void)
>> diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
>> index 2eb62be6d256..3b5cbcbbfc90 100644
>> --- a/arch/x86/realmode/rm/header.S
>> +++ b/arch/x86/realmode/rm/header.S
>> @@ -37,6 +37,9 @@ SYM_DATA_START(real_mode_header)
>> #ifdef CONFIG_X86_64
>> .long __KERNEL32_CS
>> #endif
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + .long pa_sl_trampoline_start32
>> +#endif
>> SYM_DATA_END(real_mode_header)
>>
>> /* End signature, used to verify integrity */
>> diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
>> index 14d9c7daf90f..b0ce6205d7ea 100644
>> --- a/arch/x86/realmode/rm/trampoline_64.S
>> +++ b/arch/x86/realmode/rm/trampoline_64.S
>> @@ -122,6 +122,38 @@ SYM_CODE_END(sev_es_trampoline_start)
>>
>> .section ".text32","ax"
>> .code32
>> +#ifdef CONFIG_SECURE_LAUNCH
>> + .balign 4
>> +SYM_CODE_START(sl_trampoline_start32)
>> + /*
>> + * The early secure launch stub AP wakeup code has taken care of all
>> + * the vagaries of launching out of TXT. This bit just mimics what the
>> + * 16b entry code does and jumps off to the real startup_32.
>> + */
>> + cli
>> + wbinvd
>> +
>> + /*
>> + * The %ebx provided is not terribly useful since it is the physical
>> + * address of tb_trampoline_start and not the base of the image.
>> + * Use pa_real_mode_base, which is fixed up, to get a run time
>> + * base register to use for offsets to location that do not have
>> + * pa_ symbols.
>> + */
>> + movl $pa_real_mode_base, %ebx
>> +
>> + LOCK_AND_LOAD_REALMODE_ESP lock_pa=1
>> +
>> + lgdt tr_gdt(%ebx)
>> + lidt tr_idt(%ebx)
>> +
>> + movw $__KERNEL_DS, %dx # Data segment descriptor
>> +
>> + /* Jump to where the 16b code would have jumped */
>> + ljmpl $__KERNEL32_CS, $pa_startup_32
>> +SYM_CODE_END(sl_trampoline_start32)
>> +#endif
>> +
>> .balign 4
>> SYM_CODE_START(startup_32)
>> movl %edx, %ss
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 10/19] x86: Secure Launch SMP bringup support
2024-06-04 21:47 ` ross.philipson
@ 2024-06-04 22:46 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:46 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 12:47 AM EEST, wrote:
> > static inline bool slaunch_is_txt_launch(void)
> > {
> > u32 mask = SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT;
> >
> > return slaunch_get_flags() & mask == mask;
> > }
>
> Actually I think I can take your suggested change and move this function
> to the main header files since this check is done elsewhere. And later I
> can make others like slaunch_is_skinit_launch(). Thanks.
Yep, makes sense to me.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 11/19] kexec: Secure Launch kexec SEXIT support
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (9 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 10/19] x86: Secure Launch SMP bringup support Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 12/19] reboot: Secure Launch SEXIT support on reboot paths Ross Philipson
` (7 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Prior to running the next kernel via kexec, the Secure Launch code
closes down private SMX resources and does an SEXIT. This allows the
next kernel to start normally without any issues starting the APs etc.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/kernel/slaunch.c | 73 +++++++++++++++++++++++++++++++++++++++
kernel/kexec_core.c | 4 +++
2 files changed, 77 insertions(+)
diff --git a/arch/x86/kernel/slaunch.c b/arch/x86/kernel/slaunch.c
index 48c9ca78e241..f35b4ba433fa 100644
--- a/arch/x86/kernel/slaunch.c
+++ b/arch/x86/kernel/slaunch.c
@@ -523,3 +523,76 @@ void __init slaunch_setup_txt(void)
pr_info("Intel TXT setup complete\n");
}
+
+static inline void smx_getsec_sexit(void)
+{
+ asm volatile ("getsec\n"
+ : : "a" (SMX_X86_GETSEC_SEXIT));
+}
+
+/*
+ * Used during kexec and on reboot paths to finalize the TXT state
+ * and do an SEXIT exiting the DRTM and disabling SMX mode.
+ */
+void slaunch_finalize(int do_sexit)
+{
+ u64 one = TXT_REGVALUE_ONE, val;
+ void __iomem *config;
+
+ if ((slaunch_get_flags() & (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT)) !=
+ (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
+ return;
+
+ config = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES *
+ PAGE_SIZE);
+ if (!config) {
+ pr_emerg("Error SEXIT failed to ioremap TXT private reqs\n");
+ return;
+ }
+
+ /* Clear secrets bit for SEXIT */
+ memcpy_toio(config + TXT_CR_CMD_NO_SECRETS, &one, sizeof(one));
+ memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(val));
+
+ /* Unlock memory configurations */
+ memcpy_toio(config + TXT_CR_CMD_UNLOCK_MEM_CONFIG, &one, sizeof(one));
+ memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(val));
+
+ /* Close the TXT private register space */
+ memcpy_toio(config + TXT_CR_CMD_CLOSE_PRIVATE, &one, sizeof(one));
+ memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(val));
+
+ /*
+ * Calls to iounmap are not being done because of the state of the
+ * system this late in the kexec process. Local IRQs are disabled and
+ * iounmap causes a TLB flush which in turn causes a warning. Leaving
+ * thse mappings is not an issue since the next kernel is going to
+ * completely re-setup memory management.
+ */
+
+ /* Map public registers and do a final read fence */
+ config = ioremap(TXT_PUB_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES *
+ PAGE_SIZE);
+ if (!config) {
+ pr_emerg("Error SEXIT failed to ioremap TXT public reqs\n");
+ return;
+ }
+
+ memcpy_fromio(&val, config + TXT_CR_E2STS, sizeof(val));
+
+ pr_emerg("TXT clear secrets bit and unlock memory complete.\n");
+
+ if (!do_sexit)
+ return;
+
+ if (smp_processor_id() != 0)
+ panic("Error TXT SEXIT must be called on CPU 0\n");
+
+ /* In case SMX mode was disabled, enable it for SEXIT */
+ cr4_set_bits(X86_CR4_SMXE);
+
+ /* Do the SEXIT SMX operation */
+ smx_getsec_sexit();
+
+ pr_info("TXT SEXIT complete.\n");
+}
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 0e96f6b24344..ba2fd1c0ddd9 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -40,6 +40,7 @@
#include <linux/hugetlb.h>
#include <linux/objtool.h>
#include <linux/kmsg_dump.h>
+#include <linux/slaunch.h>
#include <asm/page.h>
#include <asm/sections.h>
@@ -1046,6 +1047,9 @@ int kernel_kexec(void)
cpu_hotplug_enable();
pr_notice("Starting new kernel\n");
machine_shutdown();
+
+ /* Finalize TXT registers and do SEXIT */
+ slaunch_finalize(1);
}
kmsg_dump(KMSG_DUMP_SHUTDOWN);
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 12/19] reboot: Secure Launch SEXIT support on reboot paths
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (10 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 11/19] kexec: Secure Launch kexec SEXIT support Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 13/19] tpm: Protect against locality counter underflow Ross Philipson
` (6 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
If the MLE kernel is being powered off, rebooted or halted,
then SEXIT must be called. Note that the SEXIT GETSEC leaf
can only be called after a machine_shutdown() has been done on
these paths. The machine_shutdown() is not called on a few paths
like when poweroff action does not have a poweroff callback (into
ACPI code) or when an emergency reset is done. In these cases,
just the TXT registers are finalized but SEXIT is skipped.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/kernel/reboot.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index f3130f762784..66060fdb0822 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/objtool.h>
#include <linux/pgtable.h>
+#include <linux/slaunch.h>
#include <acpi/reboot.h>
#include <asm/io.h>
#include <asm/apic.h>
@@ -766,6 +767,7 @@ static void native_machine_restart(char *__unused)
if (!reboot_force)
machine_shutdown();
+ slaunch_finalize(!reboot_force);
__machine_emergency_restart(0);
}
@@ -776,6 +778,9 @@ static void native_machine_halt(void)
tboot_shutdown(TB_SHUTDOWN_HALT);
+ /* SEXIT done after machine_shutdown() to meet TXT requirements */
+ slaunch_finalize(1);
+
stop_this_cpu(NULL);
}
@@ -784,8 +789,12 @@ static void native_machine_power_off(void)
if (kernel_can_power_off()) {
if (!reboot_force)
machine_shutdown();
+ slaunch_finalize(!reboot_force);
do_kernel_power_off();
+ } else {
+ slaunch_finalize(0);
}
+
/* A fallback in case there is no PM info available */
tboot_shutdown(TB_SHUTDOWN_HALT);
}
@@ -813,6 +822,7 @@ void machine_shutdown(void)
void machine_emergency_restart(void)
{
+ slaunch_finalize(0);
__machine_emergency_restart(1);
}
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 13/19] tpm: Protect against locality counter underflow
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (11 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 12/19] reboot: Secure Launch SEXIT support on reboot paths Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 20:12 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup Ross Philipson
` (5 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
Commit 933bfc5ad213 introduced the use of a locality counter to control when a
locality request is allowed to be sent to the TPM. In the commit, the counter
is indiscriminately decremented. Thus creating a situation for an integer
underflow of the counter.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com>
Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality")
---
drivers/char/tpm/tpm_tis_core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 176cd8dbf1db..7c1761bd6000 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
mutex_lock(&priv->locality_count_mutex);
- priv->locality_count--;
+ if (priv->locality_count > 0)
+ priv->locality_count--;
if (priv->locality_count == 0)
__tpm_tis_relinquish_locality(priv, l);
mutex_unlock(&priv->locality_count_mutex);
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 13/19] tpm: Protect against locality counter underflow
2024-05-31 1:03 ` [PATCH v9 13/19] tpm: Protect against locality counter underflow Ross Philipson
@ 2024-06-04 20:12 ` Jarkko Sakkinen
2024-08-15 18:52 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 20:12 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> Commit 933bfc5ad213 introduced the use of a locality counter to control when a
> locality request is allowed to be sent to the TPM. In the commit, the counter
> is indiscriminately decremented. Thus creating a situation for an integer
> underflow of the counter.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com>
> Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality")
Not sure if we have practical use for fixes tag here but open for
argument ofc. I.e. I'm not sure what is the practical scenario to
worry about if Trenchboot did not exist.
> ---
> drivers/char/tpm/tpm_tis_core.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
> index 176cd8dbf1db..7c1761bd6000 100644
> --- a/drivers/char/tpm/tpm_tis_core.c
> +++ b/drivers/char/tpm/tpm_tis_core.c
> @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
>
> mutex_lock(&priv->locality_count_mutex);
> - priv->locality_count--;
> + if (priv->locality_count > 0)
> + priv->locality_count--;
I'd signal the situation with pr_info() in else branch.
> if (priv->locality_count == 0)
> __tpm_tis_relinquish_locality(priv, l);
> mutex_unlock(&priv->locality_count_mutex);
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 13/19] tpm: Protect against locality counter underflow
2024-06-04 20:12 ` Jarkko Sakkinen
@ 2024-08-15 18:52 ` Daniel P. Smith
0 siblings, 0 replies; 113+ messages in thread
From: Daniel P. Smith @ 2024-08-15 18:52 UTC (permalink / raw)
To: Jarkko Sakkinen, Ross Philipson, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu
Cc: tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, ebiederm,
dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 6/4/24 16:12, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> Commit 933bfc5ad213 introduced the use of a locality counter to control when a
>> locality request is allowed to be sent to the TPM. In the commit, the counter
>> is indiscriminately decremented. Thus creating a situation for an integer
>> underflow of the counter.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> Reported-by: Kanth Ghatraju <kanth.ghatraju@oracle.com>
>> Fixes: 933bfc5ad213 ("tpm, tpm: Implement usage counter for locality")
>
> Not sure if we have practical use for fixes tag here but open for
> argument ofc. I.e. I'm not sure what is the practical scenario to
> worry about if Trenchboot did not exist.
We can drop the fixes line.
>> ---
>> drivers/char/tpm/tpm_tis_core.c | 3 ++-
>> 1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
>> index 176cd8dbf1db..7c1761bd6000 100644
>> --- a/drivers/char/tpm/tpm_tis_core.c
>> +++ b/drivers/char/tpm/tpm_tis_core.c
>> @@ -180,7 +180,8 @@ static int tpm_tis_relinquish_locality(struct tpm_chip *chip, int l)
>> struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
>>
>> mutex_lock(&priv->locality_count_mutex);
>> - priv->locality_count--;
>> + if (priv->locality_count > 0)
>> + priv->locality_count--;
>
> I'd signal the situation with pr_info() in else branch.
Ack.
>> if (priv->locality_count == 0)
>> __tpm_tis_relinquish_locality(priv, l);
>> mutex_unlock(&priv->locality_count_mutex);
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (12 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 13/19] tpm: Protect against locality counter underflow Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 20:14 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 15/19] tpm: Make locality requests return consistent values Ross Philipson
` (4 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
When tis core initializes, it assumes all localities are closed. There
are cases when this may not be the case. This commit addresses this by
ensuring all localities are closed before initializing begins.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
include/linux/tpm.h | 6 ++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 7c1761bd6000..9fb53bb3e73f 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -1104,7 +1104,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
u32 intmask;
u32 clkrun_val;
u8 rid;
- int rc, probe;
+ int rc, probe, i;
struct tpm_chip *chip;
chip = tpmm_chip_alloc(dev, &tpm_tis);
@@ -1166,6 +1166,15 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
goto out_err;
}
+ /*
+ * There are environments, like Intel TXT, that may leave a TPM
+ * locality open. Close all localities to start from a known state.
+ */
+ for (i = 0; i <= TPM_MAX_LOCALITY; i++) {
+ if (check_locality(chip, i))
+ tpm_tis_relinquish_locality(chip, i);
+ }
+
/* Take control of the TPM's interrupt hardware and shut it off */
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
if (rc < 0)
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index c17e4efbb2e5..363f7078c3a9 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -147,6 +147,12 @@ struct tpm_chip_seqops {
*/
#define TPM2_MAX_CONTEXT_SIZE 4096
+/*
+ * The maximum locality (0 - 4) for a TPM, as defined in section 3.2 of the
+ * Client Platform Profile Specification.
+ */
+#define TPM_MAX_LOCALITY 4
+
struct tpm_chip {
struct device dev;
struct device devs;
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup
2024-05-31 1:03 ` [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup Ross Philipson
@ 2024-06-04 20:14 ` Jarkko Sakkinen
2024-08-15 19:24 ` Daniel P. Smith
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 20:14 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>
> When tis core initializes, it assumes all localities are closed. There
s/tis_core/tpm_tis_core/
> are cases when this may not be the case. This commit addresses this by
> ensuring all localities are closed before initializing begins.
>
> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
> include/linux/tpm.h | 6 ++++++
> 2 files changed, 16 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
> index 7c1761bd6000..9fb53bb3e73f 100644
> --- a/drivers/char/tpm/tpm_tis_core.c
> +++ b/drivers/char/tpm/tpm_tis_core.c
> @@ -1104,7 +1104,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
> u32 intmask;
> u32 clkrun_val;
> u8 rid;
> - int rc, probe;
> + int rc, probe, i;
> struct tpm_chip *chip;
>
> chip = tpmm_chip_alloc(dev, &tpm_tis);
> @@ -1166,6 +1166,15 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
> goto out_err;
> }
>
> + /*
> + * There are environments, like Intel TXT, that may leave a TPM
What else at this point than Intel TXT reflecting the state of the
mainline?
> + * locality open. Close all localities to start from a known state.
> + */
> + for (i = 0; i <= TPM_MAX_LOCALITY; i++) {
> + if (check_locality(chip, i))
> + tpm_tis_relinquish_locality(chip, i);
> + }
To be strict this should be enabled only for x86 platforms.
I.e. should be flagged.
> +
> /* Take control of the TPM's interrupt hardware and shut it off */
> rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
> if (rc < 0)
> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
> index c17e4efbb2e5..363f7078c3a9 100644
> --- a/include/linux/tpm.h
> +++ b/include/linux/tpm.h
> @@ -147,6 +147,12 @@ struct tpm_chip_seqops {
> */
> #define TPM2_MAX_CONTEXT_SIZE 4096
>
> +/*
> + * The maximum locality (0 - 4) for a TPM, as defined in section 3.2 of the
> + * Client Platform Profile Specification.
> + */
> +#define TPM_MAX_LOCALITY 4
> +
> struct tpm_chip {
> struct device dev;
> struct device devs;
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup
2024-06-04 20:14 ` Jarkko Sakkinen
@ 2024-08-15 19:24 ` Daniel P. Smith
0 siblings, 0 replies; 113+ messages in thread
From: Daniel P. Smith @ 2024-08-15 19:24 UTC (permalink / raw)
To: Jarkko Sakkinen, Ross Philipson, linux-kernel, x86,
linux-integrity, linux-doc, linux-crypto, kexec, linux-efi, iommu
Cc: tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59, James.Bottomley,
peterhuewe, jgg, luto, nivedita, herbert, davem, corbet, ebiederm,
dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3, trenchboot-devel
On 6/4/24 16:14, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
>>
>> When tis core initializes, it assumes all localities are closed. There
>
> s/tis_core/tpm_tis_core/
Ack.
>> are cases when this may not be the case. This commit addresses this by
>> ensuring all localities are closed before initializing begins.
>>
>> Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> drivers/char/tpm/tpm_tis_core.c | 11 ++++++++++-
>> include/linux/tpm.h | 6 ++++++
>> 2 files changed, 16 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
>> index 7c1761bd6000..9fb53bb3e73f 100644
>> --- a/drivers/char/tpm/tpm_tis_core.c
>> +++ b/drivers/char/tpm/tpm_tis_core.c
>> @@ -1104,7 +1104,7 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
>> u32 intmask;
>> u32 clkrun_val;
>> u8 rid;
>> - int rc, probe;
>> + int rc, probe, i;
>> struct tpm_chip *chip;
>>
>> chip = tpmm_chip_alloc(dev, &tpm_tis);
>> @@ -1166,6 +1166,15 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
>> goto out_err;
>> }
>>
>> + /*
>> + * There are environments, like Intel TXT, that may leave a TPM
>
> What else at this point than Intel TXT reflecting the state of the
> mainline?
Leaving the TPM in Locality 2 is a requirement of the TCG D-RTM
specification. This will be the situation for AMD and Arm as well. The
comment can be updated to ref the TCG spec instead of a specific
implementation.
>> + * locality open. Close all localities to start from a known state.
>> + */
>> + for (i = 0; i <= TPM_MAX_LOCALITY; i++) {
>> + if (check_locality(chip, i))
>> + tpm_tis_relinquish_locality(chip, i);
>> + }
>
> To be strict this should be enabled only for x86 platforms.
>
> I.e. should be flagged.
As mentioned above, this will also affect Arm.
>> +
>> /* Take control of the TPM's interrupt hardware and shut it off */
>> rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
>> if (rc < 0)
>> diff --git a/include/linux/tpm.h b/include/linux/tpm.h
>> index c17e4efbb2e5..363f7078c3a9 100644
>> --- a/include/linux/tpm.h
>> +++ b/include/linux/tpm.h
>> @@ -147,6 +147,12 @@ struct tpm_chip_seqops {
>> */
>> #define TPM2_MAX_CONTEXT_SIZE 4096
>>
>> +/*
>> + * The maximum locality (0 - 4) for a TPM, as defined in section 3.2 of the
>> + * Client Platform Profile Specification.
>> + */
>> +#define TPM_MAX_LOCALITY 4
>> +
>> struct tpm_chip {
>> struct device dev;
>> struct device devs;
>
>
> BR, Jarkko
v/r,
dps
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 15/19] tpm: Make locality requests return consistent values
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (13 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 14/19] tpm: Ensure tpm is in known state at startup Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses Ross Philipson
` (3 subsequent siblings)
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
The function tpm_tis_request_locality() is expected to return the locality
value that was requested, or a negative error code upon failure. If it is called
while locality_count of struct tis_data is non-zero, no actual locality request
will be sent. Because the ret variable is initially set to 0, the
locality_count will still get increased, and the function will return 0. For a
caller, this would indicate that locality 0 was successfully requested and not
the state changes just mentioned.
Additionally, the function __tpm_tis_request_locality() provides inconsistent
error codes. It will provide either a failed IO write or a -1 should it have
timed out waiting for locality request to succeed.
This commit changes __tpm_tis_request_locality() to return valid negative error
codes to reflect the reason it fails. It then adjusts the return value check in
tpm_tis_request_locality() to check for a non-negative return value before
incrementing locality_cout. In addition, the initial value of the ret value is
set to a negative error to ensure the check does not pass if
__tpm_tis_request_locality() is not called.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
drivers/char/tpm/tpm_tis_core.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 9fb53bb3e73f..685bdeadec51 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -208,7 +208,7 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l)
again:
timeout = stop - jiffies;
if ((long)timeout <= 0)
- return -1;
+ return -EBUSY;
rc = wait_event_interruptible_timeout(priv->int_queue,
(check_locality
(chip, l)),
@@ -227,18 +227,21 @@ static int __tpm_tis_request_locality(struct tpm_chip *chip, int l)
tpm_msleep(TPM_TIMEOUT);
} while (time_before(jiffies, stop));
}
- return -1;
+ return -EBUSY;
}
static int tpm_tis_request_locality(struct tpm_chip *chip, int l)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
- int ret = 0;
+ int ret = -EBUSY;
+
+ if (l < 0 || l > TPM_MAX_LOCALITY)
+ return -EINVAL;
mutex_lock(&priv->locality_count_mutex);
if (priv->locality_count == 0)
ret = __tpm_tis_request_locality(chip, l);
- if (!ret)
+ if (ret >= 0)
priv->locality_count++;
mutex_unlock(&priv->locality_count_mutex);
return ret;
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (14 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 15/19] tpm: Make locality requests return consistent values Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 20:27 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 17/19] tpm: Add sysfs interface to allow setting and querying the preferred locality Ross Philipson
` (2 subsequent siblings)
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Curently the locality is hard coded to 0 but for DRTM support, access
is needed to localities 1 through 4.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
drivers/char/tpm/tpm-chip.c | 24 +++++++++++++++++++++++-
drivers/char/tpm/tpm-interface.c | 15 +++++++++++++++
drivers/char/tpm/tpm.h | 1 +
include/linux/tpm.h | 4 ++++
4 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 854546000c92..73eac54d61fb 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -44,7 +44,7 @@ static int tpm_request_locality(struct tpm_chip *chip)
if (!chip->ops->request_locality)
return 0;
- rc = chip->ops->request_locality(chip, 0);
+ rc = chip->ops->request_locality(chip, chip->pref_locality);
if (rc < 0)
return rc;
@@ -143,6 +143,27 @@ void tpm_chip_stop(struct tpm_chip *chip)
}
EXPORT_SYMBOL_GPL(tpm_chip_stop);
+/**
+ * tpm_chip_preferred_locality() - set the TPM chip preferred locality to open
+ * @chip: a TPM chip to use
+ * @locality: the preferred locality
+ *
+ * Return:
+ * * true - Preferred locality set
+ * * false - Invalid locality specified
+ */
+bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality)
+{
+ if (locality < 0 || locality >=TPM_MAX_LOCALITY)
+ return false;
+
+ mutex_lock(&chip->tpm_mutex);
+ chip->pref_locality = locality;
+ mutex_unlock(&chip->tpm_mutex);
+ return true;
+}
+EXPORT_SYMBOL_GPL(tpm_chip_preferred_locality);
+
/**
* tpm_try_get_ops() - Get a ref to the tpm_chip
* @chip: Chip to ref
@@ -374,6 +395,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
}
chip->locality = -1;
+ chip->pref_locality = 0;
return chip;
out:
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 5da134f12c9a..35f14ccecf0e 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -274,6 +274,21 @@ int tpm_is_tpm2(struct tpm_chip *chip)
}
EXPORT_SYMBOL_GPL(tpm_is_tpm2);
+/**
+ * tpm_preferred_locality() - set the TPM chip preferred locality to open
+ * @chip: a TPM chip to use
+ * @locality: the preferred locality
+ *
+ * Return:
+ * * true - Preferred locality set
+ * * false - Invalid locality specified
+ */
+bool tpm_preferred_locality(struct tpm_chip *chip, int locality)
+{
+ return tpm_chip_preferred_locality(chip, locality);
+}
+EXPORT_SYMBOL_GPL(tpm_preferred_locality);
+
/**
* tpm_pcr_read - read a PCR value from SHA1 bank
* @chip: a &struct tpm_chip instance, %NULL for the default chip
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index 6b8b9956ba69..be465422d3fa 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -267,6 +267,7 @@ static inline void tpm_msleep(unsigned int delay_msec)
int tpm_chip_bootstrap(struct tpm_chip *chip);
int tpm_chip_start(struct tpm_chip *chip);
void tpm_chip_stop(struct tpm_chip *chip);
+bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality);
struct tpm_chip *tpm_find_get_ops(struct tpm_chip *chip);
struct tpm_chip *tpm_chip_alloc(struct device *dev,
diff --git a/include/linux/tpm.h b/include/linux/tpm.h
index 363f7078c3a9..935a3457d7c8 100644
--- a/include/linux/tpm.h
+++ b/include/linux/tpm.h
@@ -219,6 +219,9 @@ struct tpm_chip {
u8 null_ec_key_y[EC_PT_SZ];
struct tpm2_auth *auth;
#endif
+
+ /* preferred locality - default 0 */
+ int pref_locality;
};
#define TPM_HEADER_SIZE 10
@@ -461,6 +464,7 @@ static inline u32 tpm2_rc_value(u32 rc)
#if defined(CONFIG_TCG_TPM) || defined(CONFIG_TCG_TPM_MODULE)
extern int tpm_is_tpm2(struct tpm_chip *chip);
+extern bool tpm_preferred_locality(struct tpm_chip *chip, int locality);
extern __must_check int tpm_try_get_ops(struct tpm_chip *chip);
extern void tpm_put_ops(struct tpm_chip *chip);
extern ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_buf *buf,
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses
2024-05-31 1:03 ` [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses Ross Philipson
@ 2024-06-04 20:27 ` Jarkko Sakkinen
2024-06-04 22:14 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 20:27 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> Curently the locality is hard coded to 0 but for DRTM support, access
> is needed to localities 1 through 4.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> drivers/char/tpm/tpm-chip.c | 24 +++++++++++++++++++++++-
> drivers/char/tpm/tpm-interface.c | 15 +++++++++++++++
> drivers/char/tpm/tpm.h | 1 +
> include/linux/tpm.h | 4 ++++
> 4 files changed, 43 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> index 854546000c92..73eac54d61fb 100644
> --- a/drivers/char/tpm/tpm-chip.c
> +++ b/drivers/char/tpm/tpm-chip.c
> @@ -44,7 +44,7 @@ static int tpm_request_locality(struct tpm_chip *chip)
> if (!chip->ops->request_locality)
> return 0;
>
> - rc = chip->ops->request_locality(chip, 0);
> + rc = chip->ops->request_locality(chip, chip->pref_locality);
> if (rc < 0)
> return rc;
>
> @@ -143,6 +143,27 @@ void tpm_chip_stop(struct tpm_chip *chip)
> }
> EXPORT_SYMBOL_GPL(tpm_chip_stop);
>
> +/**
> + * tpm_chip_preferred_locality() - set the TPM chip preferred locality to open
> + * @chip: a TPM chip to use
> + * @locality: the preferred locality
> + *
> + * Return:
> + * * true - Preferred locality set
> + * * false - Invalid locality specified
> + */
> +bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality)
> +{
> + if (locality < 0 || locality >=TPM_MAX_LOCALITY)
> + return false;
> +
> + mutex_lock(&chip->tpm_mutex);
> + chip->pref_locality = locality;
> + mutex_unlock(&chip->tpm_mutex);
> + return true;
> +}
> +EXPORT_SYMBOL_GPL(tpm_chip_preferred_locality);
> +
> /**
> * tpm_try_get_ops() - Get a ref to the tpm_chip
> * @chip: Chip to ref
> @@ -374,6 +395,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
> }
>
> chip->locality = -1;
> + chip->pref_locality = 0;
> return chip;
>
> out:
> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> index 5da134f12c9a..35f14ccecf0e 100644
> --- a/drivers/char/tpm/tpm-interface.c
> +++ b/drivers/char/tpm/tpm-interface.c
> @@ -274,6 +274,21 @@ int tpm_is_tpm2(struct tpm_chip *chip)
> }
> EXPORT_SYMBOL_GPL(tpm_is_tpm2);
>
> +/**
> + * tpm_preferred_locality() - set the TPM chip preferred locality to open
> + * @chip: a TPM chip to use
> + * @locality: the preferred locality
> + *
> + * Return:
> + * * true - Preferred locality set
> + * * false - Invalid locality specified
> + */
> +bool tpm_preferred_locality(struct tpm_chip *chip, int locality)
> +{
> + return tpm_chip_preferred_locality(chip, locality);
> +}
> +EXPORT_SYMBOL_GPL(tpm_preferred_locality);
What good does this extra wrapping do?
tpm_set_default_locality() and default_locality would make so much more
sense in any case.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses
2024-06-04 20:27 ` Jarkko Sakkinen
@ 2024-06-04 22:14 ` ross.philipson
2024-06-04 22:50 ` Jarkko Sakkinen
0 siblings, 1 reply; 113+ messages in thread
From: ross.philipson @ 2024-06-04 22:14 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 1:27 PM, Jarkko Sakkinen wrote:
> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>> Curently the locality is hard coded to 0 but for DRTM support, access
>> is needed to localities 1 through 4.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>> ---
>> drivers/char/tpm/tpm-chip.c | 24 +++++++++++++++++++++++-
>> drivers/char/tpm/tpm-interface.c | 15 +++++++++++++++
>> drivers/char/tpm/tpm.h | 1 +
>> include/linux/tpm.h | 4 ++++
>> 4 files changed, 43 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
>> index 854546000c92..73eac54d61fb 100644
>> --- a/drivers/char/tpm/tpm-chip.c
>> +++ b/drivers/char/tpm/tpm-chip.c
>> @@ -44,7 +44,7 @@ static int tpm_request_locality(struct tpm_chip *chip)
>> if (!chip->ops->request_locality)
>> return 0;
>>
>> - rc = chip->ops->request_locality(chip, 0);
>> + rc = chip->ops->request_locality(chip, chip->pref_locality);
>> if (rc < 0)
>> return rc;
>>
>> @@ -143,6 +143,27 @@ void tpm_chip_stop(struct tpm_chip *chip)
>> }
>> EXPORT_SYMBOL_GPL(tpm_chip_stop);
>>
>> +/**
>> + * tpm_chip_preferred_locality() - set the TPM chip preferred locality to open
>> + * @chip: a TPM chip to use
>> + * @locality: the preferred locality
>> + *
>> + * Return:
>> + * * true - Preferred locality set
>> + * * false - Invalid locality specified
>> + */
>> +bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality)
>> +{
>> + if (locality < 0 || locality >=TPM_MAX_LOCALITY)
>> + return false;
>> +
>> + mutex_lock(&chip->tpm_mutex);
>> + chip->pref_locality = locality;
>> + mutex_unlock(&chip->tpm_mutex);
>> + return true;
>> +}
>> +EXPORT_SYMBOL_GPL(tpm_chip_preferred_locality);
>> +
>> /**
>> * tpm_try_get_ops() - Get a ref to the tpm_chip
>> * @chip: Chip to ref
>> @@ -374,6 +395,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>> }
>>
>> chip->locality = -1;
>> + chip->pref_locality = 0;
>> return chip;
>>
>> out:
>> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>> index 5da134f12c9a..35f14ccecf0e 100644
>> --- a/drivers/char/tpm/tpm-interface.c
>> +++ b/drivers/char/tpm/tpm-interface.c
>> @@ -274,6 +274,21 @@ int tpm_is_tpm2(struct tpm_chip *chip)
>> }
>> EXPORT_SYMBOL_GPL(tpm_is_tpm2);
>>
>> +/**
>> + * tpm_preferred_locality() - set the TPM chip preferred locality to open
>> + * @chip: a TPM chip to use
>> + * @locality: the preferred locality
>> + *
>> + * Return:
>> + * * true - Preferred locality set
>> + * * false - Invalid locality specified
>> + */
>> +bool tpm_preferred_locality(struct tpm_chip *chip, int locality)
>> +{
>> + return tpm_chip_preferred_locality(chip, locality);
>> +}
>> +EXPORT_SYMBOL_GPL(tpm_preferred_locality);
>
> What good does this extra wrapping do?
>
> tpm_set_default_locality() and default_locality would make so much more
> sense in any case.
Are you mainly just talking about my naming choices here and in the
follow-on response? Can you clarify what you are requesting?
Thanks
Ross
>
> BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses
2024-06-04 22:14 ` ross.philipson
@ 2024-06-04 22:50 ` Jarkko Sakkinen
2024-06-04 23:04 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 22:50 UTC (permalink / raw)
To: ross.philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Wed Jun 5, 2024 at 1:14 AM EEST, wrote:
> On 6/4/24 1:27 PM, Jarkko Sakkinen wrote:
> > On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> >> Curently the locality is hard coded to 0 but for DRTM support, access
> >> is needed to localities 1 through 4.
> >>
> >> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> >> ---
> >> drivers/char/tpm/tpm-chip.c | 24 +++++++++++++++++++++++-
> >> drivers/char/tpm/tpm-interface.c | 15 +++++++++++++++
> >> drivers/char/tpm/tpm.h | 1 +
> >> include/linux/tpm.h | 4 ++++
> >> 4 files changed, 43 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
> >> index 854546000c92..73eac54d61fb 100644
> >> --- a/drivers/char/tpm/tpm-chip.c
> >> +++ b/drivers/char/tpm/tpm-chip.c
> >> @@ -44,7 +44,7 @@ static int tpm_request_locality(struct tpm_chip *chip)
> >> if (!chip->ops->request_locality)
> >> return 0;
> >>
> >> - rc = chip->ops->request_locality(chip, 0);
> >> + rc = chip->ops->request_locality(chip, chip->pref_locality);
> >> if (rc < 0)
> >> return rc;
> >>
> >> @@ -143,6 +143,27 @@ void tpm_chip_stop(struct tpm_chip *chip)
> >> }
> >> EXPORT_SYMBOL_GPL(tpm_chip_stop);
> >>
> >> +/**
> >> + * tpm_chip_preferred_locality() - set the TPM chip preferred locality to open
> >> + * @chip: a TPM chip to use
> >> + * @locality: the preferred locality
> >> + *
> >> + * Return:
> >> + * * true - Preferred locality set
> >> + * * false - Invalid locality specified
> >> + */
> >> +bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality)
> >> +{
> >> + if (locality < 0 || locality >=TPM_MAX_LOCALITY)
> >> + return false;
> >> +
> >> + mutex_lock(&chip->tpm_mutex);
> >> + chip->pref_locality = locality;
> >> + mutex_unlock(&chip->tpm_mutex);
> >> + return true;
> >> +}
> >> +EXPORT_SYMBOL_GPL(tpm_chip_preferred_locality);
> >> +
> >> /**
> >> * tpm_try_get_ops() - Get a ref to the tpm_chip
> >> * @chip: Chip to ref
> >> @@ -374,6 +395,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
> >> }
> >>
> >> chip->locality = -1;
> >> + chip->pref_locality = 0;
> >> return chip;
> >>
> >> out:
> >> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
> >> index 5da134f12c9a..35f14ccecf0e 100644
> >> --- a/drivers/char/tpm/tpm-interface.c
> >> +++ b/drivers/char/tpm/tpm-interface.c
> >> @@ -274,6 +274,21 @@ int tpm_is_tpm2(struct tpm_chip *chip)
> >> }
> >> EXPORT_SYMBOL_GPL(tpm_is_tpm2);
> >>
> >> +/**
> >> + * tpm_preferred_locality() - set the TPM chip preferred locality to open
> >> + * @chip: a TPM chip to use
> >> + * @locality: the preferred locality
> >> + *
> >> + * Return:
> >> + * * true - Preferred locality set
> >> + * * false - Invalid locality specified
> >> + */
> >> +bool tpm_preferred_locality(struct tpm_chip *chip, int locality)
> >> +{
> >> + return tpm_chip_preferred_locality(chip, locality);
> >> +}
> >> +EXPORT_SYMBOL_GPL(tpm_preferred_locality);
> >
> > What good does this extra wrapping do?
> >
> > tpm_set_default_locality() and default_locality would make so much more
> > sense in any case.
>
> Are you mainly just talking about my naming choices here and in the
> follow-on response? Can you clarify what you are requesting?
I'd prefer:
1. Name the variable as default_locality.
2. Only create a single expored to function to tpm-chip.c:
tpm_chip_set_default_locality().
3. Call this function in all call sites.
"tpm_preferred_locality" should be just removed, as tpm_chip_*
is exported anyway.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses
2024-06-04 22:50 ` Jarkko Sakkinen
@ 2024-06-04 23:04 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 23:04 UTC (permalink / raw)
To: Jarkko Sakkinen, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel, ross.philipson
On 6/4/24 3:50 PM, Jarkko Sakkinen wrote:
> On Wed Jun 5, 2024 at 1:14 AM EEST, wrote:
>> On 6/4/24 1:27 PM, Jarkko Sakkinen wrote:
>>> On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
>>>> Curently the locality is hard coded to 0 but for DRTM support, access
>>>> is needed to localities 1 through 4.
>>>>
>>>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>>>> ---
>>>> drivers/char/tpm/tpm-chip.c | 24 +++++++++++++++++++++++-
>>>> drivers/char/tpm/tpm-interface.c | 15 +++++++++++++++
>>>> drivers/char/tpm/tpm.h | 1 +
>>>> include/linux/tpm.h | 4 ++++
>>>> 4 files changed, 43 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
>>>> index 854546000c92..73eac54d61fb 100644
>>>> --- a/drivers/char/tpm/tpm-chip.c
>>>> +++ b/drivers/char/tpm/tpm-chip.c
>>>> @@ -44,7 +44,7 @@ static int tpm_request_locality(struct tpm_chip *chip)
>>>> if (!chip->ops->request_locality)
>>>> return 0;
>>>>
>>>> - rc = chip->ops->request_locality(chip, 0);
>>>> + rc = chip->ops->request_locality(chip, chip->pref_locality);
>>>> if (rc < 0)
>>>> return rc;
>>>>
>>>> @@ -143,6 +143,27 @@ void tpm_chip_stop(struct tpm_chip *chip)
>>>> }
>>>> EXPORT_SYMBOL_GPL(tpm_chip_stop);
>>>>
>>>> +/**
>>>> + * tpm_chip_preferred_locality() - set the TPM chip preferred locality to open
>>>> + * @chip: a TPM chip to use
>>>> + * @locality: the preferred locality
>>>> + *
>>>> + * Return:
>>>> + * * true - Preferred locality set
>>>> + * * false - Invalid locality specified
>>>> + */
>>>> +bool tpm_chip_preferred_locality(struct tpm_chip *chip, int locality)
>>>> +{
>>>> + if (locality < 0 || locality >=TPM_MAX_LOCALITY)
>>>> + return false;
>>>> +
>>>> + mutex_lock(&chip->tpm_mutex);
>>>> + chip->pref_locality = locality;
>>>> + mutex_unlock(&chip->tpm_mutex);
>>>> + return true;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tpm_chip_preferred_locality);
>>>> +
>>>> /**
>>>> * tpm_try_get_ops() - Get a ref to the tpm_chip
>>>> * @chip: Chip to ref
>>>> @@ -374,6 +395,7 @@ struct tpm_chip *tpm_chip_alloc(struct device *pdev,
>>>> }
>>>>
>>>> chip->locality = -1;
>>>> + chip->pref_locality = 0;
>>>> return chip;
>>>>
>>>> out:
>>>> diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
>>>> index 5da134f12c9a..35f14ccecf0e 100644
>>>> --- a/drivers/char/tpm/tpm-interface.c
>>>> +++ b/drivers/char/tpm/tpm-interface.c
>>>> @@ -274,6 +274,21 @@ int tpm_is_tpm2(struct tpm_chip *chip)
>>>> }
>>>> EXPORT_SYMBOL_GPL(tpm_is_tpm2);
>>>>
>>>> +/**
>>>> + * tpm_preferred_locality() - set the TPM chip preferred locality to open
>>>> + * @chip: a TPM chip to use
>>>> + * @locality: the preferred locality
>>>> + *
>>>> + * Return:
>>>> + * * true - Preferred locality set
>>>> + * * false - Invalid locality specified
>>>> + */
>>>> +bool tpm_preferred_locality(struct tpm_chip *chip, int locality)
>>>> +{
>>>> + return tpm_chip_preferred_locality(chip, locality);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(tpm_preferred_locality);
>>>
>>> What good does this extra wrapping do?
>>>
>>> tpm_set_default_locality() and default_locality would make so much more
>>> sense in any case.
>>
>> Are you mainly just talking about my naming choices here and in the
>> follow-on response? Can you clarify what you are requesting?
>
> I'd prefer:
>
> 1. Name the variable as default_locality.
> 2. Only create a single expored to function to tpm-chip.c:
> tpm_chip_set_default_locality().
> 3. Call this function in all call sites.
>
> "tpm_preferred_locality" should be just removed, as tpm_chip_*
> is exported anyway.
Ok got it, thanks.
>
> BR, Jarkko
>
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 17/19] tpm: Add sysfs interface to allow setting and querying the preferred locality
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (15 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 16/19] tpm: Add ability to set the preferred locality the TPM chip uses Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-06-04 20:27 ` Jarkko Sakkinen
2024-05-31 1:03 ` [PATCH v9 18/19] x86: Secure Launch late initcall platform module Ross Philipson
2024-05-31 1:03 ` [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch Ross Philipson
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
Expose a sysfs interface to allow user mode to set and query the preferred
locality for the TPM chip.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
drivers/char/tpm/tpm-sysfs.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 94231f052ea7..5f4a966a4599 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -324,6 +324,34 @@ static ssize_t null_name_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RO(null_name);
#endif
+static ssize_t preferred_locality_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct tpm_chip *chip = to_tpm_chip(dev);
+
+ return sprintf(buf, "%d\n", chip->pref_locality);
+}
+
+static ssize_t preferred_locality_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tpm_chip *chip = to_tpm_chip(dev);
+ unsigned int locality;
+
+ if (kstrtouint(buf, 0, &locality))
+ return -ERANGE;
+
+ if (locality >= TPM_MAX_LOCALITY)
+ return -ERANGE;
+
+ if (tpm_chip_preferred_locality(chip, (int)locality))
+ return count;
+ else
+ return 0;
+}
+
+static DEVICE_ATTR_RW(preferred_locality);
+
static struct attribute *tpm1_dev_attrs[] = {
&dev_attr_pubek.attr,
&dev_attr_pcrs.attr,
@@ -336,6 +364,7 @@ static struct attribute *tpm1_dev_attrs[] = {
&dev_attr_durations.attr,
&dev_attr_timeouts.attr,
&dev_attr_tpm_version_major.attr,
+ &dev_attr_preferred_locality.attr,
NULL,
};
@@ -344,6 +373,7 @@ static struct attribute *tpm2_dev_attrs[] = {
#ifdef CONFIG_TCG_TPM2_HMAC
&dev_attr_null_name.attr,
#endif
+ &dev_attr_preferred_locality.attr,
NULL
};
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 17/19] tpm: Add sysfs interface to allow setting and querying the preferred locality
2024-05-31 1:03 ` [PATCH v9 17/19] tpm: Add sysfs interface to allow setting and querying the preferred locality Ross Philipson
@ 2024-06-04 20:27 ` Jarkko Sakkinen
0 siblings, 0 replies; 113+ messages in thread
From: Jarkko Sakkinen @ 2024-06-04 20:27 UTC (permalink / raw)
To: Ross Philipson, linux-kernel, x86, linux-integrity, linux-doc,
linux-crypto, kexec, linux-efi, iommu
Cc: dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb, mjg59,
James.Bottomley, peterhuewe, jgg, luto, nivedita, herbert, davem,
corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju, andrew.cooper3,
trenchboot-devel
On Fri May 31, 2024 at 4:03 AM EEST, Ross Philipson wrote:
> Expose a sysfs interface to allow user mode to set and query the preferred
> locality for the TPM chip.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
> ---
> drivers/char/tpm/tpm-sysfs.c | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
>
> diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
> index 94231f052ea7..5f4a966a4599 100644
> --- a/drivers/char/tpm/tpm-sysfs.c
> +++ b/drivers/char/tpm/tpm-sysfs.c
> @@ -324,6 +324,34 @@ static ssize_t null_name_show(struct device *dev, struct device_attribute *attr,
> static DEVICE_ATTR_RO(null_name);
> #endif
>
> +static ssize_t preferred_locality_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct tpm_chip *chip = to_tpm_chip(dev);
> +
> + return sprintf(buf, "%d\n", chip->pref_locality);
> +}
Disagree with the naming.
BR, Jarkko
^ permalink raw reply [flat|nested] 113+ messages in thread
* [PATCH v9 18/19] x86: Secure Launch late initcall platform module
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (16 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 17/19] tpm: Add sysfs interface to allow setting and querying the preferred locality Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 1:03 ` [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch Ross Philipson
18 siblings, 0 replies; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
From: "Daniel P. Smith" <dpsmith@apertussolutions.com>
The Secure Launch platform module is a late init module. During the
init call, the TPM event log is read and measurements taken in the
early boot stub code are located. These measurements are extended
into the TPM PCRs using the mainline TPM kernel driver.
The platform module also registers the securityfs nodes to allow
access to TXT register fields on Intel along with the fetching of
and writing events to the late launch TPM log.
Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
Signed-off-by: garnetgrimm <grimmg@ainfosec.com>
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/slmodule.c | 513 +++++++++++++++++++++++++++++++++++++
2 files changed, 514 insertions(+)
create mode 100644 arch/x86/kernel/slmodule.c
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index b35ca99ab0a0..f2432c4a747a 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -77,6 +77,7 @@ obj-$(CONFIG_IA32_EMULATION) += tls.o
obj-y += step.o
obj-$(CONFIG_INTEL_TXT) += tboot.o
obj-$(CONFIG_SECURE_LAUNCH) += slaunch.o
+obj-$(CONFIG_SECURE_LAUNCH) += slmodule.o
obj-$(CONFIG_ISA_DMA_API) += i8237.o
obj-y += stacktrace.o
obj-y += cpu/
diff --git a/arch/x86/kernel/slmodule.c b/arch/x86/kernel/slmodule.c
new file mode 100644
index 000000000000..0e1354e3a914
--- /dev/null
+++ b/arch/x86/kernel/slmodule.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Secure Launch late validation/setup, securityfs exposure and finalization.
+ *
+ * Copyright (c) 2024 Apertus Solutions, LLC
+ * Copyright (c) 2024 Assured Information Security, Inc.
+ * Copyright (c) 2024, Oracle and/or its affiliates.
+ *
+ * Co-developed-by: Garnet T. Grimm <grimmg@ainfosec.com>
+ * Signed-off-by: Garnet T. Grimm <grimmg@ainfosec.com>
+ * Signed-off-by: Daniel P. Smith <dpsmith@apertussolutions.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/security.h>
+#include <linux/memblock.h>
+#include <linux/tpm.h>
+#include <asm/segment.h>
+#include <asm/sections.h>
+#include <crypto/sha2.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
+
+/*
+ * The macro DECLARE_TXT_PUB_READ_U is used to read values from the TXT
+ * public registers as unsigned values.
+ */
+#define DECLARE_TXT_PUB_READ_U(size, fmt, msg_size) \
+static ssize_t txt_pub_read_u##size(unsigned int offset, \
+ loff_t *read_offset, \
+ size_t read_len, \
+ char __user *buf) \
+{ \
+ char msg_buffer[msg_size]; \
+ u##size reg_value = 0; \
+ void __iomem *txt; \
+ \
+ txt = ioremap(TXT_PUB_CONFIG_REGS_BASE, \
+ TXT_NR_CONFIG_PAGES * PAGE_SIZE); \
+ if (!txt) \
+ return -EFAULT; \
+ memcpy_fromio(®_value, txt + offset, sizeof(u##size)); \
+ iounmap(txt); \
+ snprintf(msg_buffer, msg_size, fmt, reg_value); \
+ return simple_read_from_buffer(buf, read_len, read_offset, \
+ &msg_buffer, msg_size); \
+}
+
+DECLARE_TXT_PUB_READ_U(8, "%#04x\n", 6);
+DECLARE_TXT_PUB_READ_U(32, "%#010x\n", 12);
+DECLARE_TXT_PUB_READ_U(64, "%#018llx\n", 20);
+
+#define DECLARE_TXT_FOPS(reg_name, reg_offset, reg_size) \
+static ssize_t txt_##reg_name##_read(struct file *flip, \
+ char __user *buf, size_t read_len, loff_t *read_offset) \
+{ \
+ return txt_pub_read_u##reg_size(reg_offset, read_offset, \
+ read_len, buf); \
+} \
+static const struct file_operations reg_name##_ops = { \
+ .read = txt_##reg_name##_read, \
+}
+
+DECLARE_TXT_FOPS(sts, TXT_CR_STS, 64);
+DECLARE_TXT_FOPS(ests, TXT_CR_ESTS, 8);
+DECLARE_TXT_FOPS(errorcode, TXT_CR_ERRORCODE, 32);
+DECLARE_TXT_FOPS(didvid, TXT_CR_DIDVID, 64);
+DECLARE_TXT_FOPS(e2sts, TXT_CR_E2STS, 64);
+DECLARE_TXT_FOPS(ver_emif, TXT_CR_VER_EMIF, 32);
+DECLARE_TXT_FOPS(scratchpad, TXT_CR_SCRATCHPAD, 64);
+
+/*
+ * Securityfs exposure
+ */
+struct memfile {
+ char *name;
+ void *addr;
+ size_t size;
+};
+
+static struct memfile sl_evtlog = {"eventlog", NULL, 0};
+static void *txt_heap;
+static struct txt_heap_event_log_pointer2_1_element *evtlog20;
+static DEFINE_MUTEX(sl_evt_log_mutex);
+
+static ssize_t sl_evtlog_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ ssize_t size;
+
+ if (!sl_evtlog.addr)
+ return 0;
+
+ mutex_lock(&sl_evt_log_mutex);
+ size = simple_read_from_buffer(buf, count, pos, sl_evtlog.addr,
+ sl_evtlog.size);
+ mutex_unlock(&sl_evt_log_mutex);
+
+ return size;
+}
+
+static ssize_t sl_evtlog_write(struct file *file, const char __user *buf,
+ size_t datalen, loff_t *ppos)
+{
+ ssize_t result;
+ char *data;
+
+ if (!sl_evtlog.addr)
+ return 0;
+
+ /* No partial writes. */
+ result = -EINVAL;
+ if (*ppos != 0)
+ goto out;
+
+ data = memdup_user(buf, datalen);
+ if (IS_ERR(data)) {
+ result = PTR_ERR(data);
+ goto out;
+ }
+
+ mutex_lock(&sl_evt_log_mutex);
+ if (evtlog20)
+ result = tpm20_log_event(evtlog20, sl_evtlog.addr,
+ sl_evtlog.size, datalen, data);
+ else
+ result = tpm12_log_event(sl_evtlog.addr, sl_evtlog.size,
+ datalen, data);
+ mutex_unlock(&sl_evt_log_mutex);
+
+ kfree(data);
+out:
+ return result;
+}
+
+static const struct file_operations sl_evtlog_ops = {
+ .read = sl_evtlog_read,
+ .write = sl_evtlog_write,
+ .llseek = default_llseek,
+};
+
+struct sfs_file {
+ const char *name;
+ const struct file_operations *fops;
+};
+
+#define SL_TXT_ENTRY_COUNT 7
+static const struct sfs_file sl_txt_files[] = {
+ { "sts", &sts_ops },
+ { "ests", &ests_ops },
+ { "errorcode", &errorcode_ops },
+ { "didvid", &didvid_ops },
+ { "ver_emif", &ver_emif_ops },
+ { "scratchpad", &scratchpad_ops },
+ { "e2sts", &e2sts_ops }
+};
+
+/* sysfs file handles */
+static struct dentry *slaunch_dir;
+static struct dentry *event_file;
+static struct dentry *txt_dir;
+static struct dentry *txt_entries[SL_TXT_ENTRY_COUNT];
+
+static long slaunch_expose_securityfs(void)
+{
+ long ret = 0;
+ int i;
+
+ slaunch_dir = securityfs_create_dir("slaunch", NULL);
+ if (IS_ERR(slaunch_dir))
+ return PTR_ERR(slaunch_dir);
+
+ if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
+ txt_dir = securityfs_create_dir("txt", slaunch_dir);
+ if (IS_ERR(txt_dir)) {
+ ret = PTR_ERR(txt_dir);
+ goto remove_slaunch;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++) {
+ txt_entries[i] = securityfs_create_file(
+ sl_txt_files[i].name, 0440,
+ txt_dir, NULL,
+ sl_txt_files[i].fops);
+ if (IS_ERR(txt_entries[i])) {
+ ret = PTR_ERR(txt_entries[i]);
+ goto remove_files;
+ }
+ }
+ }
+
+ if (sl_evtlog.addr) {
+ event_file = securityfs_create_file(sl_evtlog.name, 0440,
+ slaunch_dir, NULL,
+ &sl_evtlog_ops);
+ if (IS_ERR(event_file)) {
+ ret = PTR_ERR(event_file);
+ goto remove_files;
+ }
+ }
+
+ return 0;
+
+remove_files:
+ if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
+ while (--i >= 0)
+ securityfs_remove(txt_entries[i]);
+ securityfs_remove(txt_dir);
+ }
+
+remove_slaunch:
+ securityfs_remove(slaunch_dir);
+
+ return ret;
+}
+
+static void slaunch_teardown_securityfs(void)
+{
+ int i;
+
+ securityfs_remove(event_file);
+ if (sl_evtlog.addr) {
+ memunmap(sl_evtlog.addr);
+ sl_evtlog.addr = NULL;
+ }
+ sl_evtlog.size = 0;
+
+ if (slaunch_get_flags() & SL_FLAG_ARCH_TXT) {
+ for (i = 0; i < ARRAY_SIZE(sl_txt_files); i++)
+ securityfs_remove(txt_entries[i]);
+
+ securityfs_remove(txt_dir);
+
+ if (txt_heap) {
+ memunmap(txt_heap);
+ txt_heap = NULL;
+ }
+ }
+
+ securityfs_remove(slaunch_dir);
+}
+
+static void slaunch_intel_evtlog(void __iomem *txt)
+{
+ struct slr_entry_log_info *log_info;
+ struct txt_os_mle_data *params;
+ struct slr_table *slrt;
+ void *os_sinit_data;
+ u64 base, size;
+
+ memcpy_fromio(&base, txt + TXT_CR_HEAP_BASE, sizeof(base));
+ memcpy_fromio(&size, txt + TXT_CR_HEAP_SIZE, sizeof(size));
+
+ /* now map TXT heap */
+ txt_heap = memremap(base, size, MEMREMAP_WB);
+ if (!txt_heap)
+ slaunch_txt_reset(txt, "Error failed to memremap TXT heap\n",
+ SL_ERROR_HEAP_MAP);
+
+ params = (struct txt_os_mle_data *)txt_os_mle_data_start(txt_heap);
+
+ /* Get the SLRT and remap it */
+ slrt = memremap(params->slrt, sizeof(*slrt), MEMREMAP_WB);
+ if (!slrt)
+ slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
+ SL_ERROR_SLRT_MAP);
+ size = slrt->size;
+ memunmap(slrt);
+
+ slrt = memremap(params->slrt, size, MEMREMAP_WB);
+ if (!slrt)
+ slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
+ SL_ERROR_SLRT_MAP);
+
+ log_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_LOG_INFO);
+ if (!log_info)
+ slaunch_txt_reset(txt, "Error failed to memremap SLR Table\n",
+ SL_ERROR_SLRT_MISSING_ENTRY);
+
+ sl_evtlog.size = log_info->size;
+ sl_evtlog.addr = memremap(log_info->addr, log_info->size,
+ MEMREMAP_WB);
+ if (!sl_evtlog.addr)
+ slaunch_txt_reset(txt, "Error failed to memremap TPM event log\n",
+ SL_ERROR_EVENTLOG_MAP);
+
+ memunmap(slrt);
+
+ /* Determine if this is TPM 1.2 or 2.0 event log */
+ if (memcmp(sl_evtlog.addr + sizeof(struct tcg_pcr_event),
+ TCG_SPECID_SIG, sizeof(TCG_SPECID_SIG)))
+ return; /* looks like it is not 2.0 */
+
+ /* For TPM 2.0 logs, the extended heap element must be located */
+ os_sinit_data = txt_os_sinit_data_start(txt_heap);
+
+ evtlog20 = tpm20_find_log2_1_element(os_sinit_data);
+
+ /*
+ * If this fails, things are in really bad shape. Any attempt to write
+ * events to the log will fail.
+ */
+ if (!evtlog20)
+ slaunch_txt_reset(txt, "Error failed to find TPM20 event log element\n",
+ SL_ERROR_TPM_INVALID_LOG20);
+}
+
+static void slaunch_tpm20_extend_event(struct tpm_chip *tpm, void __iomem *txt,
+ struct tcg_pcr_event2_head *event)
+{
+ u16 *alg_id_field = (u16 *)((u8 *)event + sizeof(struct tcg_pcr_event2_head));
+ struct tpm_digest *digests;
+ u8 *dptr;
+ u32 i, j;
+ int ret;
+
+ digests = kcalloc(tpm->nr_allocated_banks, sizeof(*digests),
+ GFP_KERNEL);
+ if (!digests)
+ slaunch_txt_reset(txt, "Failed to allocate array of digests\n",
+ SL_ERROR_GENERIC);
+
+ for (i = 0; i < tpm->nr_allocated_banks; i++)
+ digests[i].alg_id = tpm->allocated_banks[i].alg_id;
+
+ /* Early SL code ensured there was a max count of 2 digests */
+ for (i = 0; i < event->count; i++) {
+ dptr = (u8 *)alg_id_field + sizeof(u16);
+
+ for (j = 0; j < tpm->nr_allocated_banks; j++) {
+ if (digests[j].alg_id != *alg_id_field)
+ continue;
+
+ switch (digests[j].alg_id) {
+ case TPM_ALG_SHA256:
+ memcpy(&digests[j].digest[0], dptr,
+ SHA256_DIGEST_SIZE);
+ alg_id_field = (u16 *)((u8 *)alg_id_field +
+ SHA256_DIGEST_SIZE + sizeof(u16));
+ break;
+ case TPM_ALG_SHA1:
+ memcpy(&digests[j].digest[0], dptr,
+ SHA1_DIGEST_SIZE);
+ alg_id_field = (u16 *)((u8 *)alg_id_field +
+ SHA1_DIGEST_SIZE + sizeof(u16));
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ ret = tpm_pcr_extend(tpm, event->pcr_idx, digests);
+ if (ret) {
+ pr_err("Error extending TPM20 PCR, result: %d\n", ret);
+ slaunch_txt_reset(txt, "Failed to extend TPM20 PCR\n",
+ SL_ERROR_TPM_EXTEND);
+ }
+
+ kfree(digests);
+}
+
+static void slaunch_tpm20_extend(struct tpm_chip *tpm, void __iomem *txt)
+{
+ struct tcg_pcr_event *event_header;
+ struct tcg_pcr_event2_head *event;
+ int start = 0, end = 0, size;
+
+ event_header = (struct tcg_pcr_event *)(sl_evtlog.addr +
+ evtlog20->first_record_offset);
+
+ /* Skip first TPM 1.2 event to get to first TPM 2.0 event */
+ event = (struct tcg_pcr_event2_head *)((u8 *)event_header +
+ sizeof(struct tcg_pcr_event) +
+ event_header->event_size);
+
+ while ((void *)event < sl_evtlog.addr + evtlog20->next_record_offset) {
+ size = __calc_tpm2_event_size(event, event_header, false);
+ if (!size)
+ slaunch_txt_reset(txt, "TPM20 invalid event in event log\n",
+ SL_ERROR_TPM_INVALID_EVENT);
+
+ /*
+ * Marker events indicate where the Secure Launch early stub
+ * started and ended adding post launch events.
+ */
+ if (event->event_type == TXT_EVTYPE_SLAUNCH_END) {
+ end = 1;
+ break;
+ } else if (event->event_type == TXT_EVTYPE_SLAUNCH_START) {
+ start = 1;
+ goto next;
+ }
+
+ if (start)
+ slaunch_tpm20_extend_event(tpm, txt, event);
+
+next:
+ event = (struct tcg_pcr_event2_head *)((u8 *)event + size);
+ }
+
+ if (!start || !end)
+ slaunch_txt_reset(txt, "Missing start or end events for extending TPM20 PCRs\n",
+ SL_ERROR_TPM_EXTEND);
+}
+
+static void slaunch_tpm12_extend(struct tpm_chip *tpm, void __iomem *txt)
+{
+ struct tpm12_event_log_header *event_header;
+ struct tcg_pcr_event *event;
+ struct tpm_digest digest;
+ int start = 0, end = 0;
+ int size, ret;
+
+ event_header = (struct tpm12_event_log_header *)sl_evtlog.addr;
+ event = (struct tcg_pcr_event *)((u8 *)event_header +
+ sizeof(struct tpm12_event_log_header));
+
+ while ((void *)event < sl_evtlog.addr + event_header->next_event_offset) {
+ size = sizeof(struct tcg_pcr_event) + event->event_size;
+
+ /*
+ * Marker events indicate where the Secure Launch early stub
+ * started and ended adding post launch events.
+ */
+ if (event->event_type == TXT_EVTYPE_SLAUNCH_END) {
+ end = 1;
+ break;
+ } else if (event->event_type == TXT_EVTYPE_SLAUNCH_START) {
+ start = 1;
+ goto next;
+ }
+
+ if (start) {
+ memset(&digest.digest[0], 0, TPM_MAX_DIGEST_SIZE);
+ digest.alg_id = TPM_ALG_SHA1;
+ memcpy(&digest.digest[0], &event->digest[0],
+ SHA1_DIGEST_SIZE);
+
+ ret = tpm_pcr_extend(tpm, event->pcr_idx, &digest);
+ if (ret) {
+ pr_err("Error extending TPM12 PCR, result: %d\n", ret);
+ slaunch_txt_reset(txt, "Failed to extend TPM12 PCR\n",
+ SL_ERROR_TPM_EXTEND);
+ }
+ }
+
+next:
+ event = (struct tcg_pcr_event *)((u8 *)event + size);
+ }
+
+ if (!start || !end)
+ slaunch_txt_reset(txt, "Missing start or end events for extending TPM12 PCRs\n",
+ SL_ERROR_TPM_EXTEND);
+}
+
+static void slaunch_pcr_extend(void __iomem *txt)
+{
+ struct tpm_chip *tpm;
+
+ tpm = tpm_default_chip();
+ if (!tpm)
+ slaunch_txt_reset(txt, "Could not get default TPM chip\n",
+ SL_ERROR_TPM_INIT);
+
+ if (!tpm_preferred_locality(tpm, 2))
+ slaunch_txt_reset(txt, "Could not set TPM chip locality 2\n",
+ SL_ERROR_TPM_INIT);
+
+ if (evtlog20)
+ slaunch_tpm20_extend(tpm, txt);
+ else
+ slaunch_tpm12_extend(tpm, txt);
+
+ tpm_preferred_locality(tpm, 0);
+}
+
+static int __init slaunch_module_init(void)
+{
+ void __iomem *txt;
+
+ /* Check to see if Secure Launch happened */
+ if ((slaunch_get_flags() & (SL_FLAG_ACTIVE|SL_FLAG_ARCH_TXT)) !=
+ (SL_FLAG_ACTIVE | SL_FLAG_ARCH_TXT))
+ return 0;
+
+ txt = ioremap(TXT_PRIV_CONFIG_REGS_BASE, TXT_NR_CONFIG_PAGES *
+ PAGE_SIZE);
+ if (!txt)
+ panic("Error ioremap of TXT priv registers\n");
+
+ /* Only Intel TXT is supported at this point */
+ slaunch_intel_evtlog(txt);
+ slaunch_pcr_extend(txt);
+ iounmap(txt);
+
+ return slaunch_expose_securityfs();
+}
+
+static void __exit slaunch_module_exit(void)
+{
+ slaunch_teardown_securityfs();
+}
+
+late_initcall(slaunch_module_init);
+__exitcall(slaunch_module_exit);
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch
2024-05-31 1:03 [PATCH v9 00/19] x86: Trenchboot secure dynamic launch Linux kernel support Ross Philipson
` (17 preceding siblings ...)
2024-05-31 1:03 ` [PATCH v9 18/19] x86: Secure Launch late initcall platform module Ross Philipson
@ 2024-05-31 1:03 ` Ross Philipson
2024-05-31 11:09 ` Ard Biesheuvel
18 siblings, 1 reply; 113+ messages in thread
From: Ross Philipson @ 2024-05-31 1:03 UTC (permalink / raw)
To: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu
Cc: ross.philipson, dpsmith, tglx, mingo, bp, hpa, dave.hansen, ardb,
mjg59, James.Bottomley, peterhuewe, jarkko, jgg, luto, nivedita,
herbert, davem, corbet, ebiederm, dwmw2, baolu.lu, kanth.ghatraju,
andrew.cooper3, trenchboot-devel
This support allows the DRTM launch to be initiated after an EFI stub
launch of the Linux kernel is done. This is accomplished by providing
a handler to jump to when a Secure Launch is in progress. This has to be
called after the EFI stub does Exit Boot Services.
Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
---
drivers/firmware/efi/libstub/x86-stub.c | 98 +++++++++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
index d5a8182cf2e1..a1143d006202 100644
--- a/drivers/firmware/efi/libstub/x86-stub.c
+++ b/drivers/firmware/efi/libstub/x86-stub.c
@@ -9,6 +9,8 @@
#include <linux/efi.h>
#include <linux/pci.h>
#include <linux/stddef.h>
+#include <linux/slr_table.h>
+#include <linux/slaunch.h>
#include <asm/efi.h>
#include <asm/e820/types.h>
@@ -830,6 +832,97 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
return efi_adjust_memory_range_protection(addr, kernel_text_size);
}
+#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
+static bool efi_secure_launch_update_boot_params(struct slr_table *slrt,
+ struct boot_params *boot_params)
+{
+ struct slr_entry_intel_info *txt_info;
+ struct slr_entry_policy *policy;
+ struct txt_os_mle_data *os_mle;
+ bool updated = false;
+ int i;
+
+ txt_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
+ if (!txt_info)
+ return false;
+
+ os_mle = txt_os_mle_data_start((void *)txt_info->txt_heap);
+ if (!os_mle)
+ return false;
+
+ os_mle->boot_params_addr = (u32)(u64)boot_params;
+
+ policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
+ if (!policy)
+ return false;
+
+ for (i = 0; i < policy->nr_entries; i++) {
+ if (policy->policy_entries[i].entity_type == SLR_ET_BOOT_PARAMS) {
+ policy->policy_entries[i].entity = (u64)boot_params;
+ updated = true;
+ break;
+ }
+ }
+
+ /*
+ * If this is a PE entry into EFI stub the mocked up boot params will
+ * be missing some of the setup header data needed for the second stage
+ * of the Secure Launch boot.
+ */
+ if (image) {
+ struct setup_header *hdr = (struct setup_header *)((u8 *)image->image_base + 0x1f1);
+ u64 cmdline_ptr, hi_val;
+
+ boot_params->hdr.setup_sects = hdr->setup_sects;
+ boot_params->hdr.syssize = hdr->syssize;
+ boot_params->hdr.version = hdr->version;
+ boot_params->hdr.loadflags = hdr->loadflags;
+ boot_params->hdr.kernel_alignment = hdr->kernel_alignment;
+ boot_params->hdr.min_alignment = hdr->min_alignment;
+ boot_params->hdr.xloadflags = hdr->xloadflags;
+ boot_params->hdr.init_size = hdr->init_size;
+ boot_params->hdr.kernel_info_offset = hdr->kernel_info_offset;
+ hi_val = boot_params->ext_cmd_line_ptr;
+ cmdline_ptr = boot_params->hdr.cmd_line_ptr | hi_val << 32;
+ boot_params->hdr.cmdline_size = strlen((const char *)cmdline_ptr);;
+ }
+
+ return updated;
+}
+
+static void efi_secure_launch(struct boot_params *boot_params)
+{
+ struct slr_entry_dl_info *dlinfo;
+ efi_guid_t guid = SLR_TABLE_GUID;
+ dl_handler_func handler_callback;
+ struct slr_table *slrt;
+
+ /*
+ * The presence of this table indicated a Secure Launch
+ * is being requested.
+ */
+ slrt = (struct slr_table *)get_efi_config_table(guid);
+ if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
+ return;
+
+ /*
+ * Since the EFI stub library creates its own boot_params on entry, the
+ * SLRT and TXT heap have to be updated with this version.
+ */
+ if (!efi_secure_launch_update_boot_params(slrt, boot_params))
+ return;
+
+ /* Jump through DL stub to initiate Secure Launch */
+ dlinfo = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
+
+ handler_callback = (dl_handler_func)dlinfo->dl_handler;
+
+ handler_callback(&dlinfo->bl_context);
+
+ unreachable();
+}
+#endif
+
static void __noreturn enter_kernel(unsigned long kernel_addr,
struct boot_params *boot_params)
{
@@ -957,6 +1050,11 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
goto fail;
}
+#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
+ /* If a Secure Launch is in progress, this never returns */
+ efi_secure_launch(boot_params);
+#endif
+
/*
* Call the SEV init code while still running with the firmware's
* GDT/IDT, so #VC exceptions will be handled by EFI.
--
2.39.3
^ permalink raw reply related [flat|nested] 113+ messages in thread* Re: [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch
2024-05-31 1:03 ` [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch Ross Philipson
@ 2024-05-31 11:09 ` Ard Biesheuvel
2024-06-04 17:22 ` ross.philipson
0 siblings, 1 reply; 113+ messages in thread
From: Ard Biesheuvel @ 2024-05-31 11:09 UTC (permalink / raw)
To: Ross Philipson
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel
On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>
> This support allows the DRTM launch to be initiated after an EFI stub
> launch of the Linux kernel is done. This is accomplished by providing
> a handler to jump to when a Secure Launch is in progress. This has to be
> called after the EFI stub does Exit Boot Services.
>
> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
Just some minor remarks below. The overall approach in this patch
looks fine now.
> ---
> drivers/firmware/efi/libstub/x86-stub.c | 98 +++++++++++++++++++++++++
> 1 file changed, 98 insertions(+)
>
> diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
> index d5a8182cf2e1..a1143d006202 100644
> --- a/drivers/firmware/efi/libstub/x86-stub.c
> +++ b/drivers/firmware/efi/libstub/x86-stub.c
> @@ -9,6 +9,8 @@
> #include <linux/efi.h>
> #include <linux/pci.h>
> #include <linux/stddef.h>
> +#include <linux/slr_table.h>
> +#include <linux/slaunch.h>
>
> #include <asm/efi.h>
> #include <asm/e820/types.h>
> @@ -830,6 +832,97 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
> return efi_adjust_memory_range_protection(addr, kernel_text_size);
> }
>
> +#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
IS_ENABLED() is mostly used for C conditionals not CPP ones.
It would be nice if this #if could be dropped, and replaced with ... (see below)
> +static bool efi_secure_launch_update_boot_params(struct slr_table *slrt,
> + struct boot_params *boot_params)
> +{
> + struct slr_entry_intel_info *txt_info;
> + struct slr_entry_policy *policy;
> + struct txt_os_mle_data *os_mle;
> + bool updated = false;
> + int i;
> +
> + txt_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
> + if (!txt_info)
> + return false;
> +
> + os_mle = txt_os_mle_data_start((void *)txt_info->txt_heap);
> + if (!os_mle)
> + return false;
> +
> + os_mle->boot_params_addr = (u32)(u64)boot_params;
> +
Why is this safe?
> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
> + if (!policy)
> + return false;
> +
> + for (i = 0; i < policy->nr_entries; i++) {
> + if (policy->policy_entries[i].entity_type == SLR_ET_BOOT_PARAMS) {
> + policy->policy_entries[i].entity = (u64)boot_params;
> + updated = true;
> + break;
> + }
> + }
> +
> + /*
> + * If this is a PE entry into EFI stub the mocked up boot params will
> + * be missing some of the setup header data needed for the second stage
> + * of the Secure Launch boot.
> + */
> + if (image) {
> + struct setup_header *hdr = (struct setup_header *)((u8 *)image->image_base + 0x1f1);
Could we use something other than a bare 0x1f1 constant here? struct
boot_params has a struct setup_header at the correct offset, so with
some casting of offsetof() use, we can make this look a lot more self
explanatory.
> + u64 cmdline_ptr, hi_val;
> +
> + boot_params->hdr.setup_sects = hdr->setup_sects;
> + boot_params->hdr.syssize = hdr->syssize;
> + boot_params->hdr.version = hdr->version;
> + boot_params->hdr.loadflags = hdr->loadflags;
> + boot_params->hdr.kernel_alignment = hdr->kernel_alignment;
> + boot_params->hdr.min_alignment = hdr->min_alignment;
> + boot_params->hdr.xloadflags = hdr->xloadflags;
> + boot_params->hdr.init_size = hdr->init_size;
> + boot_params->hdr.kernel_info_offset = hdr->kernel_info_offset;
> + hi_val = boot_params->ext_cmd_line_ptr;
We have efi_set_u64_split() for this.
> + cmdline_ptr = boot_params->hdr.cmd_line_ptr | hi_val << 32;
> + boot_params->hdr.cmdline_size = strlen((const char *)cmdline_ptr);;
> + }
> +
> + return updated;
> +}
> +
> +static void efi_secure_launch(struct boot_params *boot_params)
> +{
> + struct slr_entry_dl_info *dlinfo;
> + efi_guid_t guid = SLR_TABLE_GUID;
> + dl_handler_func handler_callback;
> + struct slr_table *slrt;
> +
... a C conditional here, e.g.,
if (!IS_ENABLED(CONFIG_SECURE_LAUNCH))
return;
The difference is that all the code will get compile test coverage
every time, instead of only in configs that enable
CONFIG_SECURE_LAUNCH.
This significantly reduces the risk that your stuff will get broken
inadvertently.
> + /*
> + * The presence of this table indicated a Secure Launch
> + * is being requested.
> + */
> + slrt = (struct slr_table *)get_efi_config_table(guid);
> + if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
> + return;
> +
> + /*
> + * Since the EFI stub library creates its own boot_params on entry, the
> + * SLRT and TXT heap have to be updated with this version.
> + */
> + if (!efi_secure_launch_update_boot_params(slrt, boot_params))
> + return;
> +
> + /* Jump through DL stub to initiate Secure Launch */
> + dlinfo = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
> +
> + handler_callback = (dl_handler_func)dlinfo->dl_handler;
> +
> + handler_callback(&dlinfo->bl_context);
> +
> + unreachable();
> +}
> +#endif
> +
> static void __noreturn enter_kernel(unsigned long kernel_addr,
> struct boot_params *boot_params)
> {
> @@ -957,6 +1050,11 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
> goto fail;
> }
>
> +#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
... and drop this #if as well.
> + /* If a Secure Launch is in progress, this never returns */
> + efi_secure_launch(boot_params);
> +#endif
> +
> /*
> * Call the SEV init code while still running with the firmware's
> * GDT/IDT, so #VC exceptions will be handled by EFI.
> --
> 2.39.3
>
^ permalink raw reply [flat|nested] 113+ messages in thread* Re: [PATCH v9 19/19] x86: EFI stub DRTM launch support for Secure Launch
2024-05-31 11:09 ` Ard Biesheuvel
@ 2024-06-04 17:22 ` ross.philipson
0 siblings, 0 replies; 113+ messages in thread
From: ross.philipson @ 2024-06-04 17:22 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-kernel, x86, linux-integrity, linux-doc, linux-crypto,
kexec, linux-efi, iommu, dpsmith, tglx, mingo, bp, hpa,
dave.hansen, mjg59, James.Bottomley, peterhuewe, jarkko, jgg,
luto, nivedita, herbert, davem, corbet, ebiederm, dwmw2, baolu.lu,
kanth.ghatraju, andrew.cooper3, trenchboot-devel, ross.philipson
On 5/31/24 4:09 AM, Ard Biesheuvel wrote:
> On Fri, 31 May 2024 at 03:32, Ross Philipson <ross.philipson@oracle.com> wrote:
>>
>> This support allows the DRTM launch to be initiated after an EFI stub
>> launch of the Linux kernel is done. This is accomplished by providing
>> a handler to jump to when a Secure Launch is in progress. This has to be
>> called after the EFI stub does Exit Boot Services.
>>
>> Signed-off-by: Ross Philipson <ross.philipson@oracle.com>
>
> Just some minor remarks below. The overall approach in this patch
> looks fine now.
>
>
>> ---
>> drivers/firmware/efi/libstub/x86-stub.c | 98 +++++++++++++++++++++++++
>> 1 file changed, 98 insertions(+)
>>
>> diff --git a/drivers/firmware/efi/libstub/x86-stub.c b/drivers/firmware/efi/libstub/x86-stub.c
>> index d5a8182cf2e1..a1143d006202 100644
>> --- a/drivers/firmware/efi/libstub/x86-stub.c
>> +++ b/drivers/firmware/efi/libstub/x86-stub.c
>> @@ -9,6 +9,8 @@
>> #include <linux/efi.h>
>> #include <linux/pci.h>
>> #include <linux/stddef.h>
>> +#include <linux/slr_table.h>
>> +#include <linux/slaunch.h>
>>
>> #include <asm/efi.h>
>> #include <asm/e820/types.h>
>> @@ -830,6 +832,97 @@ static efi_status_t efi_decompress_kernel(unsigned long *kernel_entry)
>> return efi_adjust_memory_range_protection(addr, kernel_text_size);
>> }
>>
>> +#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
>
> IS_ENABLED() is mostly used for C conditionals not CPP ones.
>
> It would be nice if this #if could be dropped, and replaced with ... (see below)
>
>
>> +static bool efi_secure_launch_update_boot_params(struct slr_table *slrt,
>> + struct boot_params *boot_params)
>> +{
>> + struct slr_entry_intel_info *txt_info;
>> + struct slr_entry_policy *policy;
>> + struct txt_os_mle_data *os_mle;
>> + bool updated = false;
>> + int i;
>> +
>> + txt_info = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_INTEL_INFO);
>> + if (!txt_info)
>> + return false;
>> +
>> + os_mle = txt_os_mle_data_start((void *)txt_info->txt_heap);
>> + if (!os_mle)
>> + return false;
>> +
>> + os_mle->boot_params_addr = (u32)(u64)boot_params;
>> +
>
> Why is this safe?
The size of the boot_params_addr is a holdover from the legacy boot
world when boot params were always loaded at a low address. We will
increase the size of the field.
>
>> + policy = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_ENTRY_POLICY);
>> + if (!policy)
>> + return false;
>> +
>> + for (i = 0; i < policy->nr_entries; i++) {
>> + if (policy->policy_entries[i].entity_type == SLR_ET_BOOT_PARAMS) {
>> + policy->policy_entries[i].entity = (u64)boot_params;
>> + updated = true;
>> + break;
>> + }
>> + }
>> +
>> + /*
>> + * If this is a PE entry into EFI stub the mocked up boot params will
>> + * be missing some of the setup header data needed for the second stage
>> + * of the Secure Launch boot.
>> + */
>> + if (image) {
>> + struct setup_header *hdr = (struct setup_header *)((u8 *)image->image_base + 0x1f1);
>
> Could we use something other than a bare 0x1f1 constant here? struct
> boot_params has a struct setup_header at the correct offset, so with
> some casting of offsetof() use, we can make this look a lot more self
> explanatory.
Yes we can do this.
>
>
>> + u64 cmdline_ptr, hi_val;
>> +
>> + boot_params->hdr.setup_sects = hdr->setup_sects;
>> + boot_params->hdr.syssize = hdr->syssize;
>> + boot_params->hdr.version = hdr->version;
>> + boot_params->hdr.loadflags = hdr->loadflags;
>> + boot_params->hdr.kernel_alignment = hdr->kernel_alignment;
>> + boot_params->hdr.min_alignment = hdr->min_alignment;
>> + boot_params->hdr.xloadflags = hdr->xloadflags;
>> + boot_params->hdr.init_size = hdr->init_size;
>> + boot_params->hdr.kernel_info_offset = hdr->kernel_info_offset;
>> + hi_val = boot_params->ext_cmd_line_ptr;
>
> We have efi_set_u64_split() for this.
Ok I will use that then.
>
>> + cmdline_ptr = boot_params->hdr.cmd_line_ptr | hi_val << 32;
>> + boot_params->hdr.cmdline_size = strlen((const char *)cmdline_ptr);;
>> + }
>> +
>> + return updated;
>> +}
>> +
>> +static void efi_secure_launch(struct boot_params *boot_params)
>> +{
>> + struct slr_entry_dl_info *dlinfo;
>> + efi_guid_t guid = SLR_TABLE_GUID;
>> + dl_handler_func handler_callback;
>> + struct slr_table *slrt;
>> +
>
> ... a C conditional here, e.g.,
>
> if (!IS_ENABLED(CONFIG_SECURE_LAUNCH))
> return;
>
> The difference is that all the code will get compile test coverage
> every time, instead of only in configs that enable
> CONFIG_SECURE_LAUNCH.
>
> This significantly reduces the risk that your stuff will get broken
> inadvertently.
Understood, I will address these as you suggest.
>
>> + /*
>> + * The presence of this table indicated a Secure Launch
>> + * is being requested.
>> + */
>> + slrt = (struct slr_table *)get_efi_config_table(guid);
>> + if (!slrt || slrt->magic != SLR_TABLE_MAGIC)
>> + return;
>> +
>> + /*
>> + * Since the EFI stub library creates its own boot_params on entry, the
>> + * SLRT and TXT heap have to be updated with this version.
>> + */
>> + if (!efi_secure_launch_update_boot_params(slrt, boot_params))
>> + return;
>> +
>> + /* Jump through DL stub to initiate Secure Launch */
>> + dlinfo = slr_next_entry_by_tag(slrt, NULL, SLR_ENTRY_DL_INFO);
>> +
>> + handler_callback = (dl_handler_func)dlinfo->dl_handler;
>> +
>> + handler_callback(&dlinfo->bl_context);
>> +
>> + unreachable();
>> +}
>> +#endif
>> +
>> static void __noreturn enter_kernel(unsigned long kernel_addr,
>> struct boot_params *boot_params)
>> {
>> @@ -957,6 +1050,11 @@ void __noreturn efi_stub_entry(efi_handle_t handle,
>> goto fail;
>> }
>>
>> +#if (IS_ENABLED(CONFIG_SECURE_LAUNCH))
>
> ... and drop this #if as well.
Yes.
Thanks
Ross
>
>> + /* If a Secure Launch is in progress, this never returns */
>> + efi_secure_launch(boot_params);
>> +#endif
>> +
>> /*
>> * Call the SEV init code while still running with the firmware's
>> * GDT/IDT, so #VC exceptions will be handled by EFI.
>> --
>> 2.39.3
>>
^ permalink raw reply [flat|nested] 113+ messages in thread