コード例 #1
0
        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));
        }
コード例 #2
0
        public void CreateSortedVersionDictionary_ParsesAsExpected()
        {
            PropertiesDictionary versionList = this.GenerateMachineFamilyData();

            CompilerVersionToMitigation[] result = EnableSpectreMitigations.CreateSortedVersionDictionary(versionList);

            this.ValidateResultFromFakeTestData(result);
        }
コード例 #3
0
        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));
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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 });
        }
コード例 #6
0
        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));
        }
コード例 #7
0
        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)));
        }
コード例 #8
0
        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()));
        }
コード例 #9
0
        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)));
        }