diff --git a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/CheckForPoison.cs b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/CheckForPoison.cs index b8d3ffe24..1ac545724 100644 --- a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/CheckForPoison.cs +++ b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/CheckForPoison.cs @@ -4,7 +4,6 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -using Mono.Cecil; using System; using System.Collections; using System.Collections.Generic; @@ -12,6 +11,7 @@ using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; +using System.Reflection; using System.Security.Cryptography; using System.Text; using System.Xml; @@ -261,22 +261,10 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection try { - memStream.Seek(0, SeekOrigin.Begin); - using (var asm = AssemblyDefinition.ReadAssembly(memStream)) + AssemblyName asm = AssemblyName.GetAssemblyName(fileToCheck); + if (IsAssemblyPoisoned(fileToCheck)) { - foreach (var a in asm.CustomAttributes) - { - foreach (var ca in a.ConstructorArguments) - { - if (ca.Type.Name == asm.MainModule.TypeSystem.String.Name) - { - if (ca.Value.ToString().Contains(PoisonMarker)) - { - poisonEntry.Type |= PoisonType.AssemblyAttribute; - } - } - } - } + poisonEntry.Type |= PoisonType.AssemblyAttribute; } } catch @@ -287,6 +275,27 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection return poisonEntry.Type != PoisonType.None ? poisonEntry : null; } + private static bool IsAssemblyPoisoned(string path) + { + byte[] buffer = File.ReadAllBytes(path); + byte[] marker = Encoding.UTF8.GetBytes(PoisonMarker); + + // Start at end of file and go backwards + // Marker is likely at the end and this saves time when + // we encounter a poisoned file. + for (int j = buffer.Length - marker.Length; j >= 0; j--) + { + int i; + for (i = 0; i < marker.Length && buffer[j + i] == marker[i]; i++) ; + if (i == marker.Length) + { + return true; + } + } + + return false; + } + private static PoisonedFileEntry ExtractAndCheckZipFileOnly(IEnumerable catalogedPackages, string zipToCheck, string markerFileName, string tempDir, Queue futureFilesToCheck) { var poisonEntry = new PoisonedFileEntry(); diff --git a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs index 0ef1ed0af..270fb11f9 100644 --- a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs +++ b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/MarkAndCatalogPackages.cs @@ -4,8 +4,6 @@ using Microsoft.Build.Framework; using Microsoft.Build.Utilities; -using Mono.Cecil; -using Mono.Collections.Generic; using System; using System.Collections.Generic; using System.IO; @@ -87,24 +85,23 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection var packageTempPath = Path.Combine(tempDir.FullName, Path.GetFileName(p.ItemSpec)); ZipFile.ExtractToDirectory(p.ItemSpec, packageTempPath, true); - foreach (string f in Directory.EnumerateFiles(packageTempPath, "*", SearchOption.AllDirectories)) + foreach (string file in Directory.EnumerateFiles(packageTempPath, "*", SearchOption.AllDirectories)) { // remove signatures so we don't later fail validation - if (Path.GetFileName(f) == ".signature.p7s") + if (Path.GetFileName(file) == ".signature.p7s") { - File.Delete(f); + File.Delete(file); continue; } var catalogFileEntry = new CatalogFileEntry(); packageEntry.Files.Add(catalogFileEntry); - catalogFileEntry.Path = Utility.MakeRelativePath(f, packageTempPath); - AssemblyDefinition asm = null; + catalogFileEntry.Path = Utility.MakeRelativePath(file, packageTempPath); // There seem to be some weird issues with using a file stream both for hashing and // assembly loading, even closing it in between. Use a MemoryStream to avoid issues. var memStream = new MemoryStream(); - using (var stream = File.OpenRead(f)) + using (var stream = File.OpenRead(file)) { stream.CopyTo(memStream); } @@ -113,49 +110,23 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection memStream.Seek(0, SeekOrigin.Begin); catalogFileEntry.OriginalHash = sha.ComputeHash(memStream); - // Now try to read it as an assembly - memStream.Seek(0, SeekOrigin.Begin); + // Add poison marker to assemblies try { - asm = AssemblyDefinition.ReadAssembly(memStream, new ReaderParameters(ReadingMode.Deferred)); + AssemblyName asm = AssemblyName.GetAssemblyName(file); + Poison(file); + + // then get the hash of the now-poisoned file + using (var stream = File.OpenRead(file)) + { + catalogFileEntry.PoisonedHash = sha.ComputeHash(stream); + } } catch { - // this is okay, it's not an assembly we can read + // this is okay, it's not an assembly } - // if we read it, now poison and write it back out - if (asm != null) - { - Poison(asm); - - try - { - // Cecil doesn't try to do some modifications until it writes out the file, - // and then throws after we've already truncated the file if it finds out it can't do them. - // Write to a memory stream first and then copy to the real stream if it suceeds. If it - // fails, we won't truncate the file and we will depend on hashes instead in that case. - using (var testMemStream = new MemoryStream()) - { - asm.Write(testMemStream); - testMemStream.Seek(0, SeekOrigin.Begin); - using (var stream = File.Open(f, FileMode.Create, FileAccess.ReadWrite)) - { - testMemStream.CopyTo(stream); - } - } - - // then get the hash of the now-poisoned file - using (var stream = File.OpenRead(f)) - { - catalogFileEntry.PoisonedHash = sha.ComputeHash(stream); - } - } - catch - { - // see above note in the try - this is okay. - } - } } if (!string.IsNullOrWhiteSpace(MarkerFileName)) @@ -203,16 +174,6 @@ namespace Microsoft.DotNet.SourceBuild.Tasks.LeakDetection return !Log.HasLoggedErrors; } - private void Poison(AssemblyDefinition asm) - { - foreach (var attr in asm.CustomAttributes) - { - if (this.AssemblyPropertiesToReplace.Any(p => p.Name == attr.AttributeType.Name)) - { - attr.ConstructorArguments.Clear(); - attr.ConstructorArguments.Add(new CustomAttributeArgument(asm.MainModule.TypeSystem.String, "POISONED by DotNetSourceBuild - Should not ship")); - } - } - } + private void Poison(string path) => File.AppendAllText(path, PoisonMarker); } } diff --git a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection.csproj b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection.csproj index 72dc0a037..8598377a2 100644 --- a/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection.csproj +++ b/src/SourceBuild/content/eng/tools/tasks/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection/Microsoft.DotNet.SourceBuild.Tasks.LeakDetection.csproj @@ -13,12 +13,6 @@ 15.7.179 - - Configuration=netstandard_Debug - Configuration=netstandard_Release - {D68133BD-1E63-496E-9EDE-4FBDBF77B486} - Mono.Cecil -