Skip to content

Commit

Permalink
jacodb-taint-configuration: better IsType condition specializer (#208)
Browse files Browse the repository at this point in the history
* jacodb-taint-configuration: better `IsType` condition specializer

* Add test
  • Loading branch information
Saloed authored Dec 14, 2023
1 parent 207c306 commit 7eff2f4
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@

package org.jacodb.taint.configuration

import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass
import org.jacodb.api.*
import org.jacodb.api.ext.*
import org.jacodb.impl.features.hierarchyExt
import java.nio.file.Path
import kotlin.io.path.readText

Expand Down Expand Up @@ -295,31 +293,49 @@ class TaintConfigurationFeature private constructor(
return mkOr(types.flatMap { type -> position.map { TypeMatches(it, type) } })
}

typeMatcher as ClassMatcher
val typeMatchers = (typeMatcher as ClassMatcher).extractAlternatives()
val unresolvedMatchers = mutableListOf<ClassMatcher>()
val disjuncts = mutableListOf<Condition>()

val pkgMatcher = typeMatcher.pkg
val clsMatcher = typeMatcher.classNameMatcher
val cp = method.enclosingClass.classpath

if (pkgMatcher is NameExactMatcher && clsMatcher is NameExactMatcher) {
for (matcher in typeMatchers) {
val pkgMatcher = matcher.pkg
val clsMatcher = matcher.classNameMatcher

if (pkgMatcher !is NameExactMatcher || clsMatcher !is NameExactMatcher) {
unresolvedMatchers += matcher
continue
}

val type = cp.findTypeOrNull("${pkgMatcher.name}$DOT_DELIMITER${clsMatcher.name}")
?: return mkOr(emptyList())
return mkOr(position.map { TypeMatches(it, type) })
}
?: continue

val alternatives = typeMatcher.extractAlternatives()
val disjuncts = mutableListOf<Condition>()
position.mapTo(disjuncts) { TypeMatches(it, type) }
}

alternatives.forEach { classMatcher ->
val allClasses = runBlocking {
cp.hierarchyExt().findSubClasses(cp.objectClass, allHierarchy = true, includeOwn = true)
if (unresolvedMatchers.isNotEmpty()) {
val allClassNames = cp.registeredLocations.flatMapTo(hashSetOf()) {
val names = it.jcLocation?.classNames ?: return@flatMapTo emptyList()
names.map { name ->
val packageName = name.substringBeforeLast(DOT_DELIMITER, missingDelimiterValue = "")
val simpleName = name.substringAfterLast(DOT_DELIMITER)
packageName to simpleName
}
}

val types = allClasses.filter {
matches(classMatcher.pkg, it.packageName) && matches(classMatcher.classNameMatcher, it.simpleName)
}
unresolvedMatchers.forEach { classMatcher ->
val matchedClassNames = allClassNames.filter { (packageName, simpleName) ->
matches(classMatcher.pkg, packageName) && matches(classMatcher.classNameMatcher, simpleName)
}

disjuncts += types.flatMap { type -> position.map { TypeMatches(it, type.toType()) } }.toList()
matchedClassNames.flatMapTo(disjuncts) { (packageName, simpleName) ->
val type = cp.findTypeOrNull("${packageName}$DOT_DELIMITER${simpleName}")
?: return@flatMapTo emptyList()

position.map { TypeMatches(it, type) }
}
}
}

return mkOr(disjuncts)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,15 @@ class ConfigurationTest : BaseTest() {

assertTrue(rules.singleOrNull() != null)
}

@Test
fun testIsTypeMatcher() {
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
val method = cp.findClass<java.util.List<*>>().methods.single {
it.name == "removeAll" && it.parameters.size == 1
}
val rules = taintFeature.getConfigForMethod(method)

assertTrue(rules.singleOrNull() != null)
}
}
51 changes: 51 additions & 0 deletions jacodb-taint-configuration/src/test/resources/testJsonConfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -479,5 +479,56 @@
}
]
}
},
{
"_": "MethodSink",
"ruleNote": "Test rule for isType matcher",
"cwe": [
-1
],
"methodInfo": {
"cls": {
"packageMatcher": {
"_": "NameIsEqualTo",
"name": "java.util"
},
"classNameMatcher": {
"_": "NameIsEqualTo",
"name": "List"
}
},
"functionName": {
"_": "NameIsEqualTo",
"name": "removeAll"
},
"parametersMatchers": [
],
"returnTypeMatcher": {
"_": "AnyTypeMatches"
},
"applyToOverrides": false,
"functionLabel": null,
"modifier": -1,
"exclude": [
]
},
"condition": {
"_": "IsType",
"position": {
"_": "Argument",
"number": 0
},
"type": {
"_": "ClassMatcher",
"packageMatcher": {
"_": "NameMatches",
"pattern": "java\\..*"
},
"classNameMatcher": {
"_": "NameMatches",
"pattern": "List.*"
}
}
}
}
]

0 comments on commit 7eff2f4

Please sign in to comment.