Skip to content

Commit

Permalink
[ifds] feat: reasons, runnerId property, IfdsResult
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeypospelov committed Apr 4, 2024
1 parent 3880b3b commit 7e765d4
Show file tree
Hide file tree
Showing 37 changed files with 942 additions and 241 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
* limitations under the License.
*/

package org.jacodb.ifds.taint
package org.jacodb.ifds

import org.jacodb.ifds.domain.Analyzer
import org.jacodb.ifds.domain.Edge
import org.jacodb.ifds.domain.FlowFunction
import org.jacodb.ifds.domain.FlowScope
import org.jacodb.ifds.domain.RunnerType
import org.jacodb.ifds.domain.RunnerId
import org.jacodb.ifds.messages.AnalyzerMessage
import org.jacodb.ifds.messages.CommonMessage
import org.jacodb.ifds.messages.EdgeMessage
import org.jacodb.ifds.messages.NewSummaryEdge
import org.jacodb.ifds.messages.NotificationOnStart
import org.jacodb.ifds.messages.ResolvedCall
import org.jacodb.ifds.messages.UnresolvedCall
Expand All @@ -35,10 +34,10 @@ import org.jacodb.api.ext.cfg.callExpr

typealias TaintFlowScope<Fact> = FlowScope<JcInst, Fact>

