-
Notifications
You must be signed in to change notification settings - Fork 480
Use DefaultDllImportSearchPaths attribute #2658
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
Use DefaultDllImportSearchPaths attribute #2658
Conversation
…hub.com/LLLXXXCCC/roslyn-analyzers into UseDefaultDllImportSearchPathsAttribute
| <value>Use DefaultDllImportSearchPaths Attribute For P/Invokes</value> | ||
| </data> | ||
| <data name="UseDefaultDllImportSearchPathsAttributeDescription" xml:space="preserve"> | ||
| <value>By default, P/Invokes using DllImportAttribute probe a number of directories, including the current working directory for the library to load. This can be a security issue for certain applications, leading to dll hijacking.</value> |
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.
dll [](start = 220, length = 3)
DLL
| var dllPath = constructorArguments[0].Value.ToString(); | ||
|
|
||
| if ((Path.IsPathRooted(dllPath) && | ||
| dllPath.EndsWith(".dll", StringComparison.Ordinal)) || |
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.
Ordinal [](start = 70, length = 7)
OrdinalIgnoreCase
| var dllPath = constructorArguments[0].Value.ToString(); | ||
|
|
||
| if ((Path.IsPathRooted(dllPath) && | ||
| dllPath.EndsWith(".dll", StringComparison.Ordinal)) || |
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.
Does it matter whether or not it ends in ".dll"?
| if (compilation.Assembly.GetAttributes().Select(o => o.AttributeClass).Contains(defaultDllImportSearchPathsAttributeTypeSymbol)) | ||
| { | ||
| hasDefaultDllImportSearchPathsAttribute = 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.
If there's an assembly level DefaultDllImportSearchPaths, do we need to do anything further?
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.
DllImportSearchPath.AssemblyDirectory, DllImportSearchPath.LegacyBehavior, DllImportSearchPath.UseDllDirectoryForDependencies.
If these 3 flag were used in DefaultDllImportSearchPaths, it will still search in the default order when it can't find the DLL in the specified path.
I don't know if we should take this into consideration.
| // 3. The system directory, usually C:\\Windows\\System32\\ (The GetSystemDirectory function is called to obtain this directory.). | ||
| // 4. The 16-bit system directory – There is no dedicated function to retrieve the path of this directory, but it is searched as well. | ||
| // 5. The Windows directory. The GetWindowsDirectory function is called to obtain this directory. | ||
| // 6. The directories that are listed in the PATH environment variable |
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 don't think we should try to document behavior here, since it varies a lot, we're unlikely to be accurate.
|
|
||
| // [DllImport] is set with an absolute path, which will let the [DefaultDllImportSearchPaths] be ignored. | ||
| // So user32.dll will also be searched in the default order. | ||
| [Fact] |
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.
It doesn't just load from the absolute path?
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.
You are right, wrong comment.
…hub.com/LLLXXXCCC/roslyn-analyzers into UseDefaultDllImportSearchPathsAttribute
…hub.com/LLLXXXCCC/roslyn-analyzers into LLLXXXCCC-UseDefaultDllImportSearchPathsAttribute
… UseDefaultDllImportSearchPathsAttribute
| MicrosoftNetCoreAnalyzersResources.ResourceManager, | ||
| typeof(MicrosoftNetCoreAnalyzersResources)); | ||
|
|
||
| private const int UnsafeBits = 2 | 256; |
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.
2 | 256; [](start = 39, length = 8)
Add a comment for what these values are.
Given that we're treating AssemblyDirectory as potentially dangerous, should do the same for ApplicationDirectory.
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.
When using ApplicationDirectory, it won't search by the default order after it didn't find the target DLL in the application directory. When using AssemblyDirectory, it does, that's why we treat it as potentially dangerous.
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 think the attack scenario of executing an application with elevated privileges from a user's "Downloads" directory, which contains a malicious DLL, is something we should worry about. In that case, I think ApplicationDirectory is also a problem, because it's going to include the "Downloads" directory.
src/Microsoft.NetCore.Analyzers/Core/Security/UseDefaultDllImportSearchPathsAttribute.cs
Outdated
Show resolved
Hide resolved
| <value>Do not create tasks without passing a TaskScheduler</value> | ||
| </data> | ||
| <data name="UseDefaultDllImportSearchPathsAttribute" xml:space="preserve"> | ||
| <value>Use DefaultDllImportSearchPaths attribute for P/Invokes</value> |
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.
Use DefaultDllImportSearchPaths attribute for P/Invokes [](start = 11, length = 55)
Trying to think of a title/message/description kinda makes me think we should have a separate rule for checking the value. What do you think?
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.
If you thumbs up the comment, does that mean you're going to add another rule? 🙂
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.
NP.
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.
Is that a "yes let's have a separate diagnostic if the value has unsafe bits", or a "no let's use the same diagnostic"? 🙂
...crosoft.NetCore.Analyzers/UnitTests/Security/UseDefaultDllImportSearchPathsAttributeTests.cs
Outdated
Show resolved
Hide resolved
|
|
||
| [Theory] | ||
| [InlineData("")] | ||
| [InlineData("dotnet_code_quality.CA5392.unsafe_DllImportSearchPath_bits = 2 | 256")] |
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.
2 | 256 [](start = 82, length = 7)
This case doesn't prove that the parsing works. Without me looking at the code, it could be just using the default value. It could just be parsing the 2 and ignoring the rest.
Add a unit test for say "1 | 1024", and see if [DefaultDllImportSearchPaths(DillImportSearchPath.UserDirectories)] will produce a diagnostic.
| }", | ||
| GetEditorConfigAdditionalFile(editorConfigText), | ||
| Array.Empty<DiagnosticResult>()); | ||
| } |
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.
So doesn't this case show that the | syntax in analyzer config integer values doesn't work? We shouldn't use | as an example in the Analyzer Configuration.md in the documentation.
src/Microsoft.NetCore.Analyzers/Core/MicrosoftNetCoreAnalyzersResources.resx
Outdated
Show resolved
Hide resolved
src/Microsoft.NetCore.Analyzers/Core/Security/UseDefaultDllImportSearchPathsAttribute.cs
Outdated
Show resolved
Hide resolved
|
|
||
| rule = DoNotUseUnsafeDllImportSearchPathRule; | ||
| ruleArgument = ((DllImportSearchPath)validBits).ToString(); | ||
| } |
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.
Not a huge deal, but may want to consider refactoring so you don't have to repeat this code and the code below.
src/Microsoft.NetCore.Analyzers/Core/MicrosoftNetCoreAnalyzersResources.resx
Outdated
Show resolved
Hide resolved
...crosoft.NetCore.Analyzers/UnitTests/Security/UseDefaultDllImportSearchPathsAttributeTests.cs
Outdated
Show resolved
Hide resolved
dotpaul
left a comment
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.
🚢
fixes #1806