public void CreateSortedVersionDictionary_BadVersionRange_ThrowsException() { var versionList = new PropertiesDictionary(); versionList.Add("8.0.0.0 - 1.0.0.0", (CompilerMitigations.D2GuardSpecLoadAvailable).ToString()); Assert.Throws <InvalidOperationException>(() => EnableSpectreMitigations.CreateSortedVersionDictionary(versionList)); }
public void CreateSortedVersionDictionary_ParsesAsExpected() { PropertiesDictionary versionList = this.GenerateMachineFamilyData(); CompilerVersionToMitigation[] result = EnableSpectreMitigations.CreateSortedVersionDictionary(versionList); this.ValidateResultFromFakeTestData(result); }
public void CreateSortedVersionDictionary_OverlappingVersionRange_ThrowsException(string firstRange, string secondRange) { var versionList = new PropertiesDictionary(); versionList.Add(firstRange, (CompilerMitigations.D2GuardSpecLoadAvailable).ToString()); versionList.Add(secondRange, (CompilerMitigations.QSpectreAvailable).ToString()); Assert.Throws <InvalidOperationException>(() => EnableSpectreMitigations.CreateSortedVersionDictionary(versionList)); }
public void GetCompilerData_VersionPresent_WorksAsExpected(string versionStr, ExtendedMachine machine, CompilerMitigations expectedMitgations) { var context = new BinaryAnalyzerContext(); context.Policy = new PropertiesDictionary(); AddFakeConfigTestData(context.Policy); CompilerMitigations actualMitigations = EnableSpectreMitigations.GetAvailableMitigations(context, machine, new Version(versionStr)); Assert.Equal(expectedMitgations, actualMitigations); }
public void LoadCompilerDataFromConfig_ParsesAndCachesAsExpected() { var context = new BinaryAnalyzerContext(); context.Policy = new PropertiesDictionary(); AddFakeConfigTestData(context.Policy); Dictionary <MachineFamily, CompilerVersionToMitigation[]> result = EnableSpectreMitigations.LoadCompilerDataFromConfig(context.Policy); ValidateResultFromFakeTestData(result[MachineFamily.X86]); result.Should().ContainKeys(new MachineFamily[] { MachineFamily.X86, MachineFamily.Arm }); }
public void GetNextCompilerVersionUp_WithSpectreMitigations_WorksAsExpected(string firstVersionStr, ExtendedMachine machine, string expectedVersionStr) { Version actualVersion = new Version(firstVersionStr); var context = new BinaryAnalyzerContext(); context.Policy = new PropertiesDictionary(); AddFakeConfigTestData(context.Policy); Version nextUp = EnableSpectreMitigations.GetClosestCompilerVersionWithSpectreMitigations(context, machine, actualVersion); nextUp.ShouldBeEquivalentTo(new Version(expectedVersionStr)); }
public void GetClosestCompilerVersionWithSpectreMitigations_UnsupportedOnMachine() { BinaryAnalyzerContext context = new BinaryAnalyzerContext(); context.Policy = new PropertiesDictionary(); PropertiesDictionary BA2024Config = new PropertiesDictionary(); PropertiesDictionary mitigatedCompilers = new PropertiesDictionary(); PropertiesDictionary fakeX86Data = GenerateMachineFamilyData(); mitigatedCompilers.Add(MachineFamily.X86.ToString(), fakeX86Data); BA2024Config.Add("MitigatedCompilers", mitigatedCompilers); context.Policy.Add("BA2024.EnableSpectreMitigations.Options", BA2024Config); Assert.Null(EnableSpectreMitigations.GetClosestCompilerVersionWithSpectreMitigations(context, ExtendedMachine.Arm, new Version(1, 0, 100, 5))); }
public override void AnalyzePortableExecutableAndPdb(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); Pdb pdb = target.Pdb; Version minCompilerVersion; minCompilerVersion = (target.PE.IsXBox) ? context.Policy.GetProperty(MinimumToolVersions)[MIN_XBOX_COMPILER_VER] : context.Policy.GetProperty(MinimumToolVersions)[MIN_COMPILER_VER]; TruncatedCompilandRecordList badModuleList = new TruncatedCompilandRecordList(); StringToVersionMap allowedLibraries = context.Policy.GetProperty(AllowedLibraries); foreach (DisposableEnumerableView <Symbol> omView in pdb.CreateObjectModuleIterator()) { Symbol om = omView.Value; ObjectModuleDetails omDetails = om.GetObjectModuleDetails(); if (omDetails.WellKnownCompiler != WellKnownCompilers.MicrosoftNativeCompiler) { continue; } // See if the item is in our skip list if (!string.IsNullOrEmpty(om.Lib)) { string libFileName = string.Concat(System.IO.Path.GetFileName(om.Lib), ",", omDetails.Language.ToString()).ToLowerInvariant(); Version minAllowedVersion; if (allowedLibraries.TryGetValue(libFileName, out minAllowedVersion) && omDetails.CompilerVersion >= minAllowedVersion) { continue; } } Version actualVersion; Version minimumVersion; Language omLanguage = omDetails.Language; switch (omLanguage) { case Language.C: case Language.Cxx: actualVersion = Minimum(omDetails.CompilerVersion, omDetails.CompilerFrontEndVersion); minimumVersion = minCompilerVersion; break; default: continue; } bool foundIssue = actualVersion < minimumVersion; AdvancedMitigations advancedMitigations = context.Policy.GetProperty(AdvancedMitigationsEnforced); if (!foundIssue && (advancedMitigations & AdvancedMitigations.Spectre) == AdvancedMitigations.Spectre) { ExtendedMachine machineType = (ExtendedMachine)target.PE.Machine; // Current toolchain is within the version range to validate. // Now we'll retrieve relevant compiler mitigation details to // ensure this object module's build and revision meet // expectations. CompilerMitigations newMitigationData = EnableSpectreMitigations.GetAvailableMitigations(context, machineType, actualVersion); // Current compiler version does not support Spectre mitigations. foundIssue = !newMitigationData.HasFlag(CompilerMitigations.D2GuardSpecLoadAvailable) && !newMitigationData.HasFlag(CompilerMitigations.QSpectreAvailable); if (foundIssue) { // Get the closest compiler version that has mitigations--i.e. if the user is using a 19.0 (VS2015) compiler, we should be recommending an upgrade to the // 19.0 version that has the mitigations, not an upgrade to a 19.10+ (VS2017) compiler. // Limitation--if there are multiple 'upgrade to' versions to recommend, this just going to give users the last one we see in the error. minCompilerVersion = EnableSpectreMitigations.GetClosestCompilerVersionWithSpectreMitigations(context, machineType, actualVersion); // Indicates Spectre mitigations are not supported on this platform. We won't flag this case. if (minCompilerVersion == null) { foundIssue = false; } } } if (foundIssue) { // built with {0} compiler version {1} (Front end version: {2}) badModuleList.Add( om.CreateCompilandRecordWithSuffix( String.Format(CultureInfo.InvariantCulture, RuleResources.BA2006_Error_BadModule, omLanguage, omDetails.CompilerVersion, omDetails.CompilerFrontEndVersion))); } } if (!badModuleList.Empty) { // '{0}' was compiled with one or more modules which were not built using // minimum required tool versions (compiler version {1}). More recent toolchains // contain mitigations that make it more difficult for an attacker to exploit // vulnerabilities in programs they produce. To resolve this issue, compile // and /or link your binary with more recent tools. If you are servicing a // product where the tool chain cannot be modified (e.g. producing a hotfix // for an already shipped version) ignore this warning. Modules built outside // of policy: {2} context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Error, context, null, nameof(RuleResources.BA2006_Error), context.TargetUri.GetFileName(), minCompilerVersion.ToString(), badModuleList.CreateSortedObjectList())); return; } // All linked modules of '{0}' generated by the Microsoft front-end // satisfy configured policy (compiler minimum version {1}). context.Logger.Log(this, RuleUtilities.BuildResult(ResultLevel.Pass, context, null, nameof(RuleResources.BA2006_Pass), context.TargetUri.GetFileName(), minCompilerVersion.ToString())); }
public override void AnalyzePortableExecutableAndPdb(BinaryAnalyzerContext context) { PEBinary target = context.PEBinary(); Pdb pdb = target.Pdb; /* * This is disabled for now. It's not clear that we can * actually detect when a binary is compiled with a version * of csc.exe that is too stale. The reasons are twofold: * 1) Older versions of csc.exe did not version the version * data that is persisted to the PE. i.e., '48.0' was * emitted for numerous versions of the compiler. * 2) Our PDB reader does not current appear able to crack * PDBs generated by the older C# compilers. Needs to * be investigated. * if (target.PE.IsManaged && !target.PE.IsMixedMode) * { * AnalyzeManagedPE(context); * } */ Version minCompilerVersion; var goodCompilers = new HashSet <string>(); var badModules = new List <ObjectModuleDetails>(); StringToVersionMap allowedLibraries = context.Policy.GetProperty(AllowedLibraries); var languageToBadModules = new Dictionary <Language, List <ObjectModuleDetails> >(); foreach (DisposableEnumerableView <Symbol> omView in pdb.CreateObjectModuleIterator()) { Symbol om = omView.Value; ObjectModuleDetails omDetails = om.GetObjectModuleDetails(); switch (omDetails.Language) { case Language.LINK: { continue; } case Language.C: case Language.Cxx: { minCompilerVersion = (target.PE.IsXBox) ? context.Policy.GetProperty(MinimumToolVersions)[MIN_XBOX_COMPILER_VER] : context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.C)]; break; } //case Language.MASM: //{ // minCompilerVersion = // context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.MASM)]; // break; //} //case Language.CVTRES: //{ // minCompilerVersion = // context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.CVTRES)]; // break; //} //case Language.CSharp: //{ // minCompilerVersion = // context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.CSharp)]; // break; //} case Language.Unknown: { minCompilerVersion = context.Policy.GetProperty(MinimumToolVersions)[nameof(Language.Unknown)]; break; } default: { continue; } } // See if the item is in our skip list if (!string.IsNullOrEmpty(om.Lib)) { string libFileName = string.Concat(System.IO.Path.GetFileName(om.Lib), ",", omDetails.Language.ToString()).ToLowerInvariant(); if (allowedLibraries.TryGetValue(libFileName, out Version minAllowedVersion) && omDetails.CompilerBackEndVersion >= minAllowedVersion) { continue; } } Version actualVersion; Version minimumVersion = minCompilerVersion; Language omLanguage = omDetails.Language; switch (omLanguage) { case Language.C: case Language.Cxx: { actualVersion = Minimum(omDetails.CompilerBackEndVersion, omDetails.CompilerFrontEndVersion); break; } case Language.LINK: case Language.MASM: case Language.CVTRES: { actualVersion = omDetails.CompilerBackEndVersion; break; } default: continue; } bool foundIssue = actualVersion < minimumVersion; AdvancedMitigations advancedMitigations = context.Policy.GetProperty(AdvancedMitigationsEnforced); if (!foundIssue && (advancedMitigations & AdvancedMitigations.Spectre) == AdvancedMitigations.Spectre) { var machineType = (ExtendedMachine)target.PE.Machine; // Current toolchain is within the version range to validate. // Now we'll retrieve relevant compiler mitigation details to // ensure this object module's build and revision meet // expectations. CompilerMitigations newMitigationData = EnableSpectreMitigations.GetAvailableMitigations(context, machineType, actualVersion); // Current compiler version does not support Spectre mitigations. foundIssue = !newMitigationData.HasFlag(CompilerMitigations.D2GuardSpecLoadAvailable) && !newMitigationData.HasFlag(CompilerMitigations.QSpectreAvailable); if (foundIssue) { // Get the closest compiler version that has mitigations--i.e. if the user is using a 19.0 (VS2015) compiler, we should be recommending an upgrade to the // 19.0 version that has the mitigations, not an upgrade to a 19.10+ (VS2017) compiler. // Limitation--if there are multiple 'upgrade to' versions to recommend, this just going to give users the last one we see in the error. minCompilerVersion = EnableSpectreMitigations.GetClosestCompilerVersionWithSpectreMitigations(context, machineType, actualVersion); // Indicates Spectre mitigations are not supported on this platform. We won't flag this case. if (minCompilerVersion == null) { foundIssue = false; } } } if (foundIssue) { badModules.Add(omDetails); } else { goodCompilers.Add(BuildCompilerIdentifier(omDetails)); } } if (badModules.Count != 0) { string badModulesText = badModules.CreateOutputCoalescedByCompiler(); string minimumRequiredCompilers = BuildMinimumCompilersList(context, languageToBadModules); // '{0}' was compiled with one or more modules which were not built using // minimum required tool versions ({1}). More recent toolchains // contain mitigations that make it more difficult for an attacker to exploit // vulnerabilities in programs they produce. To resolve this issue, compile // and /or link your binary with more recent tools. If you are servicing a // product where the tool chain cannot be modified (e.g. producing a hotfix // for an already shipped version) ignore this warning. Modules built outside // of policy: {2} context.Logger.Log(this, RuleUtilities.BuildResult(FailureLevel.Error, context, null, nameof(RuleResources.BA2006_Error), context.TargetUri.GetFileName(), minimumRequiredCompilers, badModulesText)); return; } string[] sorted = goodCompilers.ToArray(); Array.Sort(sorted); // All linked modules of '{0}' satisfy configured policy (observed compilers: {1}). context.Logger.Log(this, RuleUtilities.BuildResult(ResultKind.Pass, context, null, nameof(RuleResources.BA2006_Pass), context.TargetUri.GetFileName(), string.Join(", ", sorted))); }