Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Dynamic Stack Cookie Support to IA32/X64/AARCH64 #6381

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

os-d
Copy link
Contributor

@os-d os-d commented Oct 28, 2024

Description

This PR consists of 5 commits to support dynamic stack cookies and convert OvmfPkgIA32X64 and ArmVirtQemu to use dynamic stack cookies. The dynamic stack cookie approach was implemented per the PR discussion here: #5957. Note that MSVC AARCH64 support is not currently added for dynamic stack cookies because AARCH64 VS2022 build support needs to be upstreamed to edk2 first, which is in progress.

Note that this PR depends on: #6433 and the OvmfPkg IA32X64 CI will fail until this is rebased on that due to the ResetVector module type. When this was one PR, CI succeeded.

MdePkg: Add Dynamic Stack Cookie Implementation

Per discussion on #5957, this commit moves the existing entry point libs to a _CModuleEntryPoint function and creates a new entry point lib that simply wraps _CModuleEntryPoint() in _ModuleEntryPoint(). Then, an assembly implementation of _ModuleEntryPoint() is created in StackCheckLibDynamicInit.inf that does architecture
and toolchain specific operations to update the stack cookie value at runtime per module.

For the disabled/ignored stack cookie case, there is no change for a consumer, MdeLibs.dsc.inc includes references to the new entry point functions and so everything "just works."

For consumers of StackCheckLibDynamicInit.inf, all they do is include

StackCheckEntryPointLib|MdePkg/Library/StackCheckLib/StackCheckLibDynamicinit.inf

in their DSC and it will override all instances of the null StackCheckEntryPointLibs. The consumer can also selectively (as is recommended) apply the dynamic implementation to some module types (e.g. ones where permanent memory is available) and not to others and these others will fall back to the null StackCheckEntryPointLibs defined in MdeLibs.dsc.inc.

The StackCheckLib README is updated and StackCheckLibStaticInit.inf is renamed to StackCheckLib.inf because the design changed, StackCheckLib.inf provides stack cookie checking regardless of static or dynamic init and StackCheckLibDynamicInit.inf just provides dynamic initialization of the stack cookie and no checking functionality.

OvmfPkg: Add RDRAND Support To QEMU

In order to use dynamic stack cookies, we need RDRAND support from QEMU, so this updates the QEMU launching code for OvmfPkg to include RDRAND support.

OvmfPkg: OvmfIA32X64: Add Custom Stack Cookie Checking

To provide an example and test the code within edk2, this adds stack cookie checking to OvmfIA32X64, doing no checking
for SEC and PEI_CORE modules, static cookies for PEIMs, and dynamic cookies for all other module types.

ArmVirtPkg: Add RNDR Support to QEMU

In order to use dynamic stack cookies in ArmVirtQemu, we need RNDR support. This is added by getting the max cpu features.

ArmVirtPkg: ArmVirtQemu: Add Custom Stack Cookies

In order to provide an example and test out dynamic stack cookies in edk2, dynamic stack cookies are added to ArmVirtQemu.

  • Breaking change?
    • Breaking change - Does this PR cause a break in build or boot behavior?
    • Examples: Does it add a new library class or move a module to a different repo.
  • Impacts security?
    • Security - Does this PR have a direct security impact?
    • Examples: Crypto algorithm change or buffer overflow fix.
  • Includes tests?
    • Tests - Does this PR include any explicit test code?
    • Examples: Unit tests or integration tests.

How This Was Tested

Tested by booting OvmfIA32X64 and ArmVirtQemu with different configurations of stack cookie support (null, static, dynamic) and verifying that the stack cookies were set correctly and that the system booted as expected as seen under a software debugger.

Integration Instructions

Follow the latest instructions in MdePkg/Library/StackCheckLib/README.md.

This is marked as a breaking change because of the refactoring of StackCheckLibNull in MdeLibs.dsc.inc and no longer requiring DSCs to include StackCheckLibNull for SEC modules.

Listing the current instructions here:

Default Stack Check Library Configuration

MdePkg/MdeLibs.dsc.inc links StackCheckLibNull for all types and the null StackCheckEntryPointLib instances
per phase.

As stated above, all HOST_APPLICATIONS will link against a HOST_APPLICATION specific
implementation provided in UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc.

Custom Stack Check Library Configuration

In order to use a different instance of StackCheckLib than MdeLibs.dsc.inc provides, a DSC
should add the following:

[Defines]
  DEFINE CUSTOM_STACK_CHECK_LIB = TRUE

This will cause MdeLibs.dsc.inc to not link StackCheckLibNull and rely on a DSC to
link whichever version(s) of StackCheckLib it desires.

It is recommended that SEC and PEI_CORE modules use StackCheckLibNull because there are no exception handlers
registered at this time, so any failures here will cause a triple fault and a reboot. Pre-memory and XIP modules
should not use StackCheckLibDynamicInit as the global stack cookie value cannot be updated. All other modules
should use StackCheckLibDynamicInit.

Below is an example of how to link the StackCheckLib instances in the platform DSC file
but it may need customization based on the platform's requirements:

