Skip to content

Conversation

@AaronRobinsonMSFT
Copy link
Member

In .NET component scenarios (for example, C++/CLI), the APP_CONTEXT_BASE_DIRECTORY property is set to an empty string. When the standalone GC scenario is exercised using System.GC.Name or DOTNET_GCName, the empty directory is used as the path and the name appended to nothing. The result is for the load to use the default search path and could load the GC from anywhere. The solution is to use System.GC.Path or DOTNET_GCPath to get the desired behavior and we "fix" the component issue by going down the fallback path and use the same directory as the coreclr binary.

Fixes #119418

@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 11.0.0 milestone Sep 23, 2025
Copilot AI review requested due to automatic review settings September 23, 2025 17:30
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes a security vulnerability in standalone GC loading for .NET component scenarios (like C++/CLI). When APP_CONTEXT_BASE_DIRECTORY is empty in component scenarios, the GC library could be loaded from anywhere in the default search path, creating a potential security risk.

Key changes:

  • Add validation to check if APP_CONTEXT_BASE_DIRECTORY is an empty string
  • Skip the app base directory path when it's empty, forcing fallback to the coreclr binary directory
  • Add explanatory comments about the component scenario behavior

@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/gc
See info in area-owners.md if you want to be subscribed.

@AaronRobinsonMSFT
Copy link
Member Author

/cc @dotnet/gc

@AaronRobinsonMSFT AaronRobinsonMSFT merged commit 5636967 into dotnet:main Sep 24, 2025
98 of 100 checks passed
@github-project-automation github-project-automation bot moved this to Done in AppModel Sep 24, 2025
@AaronRobinsonMSFT AaronRobinsonMSFT deleted the runtime_119418 branch September 24, 2025 20:17
@heh-ad
Copy link

heh-ad commented Sep 29, 2025

Thanks for the fix, @AaronRobinsonMSFT . Could it be backported to .NET 10 as it impacts the upgrade to this LTS release?

@AaronRobinsonMSFT
Copy link
Member Author

Thanks for the fix, @AaronRobinsonMSFT . Could it be backported to .NET 10 as it impacts the upgrade to this LTS release?

Would it be possible to use the more precise mechaism I mentioned at #119418 (comment)? Use System.GC.Path? Porting this to .NET 10 isn't unreasonable, but since there is a workaround that is more robust it is going to be asked why the Name is needed.

@AaronRobinsonMSFT
Copy link
Member Author

/backport to release/10.0

@AaronRobinsonMSFT
Copy link
Member Author

/backport to release/9.0-staging

@github-actions
Copy link
Contributor

Started backporting to release/10.0: https://github.com/dotnet/runtime/actions/runs/18112369317

@github-actions
Copy link
Contributor

Started backporting to release/9.0-staging: https://github.com/dotnet/runtime/actions/runs/18112372375

@heh-ad
Copy link

heh-ad commented Sep 29, 2025

Thanks for the backporting, @AaronRobinsonMSFT . The reason that we have to use System.GC.Name is that we want to use the clrgc.dll in the current .NET runtime folder, such as "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\8.0.20\clrgc.dll". The path will change when .NET is upgraded.

@mangod9
Copy link
Member

mangod9 commented Sep 29, 2025

Is there a specific reason for using clrgc.dll? Are you still using segments based GC?

@heh-ad
Copy link

heh-ad commented Sep 29, 2025

We are using clrgc.dll because the default GC implementation will reserve more than 200 GB memory for the managed heap. This makes our capacity tests reporting false regressions. With clrgc.dll, the results restore to the previous level.

We are actually not aware other differences between the default GC and clrgc.dll.

@mangod9
Copy link
Member

mangod9 commented Sep 30, 2025

If its a memory reservation issue you can use the DOTNET_GCRegionRange setting to configure the reservation size. You should try that so that your application gets the benefits of the latest GC perf improvements, instead of falling back to clrgc (which mostly uses pre-.NET 7 GC)

@heh-ad
Copy link

heh-ad commented Sep 30, 2025

Thanks @mangod9 . I tried the DOTNET_GCRegionRange and it can really reduce the reservation size to the setting value. Is there a recommend value to set? If I set it as a small one, such as "1000000", then it will be unable to start the runtime. It works if set as "10000000". But will the reserved memory be expanded when there are more requirements later, or will it crash when the reserved memory is not enough?

@mangod9
Copy link
Member

mangod9 commented Sep 30, 2025

It's a static setting and the reservation size cannot be expanded. You should set it to something reasonable like the amount of physical memory on your VM/container. In .NET10 if you use Workstation GC the reservation size capped at 2 x physical memory.

@heh-ad
Copy link

heh-ad commented Sep 30, 2025

Thank you for the advice @mangod9. If the value is too big, then the capacity tests will still report false regressions. We will try to tune the value so that it will be enough and also be acceptable for the capacity tests.

@github-actions github-actions bot locked and limited conversation to collaborators Oct 31, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Custom GC is loaded from the wrong place in a C++/CLI program

3 participants