From 77f6fd008f9908943083fa865c462bacb8efdfab Mon Sep 17 00:00:00 2001 From: Valentyn Sobol <8640896+Saloed@users.noreply.github.com> Date: Tue, 11 Aug 2026 21:51:15 +0300 Subject: [PATCH 1/3] fix(analyzer): Field based default get --- .../ap/ifds/analysis/JIRMethodGetDefault.kt | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt index ba61d16a5..2f7b8730b 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt @@ -9,6 +9,7 @@ import org.opentaint.dataflow.configuration.jvm.TaintPassThrough import org.opentaint.dataflow.configuration.jvm.This import org.opentaint.dataflow.configuration.mkTrue import org.opentaint.dataflow.taint.RuleConditionRewriter +import org.opentaint.ir.api.jvm.JIRClassOrInterface import org.opentaint.ir.api.jvm.JIRMethod import org.opentaint.ir.api.jvm.TypeName import org.opentaint.ir.impl.cfg.util.isArray @@ -19,12 +20,21 @@ object JIRMethodGetDefault { private fun TypeName.mayBeArray(): Boolean = isArray || this == objectTypeName - private val getDefaultActions = listOf( - CopyAllMarks(from = This, to = Result) + private fun defaultField(cls: JIRClassOrInterface): PositionAccessor.FieldAccessor = + PositionAccessor.FieldAccessor(cls.name, "", objectTypeName.typeName) + + private fun defaultPosition(cls: JIRClassOrInterface) = + PositionWithAccess(This, defaultField(cls)) + + private fun getDefaultActions(cls: JIRClassOrInterface) = listOf( + CopyAllMarks(from = defaultPosition(cls), to = Result) ) - private val getDefaultArrayActions = listOf( - CopyAllMarks(from = This, to = PositionWithAccess(Result, PositionAccessor.ElementAccessor)) + private fun getDefaultArrayActions(cls: JIRClassOrInterface) = listOf( + CopyAllMarks( + from = defaultPosition(cls), + to = PositionWithAccess(Result, PositionAccessor.ElementAccessor) + ) ) fun defaultPropagationRules(method: JIRMethod): List> { @@ -32,9 +42,9 @@ object JIRMethodGetDefault { if (!method.name.startsWith("get")) return emptyList() - var actions = getDefaultActions + var actions = getDefaultActions(method.enclosingClass) if (method.returnType.mayBeArray()) { - actions = actions + getDefaultArrayActions + actions = actions + getDefaultArrayActions(method.enclosingClass) } val getDefaultRule = TaintPassThrough(method, mkTrue(), actions, info = null) From f73f41199fa442faf78a2c8c078cd531a78d12b6 Mon Sep 17 00:00:00 2001 From: Valentyn Sobol <8640896+Saloed@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:33:46 +0300 Subject: [PATCH 2/3] Fix --- .../jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt index 5ee1493f3..78efc167c 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt @@ -279,6 +279,9 @@ class JIRMethodCallFlowFunction( apManager, analysisContext.factTypeChecker, passFactReader, typeResolver ) + val passRules = taintCtx.passRulesForCallStatement(statement, callExpr, returnValue, passFactReader.factAp) + var passThroughFacts = applyPassThrough(passRules, conditionEvaluator, passEvaluator) + if (startFactBase !is AccessPathBase.ClassStatic) { analysisContext.taint.externalMethodTracker?.let { tracker -> if (JIRCallResolver.alwaysIgnoreMethod(method)) return@let @@ -291,9 +294,6 @@ class JIRMethodCallFlowFunction( } } - val passRules = taintCtx.passRulesForCallStatement(statement, callExpr, returnValue, passFactReader.factAp) - var passThroughFacts = applyPassThrough(passRules, conditionEvaluator, passEvaluator) - if (/*todo: fix owasp passThroughFacts.isNone && */!analysisContext.analysisManager.params.disableDefaultGetModel) { val defaultRules = JIRMethodGetDefault.defaultPropagationRules(method) val defaultPass = applyPassThrough(defaultRules, conditionEvaluator, passEvaluator) From 1f31f59bac5121cd84ee12763ea0cde759a06987 Mon Sep 17 00:00:00 2001 From: Valentyn Sobol <8640896+Saloed@users.noreply.github.com> Date: Wed, 12 Aug 2026 16:36:59 +0300 Subject: [PATCH 3/3] Fix project classes handling --- .../jvm/ap/ifds/analysis/JIRAnalysisManager.kt | 2 +- .../ap/ifds/analysis/JIRMethodCallFlowFunction.kt | 5 +++-- .../jvm/ap/ifds/analysis/JIRMethodGetDefault.kt | 10 +++++++++- .../jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt | 6 +++--- .../jvm/sast/dataflow/JIRTaintAnalyzer.kt | 14 +++++++++++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt index cf928a62a..5b5724f72 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRAnalysisManager.kt @@ -66,7 +66,7 @@ class JIRAnalysisManager( data class Params( val aliasAnalysisParams: JIRLocalAliasAnalysis.Params = JIRLocalAliasAnalysis.Params(), - val disableDefaultGetModel: Boolean = false, + val defaultGetModel: JIRMethodGetDefault? = null, ) private val relevantRuleIds = ConcurrentHashMap.newKeySet() diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt index 78efc167c..aa590a7af 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodCallFlowFunction.kt @@ -294,8 +294,9 @@ class JIRMethodCallFlowFunction( } } - if (/*todo: fix owasp passThroughFacts.isNone && */!analysisContext.analysisManager.params.disableDefaultGetModel) { - val defaultRules = JIRMethodGetDefault.defaultPropagationRules(method) + analysisContext.analysisManager.params.defaultGetModel?.run { + /*todo: fix owasp, propagate default only if passThroughFacts.isNone */ + val defaultRules = defaultPropagationRules(method) val defaultPass = applyPassThrough(defaultRules, conditionEvaluator, passEvaluator) passThroughFacts = passThroughFacts.merge(defaultPass) } diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt index 2f7b8730b..b98f0aff3 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/analysis/JIRMethodGetDefault.kt @@ -15,7 +15,13 @@ import org.opentaint.ir.api.jvm.TypeName import org.opentaint.ir.impl.cfg.util.isArray import org.opentaint.ir.impl.types.TypeNameImpl -object JIRMethodGetDefault { +class JIRMethodGetDefault( + private val config: Configuration, +) { + interface Configuration { + fun enableDefaultPropagationForClass(cls: JIRClassOrInterface): Boolean + } + private val objectTypeName = TypeNameImpl.fromTypeName("java.lang.Object") private fun TypeName.mayBeArray(): Boolean = isArray || this == objectTypeName @@ -42,6 +48,8 @@ object JIRMethodGetDefault { if (!method.name.startsWith("get")) return emptyList() + if (!config.enableDefaultPropagationForClass(method.enclosingClass)) return emptyList() + var actions = getDefaultActions(method.enclosingClass) if (method.returnType.mayBeArray()) { actions = actions + getDefaultArrayActions(method.enclosingClass) diff --git a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt index c9b0f53a0..21b3b1f05 100644 --- a/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt +++ b/core/opentaint-dataflow-core/opentaint-jvm-dataflow/src/main/kotlin/org/opentaint/dataflow/jvm/ap/ifds/trace/JIRMethodCallPrecondition.kt @@ -19,7 +19,6 @@ import org.opentaint.dataflow.jvm.ap.ifds.JIRMethodCallFactMapper.factIsRelevant import org.opentaint.dataflow.jvm.ap.ifds.MethodFlowFunctionUtils import org.opentaint.dataflow.jvm.ap.ifds.TaintConfigUtils.accept import org.opentaint.dataflow.jvm.ap.ifds.analysis.JIRMethodAnalysisContext -import org.opentaint.dataflow.jvm.ap.ifds.analysis.JIRMethodGetDefault import org.opentaint.dataflow.jvm.ap.ifds.analysis.forEachPossibleAliasAtStatement import org.opentaint.dataflow.jvm.ap.ifds.taint.resolveAp import org.opentaint.dataflow.jvm.util.callee @@ -136,8 +135,9 @@ class JIRMethodCallPrecondition( ) { val passRules = taintCtx.passRulesForCallStatement(statement, callExpr, returnValue, fact = null).toMutableList() - if (!analysisContext.analysisManager.params.disableDefaultGetModel) { - passRules += JIRMethodGetDefault.defaultPropagationRules(callExpr.method.method) + + analysisContext.analysisManager.params.defaultGetModel?.run { + passRules += defaultPropagationRules(callExpr.method.method) } if (passRules.isEmpty()) return diff --git a/core/opentaint-jvm-sast-dataflow/src/main/kotlin/org/opentaint/jvm/sast/dataflow/JIRTaintAnalyzer.kt b/core/opentaint-jvm-sast-dataflow/src/main/kotlin/org/opentaint/jvm/sast/dataflow/JIRTaintAnalyzer.kt index a5ab016fc..9c4263732 100644 --- a/core/opentaint-jvm-sast-dataflow/src/main/kotlin/org/opentaint/jvm/sast/dataflow/JIRTaintAnalyzer.kt +++ b/core/opentaint-jvm-sast-dataflow/src/main/kotlin/org/opentaint/jvm/sast/dataflow/JIRTaintAnalyzer.kt @@ -12,6 +12,7 @@ import org.opentaint.dataflow.jvm.ap.ifds.JIRSummarySerializationContext import org.opentaint.dataflow.jvm.ap.ifds.LambdaAnonymousClassFeature import org.opentaint.dataflow.jvm.ap.ifds.LambdaAnonymousClassFeature.JIRLambdaMethod import org.opentaint.dataflow.jvm.ap.ifds.analysis.JIRAnalysisManager +import org.opentaint.dataflow.jvm.ap.ifds.analysis.JIRMethodGetDefault import org.opentaint.dataflow.jvm.ap.ifds.taint.TaintRulesProvider import org.opentaint.dataflow.jvm.ifds.JIRUnitResolver import org.opentaint.dataflow.jvm.ifds.PackageUnit @@ -47,12 +48,23 @@ class JIRTaintAnalyzer( ) private val analysisParams get() = JIRAnalysisManager.Params( - disableDefaultGetModel = jirOptions.disableDefaultGetModel, + defaultGetModel = configureDefaultModel(), aliasAnalysisParams = JIRLocalAliasAnalysis.Params( aliasAnalysisInterProcCallDepth = options.experimentalAAInterProcCallDepth ) ) + private fun configureDefaultModel(): JIRMethodGetDefault? { + if (jirOptions.disableDefaultGetModel) return null + + val config = object : JIRMethodGetDefault.Configuration { + override fun enableDefaultPropagationForClass(cls: JIRClassOrInterface): Boolean = + !projectClasses.isProjectClass(cls) + } + + return JIRMethodGetDefault(config) + } + private val taintConfig: TaintRulesProvider by lazy { StringConcatRuleProvider(taintConfiguration) }