[LibraryClasses.common.SEC, LibraryClasses.common.PEI_CORE]
  NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf

[LibraryClasses.common.PEIM]
  NULL|MdePkg/Library/StackCheckLib/StackCheckLib.inf

[LibraryClasses.common.MM_CORE_STANDALONE, LibraryClasses.common.MM_STANDALONE, LibraryClasses.common.DXE_CORE,
LibraryClasses.common.SMM_CORE, LibraryClasses.common.DXE_SMM_DRIVER, LibraryClasses.common.DXE_DRIVER,
LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.DXE_SAL_DRIVER, LibraryClasses.common.UEFI_DRIVER,
LibraryClasses.common.UEFI_APPLICATION]
  NULL|MdePkg/Library/StackCheckLib/StackCheckLib.inf
  NULL|MdePkg/Library/StackCheckLib/StackCheckLibDynamicInit.inf

Disable Stack Check Library

If a platform would like to disable stack cookies (say for debugging purposes),
they can add the following to their DSC:

[BuildOptions]
  MSVC:*_*_*_CC_FLAGS = /GS-
  GCC:*_*_*_CC_FLAGS = -fno-stack-protector

The same build options can be put in a module's INF to only disable stack cookies
for that module.

It is not recommended to disable stack cookie checking in production scenarios.

@github-actions github-actions bot added impact:breaking-change This change breaks existing APIs impacting build or boot. impact:security This change has a direct security impact such as changing a crypto algorithm. labels Oct 28, 2024
@tianocore-assign-reviewers
Copy link

WARNING: Cannot add some reviewers: A user specified as a reviewer for this PR is not a collaborator of the repository. Please add them as a collaborator to the repository so they can be requested in the future.

Non-collaborators requested:

Attn Admins:


Admin Instructions:

  • Add the non-collaborators as collaborators to the appropriate team(s) listed in teams
  • If they are no longer needed as reviewers, remove them from Maintainers.txt

@mdkinney
Copy link
Member

If a platform moves from one stable tag to the next, is this still a breaking change?

@os-d
Copy link
Contributor Author

os-d commented Oct 31, 2024

If a platform moves from one stable tag to the next, is this still a breaking change?

It would still be a breaking change for x86 platforms because of the module type change for the ResetVector, which may require them to update their FDF, like in the second commit here.

For the stack cookies part it would not be a breaking change if this went into 202411, which is why I reorganized it this way, to make it easier to consume. If it doesn’t, then it will be, the only reason being that platforms would need to remove the SEC instance of StackCheckLib.

If we want, we can split this PR into two: the first, targeted for 202411 changes is the first three commits, changing the ResetVector and MdeLibs.dsc.inc to apply StackCheckLibNull to all types. This would minimze churn for consumers of stable tags only.

The dynamic stack cookies could be a separate PR and because it is the much larger and more involved change and is non-breaking change, so could come after the stable tag.

This is dependent on whether folks like what I’ve done in the first three commits :).

@mdkinney and @lgao4 , thoughts?

@mdkinney
Copy link
Member

If a platform uses SEC from edk2, then not a breaking change. If platform uses custom SEC, then they must change module type to USER_DEFINED. Correct?

@mdkinney
Copy link
Member

It appears that this change replaced the use of SEC with USER_DEFINED. After this change, is SEC ever used? If SEC is never used, and the property needed is that SEC modules do not link against NULL libs, then wouldn't it be easier to change BaseTools to not add NULL libs to SEC modules?

@os-d
Copy link
Contributor Author

os-d commented Oct 31, 2024

If a platform uses SEC from edk2, then not a breaking change. If platform uses custom SEC, then they must change module type to USER_DEFINED. Correct?

@mdkinney it still could be a breaking change if they have an FDF rule like OvmfPkg did that was SEC.RESETVECTOR. This would need to become USER_DEFINED.RESETVECTOR, like I did in the second commit.

@os-d
Copy link
Contributor Author

os-d commented Oct 31, 2024

It appears that this change replaced the use of SEC with USER_DEFINED. After this change, is SEC ever used? If SEC is never used, and the property needed is that SEC modules do not link against NULL libs, then wouldn't it be easier to change BaseTools to not add NULL libs to SEC modules?

Only the ResetVector is changed from SEC to USER_DEFINED (OvmfPkg just had several copies of it). SEC is still used for SecMain and related files:

# This is the first module taking control of the platform upon power-on/reset.
. These we do want to link to NULL libs. The only reason the ResetVector can’t be linked to NULL libs is that the BaseTools assume that if you are linking a library in that _ModuleEntryPoint is present. For every module except the ResetVector, this is true. So I chose to make the ResetVector USER_DEFINED since it is a unique file that should not be linked to anything else.

OvmfPkg/PlatformCI/PlatformBuildLib.py Outdated Show resolved Hide resolved
OvmfPkg/OvmfPkgIa32X64.dsc Outdated Show resolved Hide resolved
@os-d
Copy link
Contributor Author

os-d commented Nov 5, 2024

