-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Fix UseManagedNtlm linker substitutions #90957
Conversation
- Specify the default value (false) for the feature on Linux so the linker runs the substitution when no value was specified by the user. - Make the `UseManagedNtlm` property public because the linker and IL compiler doesn't support substitution of private properties. - Add `--ignore-substitutions` switch to ILLink during library build to prevent the substitution with default value taking place.
Tagging subscribers to this area: @dotnet/ncl, @bartonjs, @vcsjones Issue Details
Tested with the following code: using System.Net.Security;
var negAuth = new NegotiateAuthentication(new NegotiateAuthenticationClientOptions { });
negAuth.GetOutgoingBlob("", out _); It saves around 100Kb when this code is published with Fixes #90898
|
cc @sbomer @vitek-karas ... I find it odd that there was no other use of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about you call it ILLink.Substitutions.Apple.xml
? OSXLike
does not exist in any other file.
(misclicked Approve 😅)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have no strong preference on this, but Apple sounds good. There's at least one other case where OSX
is used for both macOS and iOS.
This feature switch is a bit weird currently:
I would recommend:
That should not be the case - we have internal properties which are substituted - for example runtime/src/libraries/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs Line 25 in 23b2ea3
runtime/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml Line 12 in 23b2ea3
|
@sbomer, @ivanpovazan, @eerhardt what do you think? You all have done something similar in the past (I really haven't) so maybe there's something I overlooked. |
I am fine with introducing SDK property to control this. There are two reasons why I didn't do it at this point. Firstly, I am not aware of any precedent where the default value of the property depends on the platform, and the default value was really a moving target ( Secondly, I was considering a backport of minimal fix of this substitution to .NET 8. Doing that across several repos makes that prohibitively expensive fix.
Let me rephrase that, it didn't work for |
After trying several different things, I couldn't come up with a solution that I would be happy with... I submitted PR to dotnet/sdk for adding internal
|
Where is this enumeration? I do not think ILC should be skipping private methods for substitutions. |
runtime/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/BodySubstitutionParser.cs Line 59 in 0c4329b
|
This does not have any filtering based on the visibility. It should be enumerating all methods. |
<!-- Linux Bionic doesn't ship GSSAPI, so enable managed implementation --> | ||
<_UseManagedNtlm Condition="'$(_UseManagedNtlm)' == '' and '$(_linuxLibcFlavor)' == 'bionic'">true</_UseManagedNtlm> | ||
<!-- Trim managed NTLM on Linux when it's not explicitly requested --> | ||
<_UseManagedNtlm Condition="'$(_UseManagedNtlm)' == '' and '$(_targetOS)' == 'linux'">false</_UseManagedNtlm> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this only for Native AOT apps? Wouldn't we want this default value set when just PublishTrimmed=true
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am open to placing it on a better place but I didn't really find one. As stated above, it's unfortunate that this logic would have to be in sync between dotnet/sdk (linked build-time check) and dotnet/runtime (non-linked runtime check).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<PropertyGroup Condition="'$(PublishTrimmed)' == 'true'"> |
Maybe this is the right place?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As stated above, it's unfortunate that this logic would have to be in sync between dotnet/sdk (linked build-time check) and dotnet/runtime (non-linked runtime check).
I view it as a hierarchy. The runtime check is obviously the ultimate decision maker - so for example, if the given feature doesn't exist on a given platform, runtime will simply not do it, no matter what. On platforms where it's optional, the responsibility is on the SDK to decide what the value should be - which is kind of the same as saying the app's developer should decide for a specific app.
The trimming process itself should not modify the value, it just "hardcodes" it into the IL (and while doing that removes the code which can't be used anymore after the hardcoding happens). Even without trimming SDK writes it into the app (.runtimeconfig.json
) it just so happens that it's not completely hardcoded, but in reality nobody edits that JSON after build really.
Inside the SDK we have multiple considerations what to set the default value to - what we think makes sense for the developer. It would make sense to set it to false if the target platform doesn't support it, but not doing so doesn't really change much (other than consistency), unless we need it for size reasons, then we should do it. Other than that, we may for example decide on a different default for trimming/AOT. We typically do that if it's likely people don't need the feature and it saves a lot of size. An example of a similar approach is the globalization support, which is off for NativeAOT. But we can probably find others as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The UseManagedNtlm
feature has the following considerations:
- It's supported on some Unix platforms only (ie. the code is hard-coded on Windows, Android, and tvOS)
- On the platforms where the switch has effect the user may override it to either
false
(only use GSSAPI, even if it's buggy on particular platform) ortrue
(always use managed NTLM and SPNEGO implementations, use GSSAPI for Kerberos only). - The default value is
false
on Linux, FreeBSD (Linux Bionic is odd exception, so let's ignore it for now);true
on macOS, iOS / .NET 9+;false
on macOS, iOS / .NET 8. This is implemented as fallback in theUseManagedNtlm
property if the AppContext switch doesn't exist. - If we are doing trimming and the default value is
false
according to the rules above we want to remove the managed NTLM/SPNEGO implementation to save space. It's not expected that the AppContext switch would be modified at runtime.
I updated the PR to set the _UseManagedNtlm
property in Microsoft.NET.ILLink.targets. That seems to have effect both for PublishTrimmed
and PublishAot
. It's also part of the dotnet/runtime repository which lessens my concern about the defaults becoming out-of-sync.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To add a bit more context, the reasons why the user may want to change the value of the switch:
- On Linux the NTLM module for GSSAPI is optional, so setting
UseManagedNtlm=true
provides an alternative to installing GSS-NTLMSSP package. Many distributions also ship very old version of GSS-NTLMSSP, so this also ensure more consistent behaviour across all environments where the application is deployed. - On macOS there are multiple known bugs in the NTLM implementation. This includes sending the credentials in slightly different way, which may result in failed authentication even for credentials that work on Linux/Windows, and there are buffer overflows in the native code. Changing the default was deemed risky at the late .NET 8 stage, but we switched it for .NET 9. Thus on .NET 8 users may want to opt-in with
UseManagedNtlm=true
. - For users that don't rely on NTLM but rely on Kerberos, setting
UseManagedNtlm=false
may provide size savings.
src/libraries/System.Net.Security/src/System/Net/NegotiateAuthenticationPal.Unix.cs
Outdated
Show resolved
Hide resolved
…s from NativeAOT targets to ILLink ones
This was because there are no other uses of We don't have a way to delay the substitution of |
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
I do have one question. Would it make sense to enable trimming (via substitutions) even when _UseManagedNtlm=true
?
Probably not. That remaining code is still used for Kerberos regardless of the value of the switch. It would only save one AppContext.GetData call. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Depends on dotnet/sdk#34903.
Tested with the following code:
It saves around 100Kb when this code is published with
dotnet publish -p:PublishAot=true
.Fixes #90898