Skip to content

SQL Taint Analysis #109

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 76 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
3b3e206
Improved IFDS analysis, including demos and tests; by Mario Trageser
Mar 5, 2021
eb91c75
Merge branch 'develop' into feature/IDFS-improvements
May 27, 2021
31c4c6b
Create new project "ll"
buenaventure Jun 29, 2021
a26ee83
Add llvm bindings dependency
buenaventure Jun 29, 2021
9490098
Merge branch 'develop' into feature/IDFS-improvements
TorunR Jun 30, 2021
1a3b939
Read and dump module
buenaventure Jul 5, 2021
34d4e25
Begin implementing wrappers
buenaventure Jul 6, 2021
53da4de
Read instructions
buenaventure Jul 7, 2021
283ef68
AndroidEntryPointFinder added
Diarilex Jul 14, 2021
c88385a
Implement SimplePurityAnalysis which assumes everything to be Impure
buenaventure Nov 8, 2021
bca47d7
Merge branch 'develop' into feature/IDFS-improvements
TorunR Nov 10, 2021
c87f9ac
Implement SimplePurityAnalysis
buenaventure Nov 12, 2021
df11561
Implement viewCFG
buenaventure Nov 12, 2021
75f01ea
Merge pull request #3 from buenaventure/develop
buenaventure Dec 2, 2021
79cf52a
Merge remote-tracking branch 'upstream/develop' into ll
buenaventure Jan 5, 2022
905ad98
Add simple multilingual test project
buenaventure Jan 6, 2022
c624d84
Merge remote-tracking branch 'upstream/develop' into feature/IDFS-imp…
buenaventure Feb 17, 2022
bb079fd
Merge branch 'develop' into ll
buenaventure Feb 17, 2022
9ccee79
Add taint testcase
buenaventure Feb 5, 2022
6ab61f6
Merge branch 'feature/IDFS-improvements' into ll_multiling_ifds
buenaventure Feb 18, 2022
b99997c
Format code
buenaventure Feb 18, 2022
90c179a
Adapt new ifds to new call graph (with context)
buenaventure Feb 21, 2022
a464309
Add multilingual taint test
buenaventure Feb 23, 2022
7d00973
Extract IFDSProblem(flow functions etc) from IFDSAnalysis
buenaventure Mar 2, 2022
e3838cf
Replace specialized ifds analysis classes with parameter
buenaventure Mar 2, 2022
633c377
WIP
buenaventure Mar 5, 2022
cc84ea1
WIP
buenaventure Mar 10, 2022
cb4f4f7
WIP
buenaventure Mar 10, 2022
41d949c
WIP
buenaventure Mar 11, 2022
0b40422
WIP
buenaventure Mar 16, 2022
54bb807
WIP
buenaventure Mar 16, 2022
76a1c27
WIP (compiles)
buenaventure Mar 17, 2022
2bfaeea
Initialization fix
buenaventure Mar 17, 2022
6df8fab
Implement LLVM Argument, Type(s); Better Function/Instruction represe…
buenaventure Mar 18, 2022
f92c953
Move IFDS into separate project; Refactor handling of calls outside o…
buenaventure Mar 18, 2022
3931605
Re-implement ifds solver
buenaventure Mar 24, 2022
3ee3a04
Use new implementation for native part
buenaventure Mar 24, 2022
25d0f19
Implement forward taint analysis as test for new ifds solver
buenaventure Mar 25, 2022
3283b03
Fix new forward taint analysis
buenaventure Mar 31, 2022
313fd9a
Fix scalariformat and other compile errors
buenaventure Mar 31, 2022
75be229
Refactor: Move old code to .old, remove New prefix
buenaventure Apr 1, 2022
847baa5
First native flows working
buenaventure Apr 1, 2022
7d47c14
Fix native flows
buenaventure Apr 13, 2022
5e9cfaf
Cleanup
buenaventure May 6, 2022
16a99ae
Include llvm dependency using special sbt plugin
buenaventure May 6, 2022
89c1ff7
Fix sbt assembly
buenaventure May 11, 2022
89b91ca
Reverst scalastyle change
buenaventure May 11, 2022
91bae7d
Improve test case
buenaventure Jun 8, 2022
ed4ee71
Fix test
buenaventure Jun 9, 2022
626cce9
Fix wrong flow by adding successor to return flow and checking for ab…
buenaventure Jun 9, 2022
f34443b
Fix return flow of native code
buenaventure Jun 9, 2022
7284093
Format
buenaventure Jun 9, 2022
ab242a9
Add native to java calls to TaintTest
buenaventure Jun 16, 2022
c53aa61
Fix crashes and old tests
buenaventure Jun 17, 2022
943d7a1
Add debugData for ifds; Add simple GetElementPointer handling
buenaventure Jun 18, 2022
cb0be34
Native to Java calls WIP
buenaventure Jun 19, 2022
d3ab854
Small fixes
buenaventure Jun 22, 2022
b6a2202
JNI call analysis WIP
buenaventure Jun 25, 2022
e5d34a1
JNI call analysis WIP
buenaventure Jun 26, 2022
ec8c05a
Merge remote-tracking branch 'upstream/develop' into llvm_xlang_ifds
buenaventure Jun 30, 2022
ad65890
Fix most errors after merge
buenaventure Jun 30, 2022
c050890
Fix remaining errors after merge
buenaventure Jul 1, 2022
655d22a
Implement VTA in new IFDS for evaluation
buenaventure Jul 2, 2022
b844920
Implement Subsuming and add to evaluation
buenaventure Jul 2, 2022
d43fb11
x-lang working in simple case
buenaventure Jul 2, 2022
8baacc6
Add javascript aware taint analysis
t1mlange Sep 22, 2022
d10d586
Add TODOs marking 'things left open' in the code
t1mlange Sep 29, 2022
05a0ebe
Introducing a taint demo and make it work
roterEmil Oct 21, 2022
0848636
renaming js -> sql and other little improvements
roterEmil Oct 21, 2022
3f78e27
reveresed renaming
roterEmil Oct 21, 2022
cee3b62
InitialChanges
Imagee Oct 22, 2022
d1240d1
First ClassTest successfully
Imagee Nov 22, 2022
41d729f
SqlFacts included
Imagee Nov 30, 2022
16a2b85
evaluations
Imagee Jan 11, 2023
e04f4dd
String Analyzer cleaned
Imagee Feb 20, 2023
40d1a91
String Analyzer cleaned
Imagee Feb 20, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
/*package org.opalj
package fpcf
package analyses

import java.io.File

import scala.collection.immutable.ListSet
import scala.io.Source

import org.opalj.log.LogContext
import org.opalj.fpcf.seq.PKESequentialPropertyStore
import org.opalj.br.fpcf.FPCFAnalysesManagerKey
import org.opalj.br.fpcf.PropertyStoreKey
import org.opalj.br.DeclaredMethod
import org.opalj.br.Method
import org.opalj.br.ObjectType
import org.opalj.br.MethodDescriptor
import org.opalj.br.analyses.Project
import org.opalj.br.analyses.SomeProject
import org.opalj.br.analyses.Project.JavaClassFileReader
import org.opalj.ai.domain.l1
import org.opalj.ai.fpcf.analyses.LazyL0BaseAIAnalysis
import org.opalj.ai.fpcf.properties.AIDomainFactoryKey
import org.opalj.tac.Assignment
import org.opalj.tac.Expr
import org.opalj.tac.Var
import org.opalj.tac.ReturnValue
import org.opalj.tac.Call
import org.opalj.tac.fpcf.properties.IFDSProperty
import org.opalj.tac.fpcf.properties.IFDSPropertyMetaInformation
import org.opalj.tac.fpcf.analyses.AbstractIFDSAnalysis.V
import org.opalj.tac.fpcf.analyses.AbstractIFDSAnalysis
import org.opalj.tac.fpcf.analyses.Statement
import org.opalj.tac.fpcf.analyses.IFDSAnalysis
import org.opalj.tac.fpcf.analyses.TACAITransformer

trait Fact
case object NullFact extends Fact
case class Variable(index: Int) extends Fact
case class FlowFact(flow: ListSet[Method]) extends Fact {
override val hashCode: Int = {
// HERE, a foldLeft introduces a lot of overhead due to (un)boxing.
var r = 1
flow.foreach(f => r = (r + f.hashCode()) * 31)
r
}
}
class FinalFact(flow: ListSet[Method]) extends FlowFact(flow)
object FinalFact {
def unapply(arg: FinalFact): Some[ListSet[Method]] = Some(arg.flow)
}

/**
* A simple IFDS taint analysis.
*
* @author Dominik Helm
*/
class PRATaintAnalysis private (
implicit
val project: SomeProject
) extends AbstractIFDSAnalysis[Fact] {

override val property: IFDSPropertyMetaInformation[Fact] = Taint

override def createProperty(result: Map[Statement, Set[Fact]]): IFDSProperty[Fact] = {
new Taint(result)
}

override def normalFlow(stmt: Statement, succ: Statement, in: Set[Fact]): Set[Fact] =
stmt.stmt.astID match {
case Assignment.ASTID =>
handleAssignment(stmt, stmt.stmt.asAssignment.expr, in)
case _ => in
}

/**
* Returns true if the expression contains a taint.
*/
def isTainted(expr: Expr[V], in: Set[Fact]): Boolean = {
expr.isVar && in.exists {
case Variable(index) => expr.asVar.definedBy.contains(index)
case _ => false
}
}

def handleAssignment(stmt: Statement, expr: Expr[V], in: Set[Fact]): Set[Fact] =
expr.astID match {
case Var.ASTID =>
val newTaint = in.collect {
case Variable(index) if expr.asVar.definedBy.contains(index) =>
Some(Variable(stmt.index))
case _ => None
}.flatten
in ++ newTaint
case _ => in
}

override def callFlow(
stmt: Statement,
callee: DeclaredMethod,
in: Set[Fact]
): Set[Fact] = {
val call = asCall(stmt.stmt)
val allParams = call.receiverOption ++ asCall(stmt.stmt).params
if (isSink(call)) {
Set.empty
} else {
in.collect {
case Variable(index) => // Taint formal parameter if actual parameter is tainted
allParams.zipWithIndex.collect {
case (param, pIndex) if param.asVar.definedBy.contains(index) =>
Variable(paramToIndex(pIndex, !callee.definedMethod.isStatic))
}
}.flatten
}
}

override def returnFlow(
stmt: Statement,
callee: DeclaredMethod,
exit: Statement,
succ: Statement,
in: Set[Fact]
): Set[Fact] = {

/**
* Checks whether the formal parameter is of a reference type, as primitive types are
* call-by-value.
*/
def isRefTypeParam(index: Int): Boolean =
if (index == -1) true
else {
callee.descriptor.parameterType(
paramToIndex(index, includeThis = false)
).isReferenceType
}

val call = asCall(stmt.stmt)
if (isSource(call) && stmt.stmt.astID == Assignment.ASTID)
Set(Variable(stmt.index))
else {
val allParams = (asCall(stmt.stmt).receiverOption ++ asCall(stmt.stmt).params).toSeq
var flows: Set[Fact] = Set.empty
for (fact <- in) {
fact match {
case Variable(index) if index < 0 && index > -100 && isRefTypeParam(index) =>
// Taint actual parameter if formal parameter is tainted
val param =
allParams(paramToIndex(index, !callee.definedMethod.isStatic))
flows ++= param.asVar.definedBy.iterator.map(Variable)

case FlowFact(flow) =>
val newFlow = flow + stmt.method
flows += FlowFact(newFlow)
case _ =>
}
}

// Propagate taints of the return value
if (exit.stmt.astID == ReturnValue.ASTID && stmt.stmt.astID == Assignment.ASTID) {
val returnValue = exit.stmt.asReturnValue.expr.asVar
flows ++= in.collect {
case Variable(index) if returnValue.definedBy.contains(index) =>
Variable(stmt.index)
}
}

flows
}
}

/**
* Converts a parameter origin to the index in the parameter seq (and vice-versa).
*/
def paramToIndex(param: Int, includeThis: Boolean): Int =
(if (includeThis) -1 else -2) - param

override def callToReturnFlow(stmt: Statement, succ: Statement, in: Set[Fact]): Set[Fact] = {
val call = asCall(stmt.stmt)
if (isSink(call)) {
if (in.exists {
case Variable(index) =>
asCall(stmt.stmt).params.exists(p => p.asVar.definedBy.contains(index))
case _ => false
}) {
in ++ Set(FlowFact(ListSet(stmt.method)))
} else {
in
}
} else {
in
}
}

def isSource(call: Call[V]): Boolean = {
PRATaintAnalysis.sources.get((call.name, call.descriptor)).exists(p.classHierarchy.isSubtypeOf(_, call.declaringClass))
}

def isSink(call: Call[V]): Boolean = {
PRATaintAnalysis.sinks.get((call.name, call.descriptor)).exists(p.classHierarchy.isSubtypeOf(_, call.declaringClass))
}

val entryPoints: Map[DeclaredMethod, Fact] = (for {
m <- p.allMethodsWithBody
} yield declaredMethods(m) -> NullFact).toMap

}

