Skip to content

Conversation

@LLLXXXCCC
Copy link

fixes #1806

<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>
Copy link

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)) ||
Copy link

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)) ||
Copy link

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;
}
Copy link

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?

Copy link
Author

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
Copy link

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]
Copy link

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?

Copy link
Author

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.

MicrosoftNetCoreAnalyzersResources.ResourceManager,
typeof(MicrosoftNetCoreAnalyzersResources));

private const int UnsafeBits = 2 | 256;
Copy link

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.

Copy link
Author

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.

Copy link

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.

<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>
Copy link

@dotpaul dotpaul Jul 30, 2019

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?

Copy link

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? 🙂

Copy link
Author

Choose a reason for hiding this comment

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

NP.

Copy link

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"? 🙂


[Theory]
[InlineData("")]
[InlineData("dotnet_code_quality.CA5392.unsafe_DllImportSearchPath_bits = 2 | 256")]
Copy link

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>());
}
Copy link

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.


rule = DoNotUseUnsafeDllImportSearchPathRule;
ruleArgument = ((DllImportSearchPath)validBits).ToString();
}
Copy link

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.

Copy link

@dotpaul dotpaul left a comment

Choose a reason for hiding this comment

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

🚢

@Zenexer
Copy link

Zenexer commented Sep 17, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add security diagnostic for DefaultDllImportSearchPathsAttribute

4 participants