class TaintAnalyzer<Fact>(
class DefaultAnalyzer<Fact>(
private val applicationGraph: JcApplicationGraph,
private val flowFunction: FlowFunction<JcInst, Fact>,
private val runnerType: RunnerType,
private val runnerId: RunnerId,
) : Analyzer<JcInst, Fact> {
override fun step(message: AnalyzerMessage<JcInst, Fact>): Collection<CommonMessage> = buildList {
when (message) {
Expand Down Expand Up @@ -73,13 +72,12 @@ class TaintAnalyzer<Fact>(

when {
callExpr != null -> processCall(edge)
isExit -> processExit(edge)
else -> processSequent(edge)
!isExit -> processSequent(edge)
}
}

private fun TaintFlowScope<Fact>.processCall(edge: Edge<JcInst, Fact>) {
val callMessage = UnresolvedCall(edge)
val callMessage = UnresolvedCall(runnerId, edge)
add(callMessage)

val successors = applicationGraph.successors(edge.to.stmt)
Expand All @@ -91,11 +89,6 @@ class TaintAnalyzer<Fact>(
}
}

private fun TaintFlowScope<Fact>.processExit(edge: Edge<JcInst, Fact>) {
val summaryEdge = NewSummaryEdge(runnerType, edge)
add(summaryEdge)
}

private fun TaintFlowScope<Fact>.processSequent(edge: Edge<JcInst, Fact>) {
val successors = applicationGraph.successors(edge.to.stmt)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,25 @@
* limitations under the License.
*/

package org.jacodb.ifds.taint
package org.jacodb.ifds

import org.jacodb.analysis.ifds.Analyzer
import org.jacodb.api.cfg.JcInst
import org.jacodb.ifds.domain.Edge
import org.jacodb.ifds.domain.FlowFunction
import org.jacodb.ifds.domain.FlowScope
import org.jacodb.ifds.domain.RunnerType
import org.jacodb.ifds.domain.Reason
import org.jacodb.ifds.domain.RunnerId
import org.jacodb.ifds.domain.Vertex
import org.jacodb.ifds.messages.NewEdge
import org.jacodb.ifds.messages.SubscriptionOnStart
import org.jacodb.analysis.ifds.Analyzer
import org.jacodb.api.cfg.JcInst

typealias JcEventProcessor<Fact, Event> = FlowScope<JcInst, Fact>.(Event) -> Unit

class JcFlowFunctionsAdapter<Fact, Event>(
private val runnerType: RunnerType,
private val runnerId: RunnerId,
private val jcAnalyzer: Analyzer<Fact, Event>,
private val jcEventProcessor: FlowScope<JcInst, Fact>.(Event) -> Unit,
private val jcEventProcessor: JcEventProcessor<Fact, Event>,
) : FlowFunction<JcInst, Fact> {
private val jcFlowFunctions = jcAnalyzer.flowFunctions

Expand All @@ -40,7 +42,7 @@ class JcFlowFunctionsAdapter<Fact, Event>(
.compute(edge.to.fact)
.forEach { newFact ->
val newEdge = Edge(edge.from, Vertex(next, newFact))
processNewEdge(runnerType, newEdge)
processNewEdge(runnerId, newEdge, Reason.Sequent(edge))
}

override fun FlowScope<JcInst, Fact>.callToReturn(returnSite: JcInst) =
Expand All @@ -49,7 +51,7 @@ class JcFlowFunctionsAdapter<Fact, Event>(
.compute(edge.to.fact)
.forEach { newFact ->
val newEdge = Edge(edge.from, Vertex(returnSite, newFact))
processNewEdge(runnerType, newEdge)
processNewEdge(runnerId, newEdge, Reason.CallToReturn(edge))
}

override fun FlowScope<JcInst, Fact>.callToStart(calleeStart: JcInst) =
Expand All @@ -59,11 +61,11 @@ class JcFlowFunctionsAdapter<Fact, Event>(
.forEach { newFact ->
val vertex = Vertex(calleeStart, newFact)

val subscription = SubscriptionOnStart(runnerType, vertex, runnerType, edge)
val subscription = SubscriptionOnStart(runnerId, vertex, runnerId, edge)
add(subscription)

val newEdge = Edge(vertex, vertex)
processNewEdge(runnerType, newEdge)
processNewEdge(runnerId, newEdge, Reason.CallToStart(edge))
}

override fun FlowScope<JcInst, Fact>.exitToReturnSite(
Expand All @@ -74,23 +76,26 @@ class JcFlowFunctionsAdapter<Fact, Event>(
.compute(edge.to.fact)
.forEach { newFact ->
val newEdge = Edge(callerEdge.from, Vertex(returnSite, newFact))
processNewEdge(runnerType, newEdge)
processNewEdge(runnerId, newEdge, Reason.ExitToReturnSite(callerEdge, edge))
}

private fun FlowScope<JcInst, Fact>.processNewEdge(
runnerType: RunnerType,
runnerId: RunnerId,
newEdge: Edge<JcInst, Fact>,
reason: Reason<JcInst, Fact>,
) {
val edge = NewEdge(runnerType, newEdge, edge)
val edge = NewEdge(runnerId, newEdge, reason)
add(edge)

val jcEvents = jcAnalyzer.handleNewEdge(newEdge.toJcEdge())
for (event in jcEvents) {
jcEventProcessor(event)
}

}
}

private fun <Fact> Vertex<JcInst, Fact>.toJcVertex() = org.jacodb.analysis.ifds.Vertex(stmt, fact)
private fun <Fact> Edge<JcInst, Fact>.toJcEdge() = org.jacodb.analysis.ifds.Edge(from.toJcVertex(), to.toJcVertex())

fun <Fact> org.jacodb.analysis.ifds.Vertex<Fact>.toVertex() = Vertex(statement, fact)
fun <Fact> org.jacodb.analysis.ifds.Edge<Fact>.toEdge() = Edge(from.toVertex(), to.toVertex())
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package org.jacodb.ifds.taint
package org.jacodb.ifds

import org.jacodb.actors.api.Actor
import org.jacodb.actors.api.ActorContext
Expand All @@ -27,6 +27,7 @@ import org.jacodb.api.cfg.JcVirtualCallExpr
import org.jacodb.api.ext.HierarchyExtension
import org.jacodb.api.ext.cfg.callExpr
import org.jacodb.api.ext.isSubClassOf
import org.jacodb.ifds.domain.RunnerId
import org.jacodb.ifds.messages.CommonMessage
import org.jacodb.ifds.messages.IndirectionMessage
import org.jacodb.ifds.messages.ResolvedCall
Expand All @@ -37,6 +38,7 @@ class IndirectionHandler(
private val hierarchy: HierarchyExtension,
private val bannedPackagePrefixes: List<String>,
private val parent: ActorRef<CommonMessage>,
private val runnerId: RunnerId,
) : Actor<IndirectionMessage> {
private val cache = hashMapOf<JcMethod, List<JcMethod>>()

Expand All @@ -55,13 +57,13 @@ class IndirectionHandler(
val callExpr = node.callExpr as? JcVirtualCallExpr
if (callExpr == null) {
for (override in callees) {
parent.send(ResolvedCall(message.edge, override))
parent.send(ResolvedCall(runnerId, message.edge, override))
}
return
}
val instanceClass = (callExpr.instance.type as? JcClassType)?.jcClass
if (instanceClass == null) {
parent.send(ResolvedCall(message.edge, callExpr.method.method))
parent.send(ResolvedCall(runnerId, message.edge, callExpr.method.method))
return
}

Expand All @@ -79,7 +81,7 @@ class IndirectionHandler(
}

for (override in overrides) {
parent.send(ResolvedCall(message.edge, override))
parent.send(ResolvedCall(runnerId, message.edge, override))
}
}
}
57 changes: 57 additions & 0 deletions jacodb-analysis/src/main/kotlin/org/jacodb/ifds/JcIfdsContext.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.ifds

import org.jacodb.actors.api.ActorRef
import org.jacodb.actors.api.Factory
import org.jacodb.api.JcClasspath
import org.jacodb.api.analysis.JcApplicationGraph
import org.jacodb.api.cfg.JcInst
import org.jacodb.ifds.domain.Analyzer
import org.jacodb.ifds.domain.ChunkId
import org.jacodb.ifds.domain.FlowFunction
import org.jacodb.ifds.domain.IfdsContext
import org.jacodb.ifds.domain.RunnerId
import org.jacodb.ifds.messages.CommonMessage
import org.jacodb.impl.features.HierarchyExtensionImpl

class JcIfdsContext<Fact>(
private val cp: JcClasspath,
private val graph: JcApplicationGraph,
private val bannedPackagePrefixes: List<String>,
private val flowFunctionFactory: (ChunkId, RunnerId) -> FlowFunction<JcInst, Fact>,
) : IfdsContext<JcInst, Fact> {
data object SingleChunk : ChunkId

override fun chunkByMessage(message: CommonMessage): ChunkId =
SingleChunk

override fun runnerIdByMessage(message: CommonMessage): RunnerId =
message.runnerId

override fun getAnalyzer(chunkId: ChunkId, runnerId: RunnerId): Analyzer<JcInst, Fact> =
DefaultAnalyzer(
graph,
flowFunctionFactory(chunkId, runnerId),
runnerId
)

override fun indirectionHandlerFactory(parent: ActorRef<CommonMessage>, runnerId: RunnerId) =
Factory {
IndirectionHandler(HierarchyExtensionImpl(cp), bannedPackagePrefixes, parent, runnerId)
}
}
67 changes: 67 additions & 0 deletions jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Context.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.ifds.npe

import org.jacodb.analysis.npe.NpeAnalyzer
import org.jacodb.analysis.taint.EdgeForOtherRunner
import org.jacodb.analysis.taint.NewVulnerability
import org.jacodb.analysis.taint.TaintDomainFact
import org.jacodb.api.JcClasspath
import org.jacodb.api.analysis.JcApplicationGraph
import org.jacodb.ifds.JcFlowFunctionsAdapter
import org.jacodb.ifds.JcIfdsContext
import org.jacodb.ifds.messages.NewResult
import org.jacodb.ifds.messages.NewSummaryEdge
import org.jacodb.ifds.toEdge

fun npeIfdsContext(
cp: JcClasspath,
graph: JcApplicationGraph,
bannedPackagePrefixes: List<String>,
): JcIfdsContext<TaintDomainFact> =
JcIfdsContext(
cp,
graph,
bannedPackagePrefixes
) { _, runnerId ->
val analyzer = when (runnerId) {
is SingleRunner -> NpeAnalyzer(graph)
else -> error("Unexpected runnerId: $runnerId")
}

JcFlowFunctionsAdapter(
runnerId,
analyzer
) { event ->
when (event) {
is EdgeForOtherRunner -> {
error("Unexpected event: $event")
}

is org.jacodb.analysis.taint.NewSummaryEdge -> {
val summaryEdge = NewSummaryEdge(runnerId, event.edge.toEdge())
add(summaryEdge)
}

is NewVulnerability -> {
val result = NewResult(runnerId, NpeVulnerability(event.vulnerability))
add(result)
}
}
}
}

31 changes: 31 additions & 0 deletions jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Results.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.ifds.npe

import org.jacodb.analysis.taint.TaintDomainFact
import org.jacodb.analysis.taint.TaintVulnerability
import org.jacodb.api.cfg.JcInst
import org.jacodb.ifds.domain.Vertex
import org.jacodb.ifds.toVertex
import org.jacodb.ifds.result.IfdsResult

data class NpeVulnerability(
val vulnerability: TaintVulnerability,
) : IfdsResult<JcInst, TaintDomainFact> {
override val vertex: Vertex<JcInst, TaintDomainFact>
get() = vulnerability.sink.toVertex()
}
21 changes: 21 additions & 0 deletions jacodb-analysis/src/main/kotlin/org/jacodb/ifds/npe/Runners.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright 2022 UnitTestBot contributors (utbot.org)
* <p>
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.jacodb.ifds.npe

import org.jacodb.ifds.domain.RunnerId

data object SingleRunner : RunnerId
Loading

0 comments on commit 7e765d4

Please sign in to comment.