Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ seqraOrg=seqra

seqraBuildVersion=2025.10.01.6b66511

seqraIrVersion=2026.01.21.17b5bbb
seqraConfigVersion=2026.01.21.57ada3f
seqraUtilVersion=2026.01.21.d61d52a
seqraIrVersion=2026.02.01.c54b6cc
seqraConfigVersion=2026.02.01.02e636c
seqraUtilVersion=2026.02.01.44bb600
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ import org.seqra.dataflow.configuration.jvm.Not
import org.seqra.dataflow.configuration.jvm.Or
import org.seqra.dataflow.configuration.jvm.PositionResolver
import org.seqra.dataflow.jvm.ap.ifds.JIRMarkAwareConditionExpr.Literal
import org.seqra.dataflow.jvm.ap.ifds.analysis.JIRMethodAnalysisContext
import org.seqra.dataflow.jvm.ap.ifds.taint.ContainsMarkOnAnyField
import org.seqra.dataflow.jvm.ap.ifds.taint.JIRBasicAtomEvaluator
import org.seqra.ir.api.common.cfg.CommonInst
import org.seqra.ir.api.jvm.cfg.JIRValue
import org.seqra.util.Maybe

class JIRMarkAwareConditionRewriter(
positionResolver: PositionResolver<Maybe<JIRValue>>,
typeChecker: JIRFactTypeChecker,
analysisContext: JIRMethodAnalysisContext,
statement: CommonInst,
) {
private val positiveAtomEvaluator = JIRBasicAtomEvaluator(negated = false, positionResolver, typeChecker)
private val negativeAtomEvaluator = JIRBasicAtomEvaluator(negated = true, positionResolver, typeChecker)
private val positiveAtomEvaluator = JIRBasicAtomEvaluator(negated = false, positionResolver, analysisContext, statement)
private val negativeAtomEvaluator = JIRBasicAtomEvaluator(negated = true, positionResolver, analysisContext, statement)

fun rewrite(condition: Condition): ExprOrConstant =
rewriteCondition(condition)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import org.seqra.dataflow.jvm.ap.ifds.alias.RefValue.Local
import org.seqra.ir.api.common.CommonMethod
import org.seqra.ir.api.common.cfg.CommonInst
import org.seqra.ir.api.jvm.cfg.JIRInst
import org.seqra.ir.api.jvm.cfg.JIRStringConstant
import org.seqra.jvm.graph.JApplicationGraph
import org.seqra.util.analysis.ApplicationGraph

Expand Down Expand Up @@ -110,8 +111,13 @@ class JIRIntraProcAliasAnalysis(
is RefValue.This -> AccessPathBase.This
is RefValue.Static -> AccessPathBase.ClassStatic(loc.type)
}
is LocalAlias.Alloc -> {
val assign = cur.stmt as? Stmt.Assign
val const = assign?.expr as? SimpleValue.RefConst
val stringConst = const?.expr as? JIRStringConstant
stringConst?.let { AccessPathBase.Constant("java.lang.String", it.value) }
}
is CallReturn,
is LocalAlias.Alloc,
is Unknown -> null
is HeapAlias -> error("unreachable")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class JIRMethodCallFlowFunction(
override fun propagateZeroToZero() = buildSet {
val conditionRewriter = JIRMarkAwareConditionRewriter(
CallPositionToJIRValueResolver(callExpr, returnValue),
analysisContext.factTypeChecker
analysisContext, statement
)

applySinkRules(
Expand Down Expand Up @@ -197,7 +197,7 @@ class JIRMethodCallFlowFunction(

val conditionRewriter = JIRMarkAwareConditionRewriter(
CallPositionToJIRValueResolver(callExpr, returnValue),
analysisContext.factTypeChecker
analysisContext, statement
)

val factReader = FinalFactReader(factAp, apManager)
Expand Down Expand Up @@ -270,7 +270,8 @@ class JIRMethodCallFlowFunction(

val simpleConditionEvaluator = JIRSimpleFactAwareConditionEvaluator(conditionRewriter, conditionEvaluator)

val cleaner = TaintCleanActionEvaluator()
val typeResolver = JIRMethodPositionBaseTypeResolver(method)
val cleaner = TaintCleanActionEvaluator(typeResolver)

val factReaderBeforeCleaner = FinalFactReader(callerFact, apManager)
val cleanerResults = applyCleaner(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.seqra.dataflow.configuration.jvm.TaintConfigurationItem
import org.seqra.dataflow.configuration.jvm.TaintMark
import org.seqra.dataflow.jvm.ap.ifds.CallPositionToJIRValueResolver
import org.seqra.dataflow.jvm.ap.ifds.JIRMarkAwareConditionRewriter
import org.seqra.dataflow.jvm.ap.ifds.JIRMethodPositionBaseTypeResolver
import org.seqra.dataflow.jvm.ap.ifds.TaintConfigUtils.applyCleanerActions
import org.seqra.dataflow.jvm.ap.ifds.taint.EvaluatedCleanAction
import org.seqra.dataflow.jvm.ap.ifds.taint.FinalFactReader
Expand Down Expand Up @@ -35,7 +36,7 @@ class JIRMethodCallRuleBasedSummaryRewriter(

JIRMarkAwareConditionRewriter(
CallPositionToJIRValueResolver(callExpr, returnValue),
analysisContext.factTypeChecker
analysisContext, statement
)
}

Expand Down Expand Up @@ -75,7 +76,8 @@ class JIRMethodCallRuleBasedSummaryRewriter(
fun rewriteSummaryFact(fact: FinalFactAp): List<Pair<FinalFactAp, FinalFactReader>> {
val startFactReader = FinalFactReader(fact, apManager)

val cleanEvaluator = TaintCleanActionEvaluator()
val typeResolver = JIRMethodPositionBaseTypeResolver(callExpr.method.method)
val cleanEvaluator = TaintCleanActionEvaluator(typeResolver)

val cleanedFact = userRuleDefinedActions.applyCleanerActions(
evaluator = cleanEvaluator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ class JIRMethodSequentFlowFunction(
val valueResolver = CalleePositionToJIRValueResolver(currentInst.location.method)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver,
analysisContext.factTypeChecker
analysisContext, currentInst
)

val sourceEvaluator = TaintSourceActionEvaluator(
Expand Down Expand Up @@ -604,7 +604,7 @@ class JIRMethodSequentFlowFunction(
val valueResolver = CalleePositionToJIRValueResolver(currentInst.location.method)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver,
analysisContext.factTypeChecker
analysisContext, currentInst
)

val exclusion = fact?.exclusions ?: ExclusionSet.Universe
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class JIRMethodStartFlowFunction(
val method = context.methodEntryPoint.method as JIRMethod
val valueResolver = CalleePositionToJIRValueResolver(method)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver, context.factTypeChecker
valueResolver, context, context.methodEntryPoint.statement
)

val conditionEvaluator = JIRSimpleFactAwareConditionEvaluator(conditionRewriter, evaluator = null)
Expand Down Expand Up @@ -93,7 +93,7 @@ class JIRMethodStartFlowFunction(
val valueResolver = CalleePositionToJIRValueResolver(method as JIRMethod)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver,
context.factTypeChecker
context, context.methodEntryPoint.statement
)

val conditionEvaluator = JIRSimpleFactAwareConditionEvaluator(conditionRewriter, evaluator = null)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.seqra.dataflow.jvm.ap.ifds.taint

import org.seqra.dataflow.ap.ifds.AccessPathBase
import org.seqra.dataflow.configuration.jvm.And
import org.seqra.dataflow.configuration.jvm.ConditionNameMatcher
import org.seqra.dataflow.configuration.jvm.ConditionVisitor
Expand All @@ -20,12 +21,14 @@ import org.seqra.dataflow.configuration.jvm.Or
import org.seqra.dataflow.configuration.jvm.PositionResolver
import org.seqra.dataflow.configuration.jvm.TypeMatches
import org.seqra.dataflow.configuration.jvm.TypeMatchesPattern
import org.seqra.dataflow.jvm.ap.ifds.JIRFactTypeChecker
import org.seqra.dataflow.jvm.ap.ifds.analysis.JIRMethodAnalysisContext
import org.seqra.ir.api.common.cfg.CommonInst
import org.seqra.ir.api.common.cfg.CommonValue
import org.seqra.ir.api.jvm.JIRRefType
import org.seqra.ir.api.jvm.cfg.JIRBool
import org.seqra.ir.api.jvm.cfg.JIRConstant
import org.seqra.ir.api.jvm.cfg.JIRInt
import org.seqra.ir.api.jvm.cfg.JIRLocalVar
import org.seqra.ir.api.jvm.cfg.JIRNullConstant
import org.seqra.ir.api.jvm.cfg.JIRStringConstant
import org.seqra.ir.api.jvm.cfg.JIRValue
Expand All @@ -36,8 +39,11 @@ import org.seqra.util.onSome
class JIRBasicAtomEvaluator(
private val negated: Boolean,
private val positionResolver: PositionResolver<Maybe<JIRValue>>,
private val typeChecker: JIRFactTypeChecker
private val analysisContext: JIRMethodAnalysisContext,
private val statement: CommonInst,
) : ConditionVisitor<Boolean> {
private val typeChecker get() = analysisContext.factTypeChecker

override fun visit(condition: Not): Boolean = error("Non-atomic condition")
override fun visit(condition: And): Boolean = error("Non-atomic condition")
override fun visit(condition: Or): Boolean = error("Non-atomic condition")
Expand Down Expand Up @@ -159,8 +165,24 @@ class JIRBasicAtomEvaluator(
}

private fun matches(value: JIRValue, pattern: Regex): Boolean {
if (value !is JIRStringConstant) return false
return pattern.matches(value.value)
if (value is JIRStringConstant) {
return pattern.matches(value.value)
}

if (value is JIRLocalVar) {
val base = AccessPathBase.LocalVar(value.index)
val aliasInfo = analysisContext.aliasAnalysis?.findAlias(base, statement)
val constants = aliasInfo
?.mapNotNull { ai -> ai.base.takeIf { ai.accessors.isEmpty() } }
?.filterIsInstance<AccessPathBase.Constant>()
.orEmpty()

if (constants.isNotEmpty()) {
return constants.any { pattern.matches(it.value) }
}
}

return false
}

private fun typeMatches(value: CommonValue, condition: TypeMatches): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ data class EvaluatedCleanAction(
}
}

class TaintCleanActionEvaluator {
class TaintCleanActionEvaluator(
private val positionTypeResolver: PositionResolver<JIRType?>,
) {
fun evaluate(
initialFact: EvaluatedCleanAction,
rule: TaintConfigurationItem,
Expand All @@ -159,7 +161,17 @@ class TaintCleanActionEvaluator {
action: RemoveMark,
): List<EvaluatedCleanAction> {
val variable = action.position.resolveAp()
return removeFinalFact(initialFact, variable, action.mark, rule, action)
val cleaned = removeFinalFact(initialFact, variable, action.mark, rule, action)

val positionType = positionTypeResolver.resolve(action.position)
if (positionType?.typeName != STRING) {
return cleaned
}

val stringBytesVar = PositionWithAccess(action.position, stringBytes).resolveAp()
return cleaned.flatMap { f ->
removeFinalFact(f, stringBytesVar, action.mark, rule, action)
}
}

private fun removeAllFacts(
Expand Down Expand Up @@ -255,6 +267,13 @@ class TaintCleanActionEvaluator {

companion object {
private val logger = KotlinLogging.logger {}

private const val STRING = "java.lang.String"

// todo: fix in config?
// string bytes virtual field fully reflects the string content.
// So, if we clean string, we should clean its byte content
private val stringBytes = PositionAccessor.FieldAccessor(STRING, "<string-bytes>", "byte[]")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class JIRMethodCallPrecondition(

val conditionRewriter = JIRMarkAwareConditionRewriter(
jIRValueResolver,
analysisContext.factTypeChecker
analysisContext, statement
)

for (rule in taintConfig.sourceRulesForMethod(method, statement, fact = null)) {
Expand Down Expand Up @@ -144,7 +144,7 @@ class JIRMethodCallPrecondition(

val conditionRewriter = JIRMarkAwareConditionRewriter(
jIRValueResolver,
analysisContext.factTypeChecker
analysisContext, statement
)

for (rule in passRules) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ class JIRMethodSequentPrecondition(

val valueResolver = CalleePositionToJIRValueResolver(currentInst.location.method)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver, analysisContext.factTypeChecker
valueResolver, analysisContext, currentInst
)

for (rule in sourceRules) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class JIRMethodStartPrecondition(
val valueResolver = CalleePositionToJIRValueResolver(method)
val conditionRewriter = JIRMarkAwareConditionRewriter(
valueResolver,
context.factTypeChecker
context, context.methodEntryPoint.statement
)
val conditionEvaluator = JIRSimpleFactAwareConditionEvaluator(conditionRewriter, evaluator = null)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

class JIRInstListBuilder(
private val mutableInstructions: MutableList<JIRInst> = mutableListOf()
val mutableInstructions: MutableList<JIRInst> = mutableListOf()
) : JIRInstList<JIRInst> {
private var localVarIdx: Int

Expand Down
Loading