object PRATaintAnalysis extends IFDSAnalysis[Fact] {
override def init(p: SomeProject, ps: PropertyStore) = new PRATaintAnalysis()(p)

override def property: IFDSPropertyMetaInformation[Fact] = Taint

var sources: Map[(String, MethodDescriptor), ObjectType] = _
var sinks: Map[(String, MethodDescriptor), ObjectType] = _
}

class Taint(val flows: Map[Statement, Set[Fact]]) extends IFDSProperty[Fact] {

override type Self = Taint

def key: PropertyKey[Taint] = Taint.key
}

object Taint extends IFDSPropertyMetaInformation[Fact] {
override type Self = Taint

val key: PropertyKey[Taint] = PropertyKey.create(
"PRATaint",
new Taint(Map.empty)
)
}

object PRATaintAnalysisRunner {

def main(args: Array[String]): Unit = {

val cp = new File(args(0)+"S")
val sources = new File(args(1))
val sinks = new File(args(2))

val p = Project(
JavaClassFileReader().ClassFiles(cp),
JavaClassFileReader().ClassFiles(new File("/home/dominik/Desktop/android.jar")),
libraryClassFilesAreInterfacesOnly = false,
Iterable.empty
)
p.getOrCreateProjectInformationKeyInitializationData(
PropertyStoreKey,
(context: List[PropertyStoreContext[AnyRef]]) => {
implicit val lg: LogContext = p.logContext
val ps = PKESequentialPropertyStore.apply(context: _*)
PropertyStore.updateDebug(false)
ps
}
)
p.updateProjectInformationKeyInitializationData(AIDomainFactoryKey)(
(i: Option[Set[Class[_ <: AnyRef]]]) => (i match {
case None => Set(classOf[l1.DefaultDomainWithCFGAndDefUse[_]])
case Some(requirements) => requirements + classOf[l1.DefaultDomainWithCFGAndDefUse[_]]
}): Set[Class[_ <: AnyRef]]
)

PRATaintAnalysis.sources = getList(sources)
PRATaintAnalysis.sinks = getList(sinks)

val ps = p.get(PropertyStoreKey)
val manager = p.get(FPCFAnalysesManagerKey)
val (_, analyses) =
manager.runAll(LazyL0BaseAIAnalysis, TACAITransformer, PRATaintAnalysis)

val entryPoints = analyses.collect { case (_, a: PRATaintAnalysis) => a.entryPoints }.head
for {
e <- entryPoints
flows = ps(e, PRATaintAnalysis.property.key)
fact <- flows.ub.asInstanceOf[IFDSProperty[Fact]].flows.values.flatten.toSet[Fact]
} {
fact match {
case FlowFact(flow) => println(s"flow: "+flow.map(_.toJava).mkString(", "))
case _ =>
}
}

}

def getList(file: File): Map[(String, MethodDescriptor), ObjectType] = {
(
for {
line <- Source.fromFile(file).getLines()
Array(declClass, returnType, signature, _) = line.split(' ')
index = signature.indexOf("(")
name = signature.substring(0, index)
parameters = signature.substring(index + 1, signature.length - 1)
jvmSignature = parameters.split(',').map(toJVMType).mkString("(", "", ")"+toJVMType(returnType))
descriptor = MethodDescriptor(jvmSignature)
} yield (name, descriptor) -> ObjectType(declClass.replace('.', '/'))
).toMap
}

def toJVMType(javaType: String): String = {
val trimmedType = javaType.trim
if (trimmedType.endsWith("[]")) "["+toJVMType(trimmedType.substring(0, trimmedType.length - 2))
else trimmedType match {
case "void" => "V"
case "byte" => "B"
case "char" => "C"
case "double" => "D"
case "float" => "F"
case "int" => "I"
case "long" => "J"
case "short" => "S"
case "boolean" => "Z"
case _ => "L"+trimmedType.replace('.', '/')+";"
}
}
}
*/
Loading