Skip to content

Commit

Permalink
Fix potential erroneous load of assembly
Browse files Browse the repository at this point in the history
This change makes the assembly resolve handler be more strict when
checking whether or not to load the YamlDotNet assembly.

This should prevent accidentally loading the YamlDotNet assembly as
a result of a request coming from another assembly that is looking
to load a different assembly.

Signed-off-by: Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
  • Loading branch information
gabriel-samfira committed Jan 22, 2025
1 parent 18c7894 commit 01b1b46
Showing 1 changed file with 14 additions and 7 deletions.
21 changes: 14 additions & 7 deletions powershell-yaml.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -34,33 +34,40 @@ function Invoke-LoadFile {
[string]$assemblyPath
)

$global:powershellYamlDotNetAssemblyPath = Join-Path $assemblyPath "YamlDotNet.dll"
$powershellYamlDotNetAssemblyPath = Join-Path $assemblyPath "YamlDotNet.dll"
$serializerAssemblyPath = Join-Path $assemblyPath "PowerShellYamlSerializer.dll"
$yamlAssembly = [Reflection.Assembly]::LoadFile($powershellYamlDotNetAssemblyPath)
$serializerAssembly = [Reflection.Assembly]::LoadFile($serializerAssemblyPath)

if ($PSVersionTable['PSEdition'] -eq 'Core') {
# Register the AssemblyResolve event to load dependencies manually. This seems to be needed only on
# PowerShell Core.
[System.AppDomain]::CurrentDomain.add_AssemblyResolve({
$resolver = {
param ($snd, $e)
# This event only needs to run once when the Invoke-LoadFile function is called.
# If it's called again, the variables defined in this functions will not be available,
# so we can safely ignore the event.
if (-not $serializerAssemblyPath -or -not $powershellYamlDotNetAssemblyPath) {
return $null
}
# Load YamlDotNet if it's requested by PowerShellYamlSerializer. Ignore other requests as they might
# originate from other assemblies that are not part of this module and which might have different
# versions of the module that they need to load.
if ($e.Name -like "*YamlDotNet*" -and $e.RequestingAssembly -like "*PowerShellYamlSerializer*" ) {
if ($e.Name -match "^YamlDotNet,*" -and $e.RequestingAssembly.Location -eq $serializerAssemblyPath) {
return [System.Reflection.Assembly]::LoadFile($powershellYamlDotNetAssemblyPath)
}

return $null
})
}
[System.AppDomain]::CurrentDomain.add_AssemblyResolve($resolver)
# Load the StringQuotingEmitter from PowerShellYamlSerializer to force the resolver handler to fire once.
# This will load the YamlDotNet assembly and expand the global variable $powershellYamlDotNetAssemblyPath.
# We then remove it to avoid polluting the global scope.
# This is an ugly hack I am not happy with.
$serializerAssembly.GetType("StringQuotingEmitter") | Out-Null

# Remove the resolver handler after it has been used.
[System.AppDomain]::CurrentDomain.remove_AssemblyResolve($resolver)
}

Remove-Variable -Name powershellYamlDotNetAssemblyPath -Scope Global
return @{ "yaml"= $yamlAssembly; "quoted" = $serializerAssembly }
}

Expand Down

0 comments on commit 01b1b46

Please sign in to comment.