@mdkinney , shall I split this PR into two pieces, one for the change to ResetVector and the StackCheckLibNull consumption so that we can get that smaller piece in for the stable tag and the other for dynamic stack cookies that can come after the stable tag? To attempt to avoid churn for consumers of stable tags.

@os-d
Copy link
Contributor Author

os-d commented Nov 6, 2024

@kraxel , I have made the changes you requested, if you want to re-review.

@os-d os-d force-pushed the dynamic_stack_cookies branch 2 times, most recently from 9ef4c67 to 6d0af4a Compare November 6, 2024 23:49
ArmVirtPkg/ArmVirtQemu.dsc Outdated Show resolved Hide resolved
@os-d
Copy link
Contributor Author

os-d commented Nov 9, 2024

@kraxel I updated ArmVirtPkg to move to a dsc.inc, too, if you want to re-review.

@mdkinney @ajfish @lgao4 can you review please?

@mdkinney
Copy link
Member

@os-d I do recommend splitting the PR so the cleanup for edk2-stable202411 can be considered without adding dynamic cookie support. I think this minimizes the downstream platform impact for platforms that will sync from edk2-stable202408 to edk2-stable202411. Do you agree?

Adding @lgao4 for feedback on edk2-stable202411.

@os-d
Copy link
Contributor Author

os-d commented Nov 12, 2024

@mdkinney I completely agree and I think it will be a much better experience for downstream consumers if we get the cleanup PR into edk2-stable202411. I will split this PR into two.

Per discussion on tianocore#5957,
this commit moves the existing entry point libs to a
_CModuleEntryPoint function and creates a new entry point lib
that simply wraps _CModuleEntryPoint() in _ModuleEntryPoint().
Then, an assembly implementation of _ModuleEntryPoint() is
created in StackCheckLibDynamicInit.inf that does architecture
and toolchain specific operations to update the stack cookie
value at runtime per module.

For the disabled/ignored stack cookie case, there is no change
for a consumer, MdeLibs.dsc.inc includes references to the
new entry point functions and so everything "just works."

For consumers of StackCheckLibDynamicInit.inf, all they do
is include

StackCheckEntryPointLib|
MdePkg/Library/StackCheckLib/StackCheckLibDynamicinit.inf

in their DSC and it will override all instances of the
null StackCheckEntryPointLibs. The consumer can also
selectively (as is recommended) apply the dynamic
implementation to some module types (e.g. ones where
permanent memory is available) and not to others and these
others will fall back to the null StackCheckEntryPointLibs
defined in MdeLibs.dsc.inc.

The StackCheckLib README is updated and StackCheckLibStaticInit.inf
is renamed to StackCheckLib.inf because the design changed,
StackCheckLib.inf provides stack cookie checking regardless of
static or dynamic init and StackCheckLibDynamicInit.inf just
provides dynamic initialization of the stack cookie and no
checking functionality.

Continuous-integration-options: PatchCheck.ignore-multi-package

Suggested-by: Andrew Fish <[email protected]>
Signed-off-by: Oliver Smith-Denny <[email protected]>
In order to use dynamic stack cookies, we need RDRAND support
from QEMU, so this updates the QEMU launching code for OvmfPkg
to include RDRAND support.

Signed-off-by: Oliver Smith-Denny <[email protected]>
To provide an example and test the code within edk2, this
adds stack cookie checking to OvmfIA32X64, doing no checking
for SEC and PEI_CORE modules, static cookies for PEIMs, and
dynamic cookies for all other module types.

The logic, per maintainer request, is added to a dsc.inc
file for easy inclusion into other Ovmf platforms in
the future.

Signed-off-by: Oliver Smith-Denny <[email protected]>
In order to use dynamic stack cookies in ArmVirtQemu, we need
RNDR support. This is added by getting the max cpu features.

Signed-off-by: Oliver Smith-Denny <[email protected]>
In order to provide an example and test out dynamic stack
cookies in edk2, dynamic stack cookies are added to ArmVirtPkg
platforms using ArmVirt.dsc.inc, per maintainer request.

Signed-off-by: Oliver Smith-Denny <[email protected]>
@os-d
Copy link
Contributor Author

os-d commented Nov 12, 2024

I have created this PR: #6433, that is targeted for edk2-stable202411. @kraxel , the only change to this PR is removing commits, so I believe your review is still valid here, but if you want to re-review or review the new PR, please do so.

@os-d
Copy link
Contributor Author

os-d commented Nov 12, 2024

@mdkinney , this PR is no longer a breaking change, but I do not have permission to remove the label. Can you please remove it?

@ardbiesheuvel ardbiesheuvel removed the impact:breaking-change This change breaks existing APIs impacting build or boot. label Nov 12, 2024
@os-d
Copy link
Contributor Author

os-d commented Nov 12, 2024

Note that this PR now depends on: #6433 and the OvmfPkg IA32X64 CI will fail until this is rebased on that due to the ResetVector module type. When this was one PR, CI succeeded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
impact:security This change has a direct security impact such as changing a crypto algorithm.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants