public override void Eval(FlowController flow, MemoryEntry code) { //extend current program point as Eval var codes = new HashSet <string>(); foreach (StringValue possibleFile in code.PossibleValues) { codes.Add(possibleFile.Value); } foreach (var branchKey in flow.ExtensionKeys) { if (!codes.Remove(branchKey as string)) { //this eval is now not resolved as possible eval branch flow.RemoveExtension(branchKey); } } foreach (var sourceCode in codes) { //Create graph for every evaluated code - NOTE: we can share pp graphs var cfg = AnalysisTestUtils.CreateCFG(sourceCode, null); var ppGraph = ProgramPointGraph.FromSource(cfg); flow.AddExtension(sourceCode, ppGraph, ExtensionType.ParallelEval); } }
public override void Include(FlowController flow, MemoryEntry includeFile) { //extend current program point as Include var files = new HashSet <string>(); foreach (StringValue possibleFile in includeFile.PossibleValues) { files.Add(possibleFile.Value); } foreach (var branchKey in flow.ExtensionKeys) { if (!files.Remove(branchKey as string)) { //this include is now not resolved as possible include branch flow.RemoveExtension(branchKey); } } foreach (var file in files) { //Create graph for every include - NOTE: we can share pp graphs var cfg = AnalysisTestUtils.CreateCFG(_includes[file], null); var ppGraph = ProgramPointGraph.FromSource(cfg); flow.AddExtension(file, ppGraph, ExtensionType.ParallelInclude); } }
/// <inheritdoc /> public override void Eval(FlowController flow, MemoryEntry code) { var flags = FlagsHandler.GetFlags(code.PossibleValues); if (flags.isDirty(FlagType.FilePathDirty) || flags.isDirty(FlagType.SQLDirty) || flags.isDirty(FlagType.FilePathDirty)) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisSecurityWarning(flow.CurrentScript.FullName, "Eval shoudn't contain anything from user input", flow.CurrentPartial, flow.CurrentProgramPoint, FlagType.HTMLDirty)); } double evalDepth = 0; var maxValue = new MaxValueVisitor(flow.OutSet); evalDepth = maxValue.Evaluate(flow.OutSet.GetControlVariable(FunctionResolver.evalDepth).ReadMemory(flow.OutSet.Snapshot)); if (evalDepth > 3) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, @"Eval cannot be called in ""eval recursion"" more than 3 times", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.TOO_DEEP_EVAL_RECURSION)); return; } StringConverter converter = new StringConverter(); converter.SetContext(flow); bool isAllwasConcrete = true; var codes = new HashSet <string>(); foreach (StringValue possibleFile in converter.Evaluate(code, out isAllwasConcrete)) { codes.Add(string.Format("<? {0}; ?>", possibleFile.Value)); } if (isAllwasConcrete == false) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Couldn't resolve all possible evals", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.COULDNT_RESOLVE_ALL_EVALS)); } foreach (var branchKey in flow.ExtensionKeys) { if (branchKey is string) { if (!codes.Remove(branchKey as string)) { //this eval is now not resolved as possible eval branch flow.RemoveExtension(branchKey); } } } int numberOfWarnings = 0; foreach (var sourceCode in codes) { try { var cfg = ControlFlowGraph.ControlFlowGraph.FromSource(sourceCode, flow.CurrentScript.FullName); var ppGraph = ProgramPointGraph.FromSource(cfg); flow.AddExtension(sourceCode, ppGraph, ExtensionType.ParallelEval); } catch (ControlFlowGraph.ControlFlowException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Control flow graph creation error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.CFG_EXCEPTION_IN_INCLUDE_OR_EVAL)); } catch (Parsers.ParserException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Parser error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.PARSER_EXCEPTION_IN_INCLUDE_OR_EVAL)); } } if (numberOfWarnings > 0) { if (numberOfWarnings == codes.Count && isAllwasConcrete == true) { fatalError(flow, true); } else { fatalError(flow, false); } } }
/// <summary> /// Is called after each include/require/include_once/require_once expression (can be resolved according to flow.CurrentPartial) /// </summary> /// <param name="flow">Flow controller where include extensions can be stored</param> /// <param name="includeFile">File argument of include statement</param> public override void Include(FlowController flow, MemoryEntry includeFile) { if (FlagsHandler.IsDirty(includeFile.PossibleValues, FlagType.FilePathDirty)) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisSecurityWarning(flow.CurrentScript.FullName, flow.CurrentPartial, flow.CurrentProgramPoint, FlagType.FilePathDirty, "")); } bool isAlwaysConcrete = true; //extend current program point as Include List <string> files = FunctionResolver.GetFunctionNames(includeFile, flow, out isAlwaysConcrete); if (isAlwaysConcrete == false) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Couldn't resolve all possible includes", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.COULDNT_RESOLVE_ALL_INCLUDES)); } IncludingEx includeExpression = flow.CurrentPartial as IncludingEx; foreach (var branchKey in flow.ExtensionKeys) { if (!files.Remove(branchKey as string)) { //this include is now not resolved as possible include branch flow.RemoveExtension(branchKey); } } int numberOfWarnings = 0; var includedFiles = flow.OutSet.GetControlVariable(new VariableName(".includedFiles")).ReadMemory(flow.OutSet.Snapshot); foreach (var file in files) { var fileInfo = findFile(flow, file); if (fileInfo == null) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "The file " + file + " to be included not found", flow.CurrentProgramPoint.Partial, flow.CurrentProgramPoint, AnalysisWarningCause.FILE_TO_BE_INCLUDED_NOT_FOUND)); numberOfWarnings++; continue; } string fileName = fileInfo.FullName; // Handling include_once, require_once var varIncluded = flow.OutSet.GetControlVariable(new VariableName(fileName)); if (includeExpression.InclusionType == InclusionTypes.IncludeOnce || includeExpression.InclusionType == InclusionTypes.RequireOnce) { var includedInfo = varIncluded.ReadMemory(flow.OutSet.Snapshot); if (includedInfo != null) { var includeType = (includeExpression.InclusionType == InclusionTypes.IncludeOnce) ? "include_once" : "require_once"; if (includedInfo.PossibleValues.Count() > 1) { //TODO: report or not? //AnalysisWarningHandler.SetWarning (flow.OutSet, new AnalysisWarning (flow.CurrentScript.FullName, includeType + " is called more times in some program paths with the file " + fileName, flow.CurrentProgramPoint.Partial, flow.CurrentProgramPoint, AnalysisWarningCause.INCLUDE_REQUIRE_ONCE_CALLED_MORE_TIMES_WITH_SAME_FILE)); // TODO: include the file or not?? continue; } else { if (!(includedInfo.PossibleValues.First() is UndefinedValue)) { //TODO: report or not? //AnalysisWarningHandler.SetWarning (flow.OutSet, new AnalysisWarning (flow.CurrentScript.FullName, includeType + " is called more times with the file " + fileName, flow.CurrentProgramPoint.Partial, flow.CurrentProgramPoint, AnalysisWarningCause.INCLUDE_REQUIRE_ONCE_CALLED_MORE_TIMES_WITH_SAME_FILE)); continue; } } } } // Avoid recursive includes // the file was never included int numberOfIncludes = -1; // TODO: optimization - avoid iterating all included files // - make .includedFiles associative array with names of functions as indexes foreach (InfoValue <NumberOfCalls <string> > includeInfo in includedFiles.PossibleValues.Where(a => (a is InfoValue <NumberOfCalls <string> >))) { if (includeInfo.Data.Callee == fileName) { numberOfIncludes = Math.Max(numberOfIncludes, includeInfo.Data.TimesCalled); } } if (numberOfIncludes >= 0) { if (numberOfIncludes > 2 || sharedFiles.Contains(fileName)) { if (sharedFiles.Contains(fileName)) { //set graph sharing for this function if (!sharedProgramPoints.ContainsKey(fileName)) { try { //create single graph instance sharedProgramPoints[fileName] = ProgramPointGraph.FromSource(ControlFlowGraph.ControlFlowGraph.FromFile(fileInfo)); } catch (ControlFlowGraph.ControlFlowException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Control flow graph creation error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.CFG_EXCEPTION_IN_INCLUDE_OR_EVAL)); } catch (Parsers.ParserException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Parser error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.PARSER_EXCEPTION_IN_INCLUDE_OR_EVAL)); } } //get shared instance of program point graph flow.AddExtension(fileName, sharedProgramPoints[fileName], ExtensionType.ParallelInclude); continue; } else { sharedFiles.Add(fileName); } } } try { // Write information about inclusion of the file varIncluded.WriteMemory(flow.OutSet.Snapshot, new MemoryEntry(flow.OutSet.Snapshot.CreateBool(true))); //Create graph for every include - NOTE: we can share pp graphs var cfg = ControlFlowGraph.ControlFlowGraph.FromFile(fileInfo); var ppGraph = ProgramPointGraph.FromSource(cfg); flow.AddExtension(fileName, ppGraph, ExtensionType.ParallelInclude); } catch (ControlFlowGraph.ControlFlowException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Control flow graph creation error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.CFG_EXCEPTION_IN_INCLUDE_OR_EVAL)); } catch (Parsers.ParserException) { numberOfWarnings++; AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(flow.CurrentScript.FullName, "Parser error", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.PARSER_EXCEPTION_IN_INCLUDE_OR_EVAL)); } } if (numberOfWarnings > 0 && (includeExpression.InclusionType == InclusionTypes.Require || includeExpression.InclusionType == InclusionTypes.RequireOnce)) { if (numberOfWarnings == files.Count && isAlwaysConcrete == true) { fatalError(flow, true); } else { fatalError(flow, false); } } }