-
| Dear everybody, CodeQL Query: /**
 * @name Static slicing
 * @description An attempt to perform a static slice
 * @id cs/static-slicing
 * @problem.severity error
 * @precision very-high
 * @tags security
 * @kind path-problem
 */
import csharp
import semmle.code.csharp.security.dataflow.flowsources.Remote
import semmle.code.csharp.commons.Util
import semmle.code.csharp.dataflow.DataFlow::DataFlow::PathGraph
import semmle.code.csharp.controlflow.Guards
import semmle.code.csharp.controlflow.BasicBlocks
import semmle.code.csharp.ExprOrStmtParent
class TaintTrackingConfiguration extends TaintTracking::Configuration {
  TaintTrackingConfiguration() { this = "CustomSlice" }
  override predicate isSource(DataFlow::Node source) {
    any()
  }
  override predicate isSink(DataFlow::Node sink) {
     sink.asExpr().getLocation().getFile().getAbsolutePath().indexOf("Program.cs") > 0
	 and sink.asExpr().getLocation().getStartLine() = 12 // Target of the slicer (catching the variable result)
  }
  // An attempt to add the control dependencies
  override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
    exists (Guard g, BasicBlock b, AbstractValue v | 
        g.getAControlFlowNode() = pred.getControlFlowNode() and
        b.getANode() = succ.getControlFlowNode() and
        g.controlsBasicBlock(b, v)
      )
  }
}
from TaintTrackingConfiguration c, DataFlow::PathNode source, DataFlow::PathNode sink
where c.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Msg", source.getNode(), "Msg"So I run this query to the next source code: using System;
namespace example2
{
	public class Program
	{
		public static void Main(string[] args)
		{
			int levels = 5;
			TreeNode root = new TreeNode(levels);
			int result = root.addTree(); // *
			var slicingVariable1 = result; // *
			System.Console.WriteLine("Done!");
		}
	}
	internal class TreeNode
	{
		private int value = 0;
		private TreeNode left = null;
		private TreeNode right = null;
		internal TreeNode(int levels)
		{
			value = 1;
			if (levels <= 1)
			{
				if (levels <= 0)
					throw new System.Exception("Number of levels must be positive no.");
				left = null;
				right = null;
			}
			else
			{
				left = new TreeNode(levels - 1);
				right = new TreeNode(levels - 1);
			}
		}
		internal virtual int addTree()
		{
			int total = value; // *
			if (left != null) // *
				total += left.addTree(); // *
			if (right != null) // *
				total += right.addTree(); // *
			return total; // *
		}
	}
}After running the query I collect every line in every path, and I get these lines: {11, 12, 42, 43, 44, 45, 46, 47} (marked with // *). For example, Any suggestions? | 
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 2 replies
-
| Hi @asoifer, I'm sorry to say that our data-flow analysis has a specific limitation that disallows defining sources/sinks of a data-flow configuration based on paths found with that configuration. For the security queries we are writing, that has not been a big problem so far. In some cases, we've had to have two layers of data-flow, which we have managed by just introducing a separate copy of the whole data-flow analysis, and then each part can sit in it's own "layer". In this way we can define sources/sinks in one layer based on the results form the other layer. For C# this would be DataFlow, DataFlow2, DataFlow3, DataFlow4, DataFlow5. And as an example of actually combining such two layers, I will highlight path injection query in Python. But I think this would at best be a band-aid for the specific problem you are trying to solve, where I would assume you want to reach a fixed point, and not just do a few iterations at most. Also sorry for the very late reply. This question somehow slipped off the radar 😐 | 
Beta Was this translation helpful? Give feedback.
Hi @asoifer,
I'm sorry to say that our data-flow analysis has a specific limitation that disallows defining sources/sinks of a data-flow configuration based on paths found with that configuration. For the security queries we are writing, that has not been a big problem so far. In some cases, we've had to have two layers of data-flow, which we have managed by just introducing a separate copy of the whole data-flow analysis, and then each part can sit in it's own "layer". In this way we can define sources/sinks in one layer based on the results form the other layer.
For C# this would be DataFlow, DataFlow2, DataFlow3, DataFlow4, DataFlow5. And as an example of actually combining such two la…