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

Added support for ImplMap entries and relationships for .NET binaries #54

Merged
merged 43 commits into from
Nov 20, 2023

Conversation

Czatar
Copy link
Collaborator

@Czatar Czatar commented Oct 9, 2023

Output for the "dotnetImplMap" key in the metadata shows the name of the DLL paired with a list of functions used from the DLL. Determining relationships works the same way as "dotnetAssemblyRef" entries.

@nightlark nightlark added the enhancement New feature or request label Oct 10, 2023
@@ -233,6 +238,17 @@ def get_assemblyref_info(asmref_info):
return asmref


def get_implmap_info(im_info, imp_modules):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
def get_implmap_info(im_info, imp_modules):
def get_implmap_info(im_info, imp_modules):

This is doing a bit more than just getting the implmap -- maybe call it add_implmap_info or insert_implmap_info instead to capture that it is also modifying part of the SBOM.

Comment on lines 84 to 85
if "dotnetImplMap" in metadata:
combinedRefs.append(metadata["dotnetImplMap"])
Copy link
Collaborator

Choose a reason for hiding this comment

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

What were the URLs/doc links that you referenced for info on how .NET determines where to look for the DLLs listed in ImplMap?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I was mistaken about unmanaged code loading being the same as loading assemblies. I got my sources mixed up, but I found the one that relates to ImplMap (PInvoked) libraries and included it. From what it looks like, if it's not the assembly/application directory, it's the system32 folder (default unless someone overrides the loading function).

Comment on lines 85 to 94
refName = None
refCulture = None
if "Name" in asmRef:
refName = asmRef["Name"]

# Aside from .deps.json, the assembly's install directory is searched
probedirs = get_dotnet_probedirs(software, refCulture, refName, dnProbingPaths)
for e in find_installed_software(sbom, probedirs, refName + ".dll"):
dependency_uuid = e.UUID
relationships.append(Relationship(dependent_uuid, dependency_uuid, "Uses"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

In addition to probing directories similar to .NET (or instead of depending on if we can determine whether or not this applies to loading unmanaged libraries), it looks like we need to have code that looks for relationships according to https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing#unmanaged-native-library-probing and searches for names/paths according to https://learn.microsoft.com/en-us/dotnet/standard/native-interop/native-library-loading when a relative path is given.

continue
refName = asmRef["Name"]
if is_absolute_path(refName):
relationships.extend(get_windows_pe_dependencies(sbom, software, [refName]))
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think the get_windows_pe_dependencies function does what we want when a dependency is specified using absolute paths -- the function itself constructs a list of probe directories relative to the software, which when the given path is absolute we don't care about searching, and then it calls the find_installed_software function internally to find a match, which appends the file name for an import (which in this case would be an absolute path) to each probe directory given in turn.

For an example of a program in C:/PrgFiles/Program.exe an absolute import of C:/SomeFolder/Dep.dll looks like it would result in the function trying to search for something like C:/PrgFiles/C:/Somefolder/Dep.dll.

For matching an import listed as an absolute dependency, I think we can have a loop that just looks for a Software entry with an install path that just matches the absolute import name, without any of the probe directory things in it.

ref_abspath = pathlib.PureWindowsPath(refName)
# iterate through all sbom entries
for e in sbom.software:
    # Skip if no install path (e.g. installer/temporary file)
    if e.installPath is None:
        continue
    if isinstance(e.installPath, Iterable):
        for ifile in e.installPath:
            # PureWindowsPath is case-insensitive for file/directory names
            if ref_abspath == pathlib.PureWindowsPath(ifile):
                # matching probe directory and filename, add relationship to list
                relationships.extend(Relationship(dependent_uuid, e.uuid, "Uses"))

for ifile in e.installPath:
if ref_abspath == pathlib.PureWindowsPath(ifile):
relationships.extend(Relationship(dependent_uuid, e.uuid, "Uses"))
relationships.extend(get_windows_pe_dependencies(sbom, software, [refName]))
Copy link
Collaborator

@nightlark nightlark Nov 20, 2023

Choose a reason for hiding this comment

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

I don't think the line calling get_windows_pe_dependencies should be present - haven't confirmed, but in that function it is appending refName (which in this case is an absolute path such as C:/Somefolder/Dep.dll) with the path software is located in, so it will just be searching for garbage paths like C:/Program Files/softwareinstalldir/C:/Somefolder/Dep.dll that are actually invalid path names on Windows (: is not allowed in folder names) so the files it is looking for should never exist.

@nightlark nightlark merged commit 999eca7 into main Nov 20, 2023
@nightlark nightlark deleted the CYT-579-dotNet-ImplMap-Support branch November 20, 2023 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants