Skip to content

Commit 9c1fbfd

Browse files
authored
Merge branch 'main' into expand-ruby-ssrf-sinks-faraday-connection-new
2 parents 3659eaa + 3d025ea commit 9c1fbfd

File tree

70 files changed

+1659
-45
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1659
-45
lines changed

cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
* variable), and `v` is an integer in the range `[0 .. m-1]`.
55
*/
66

7+
/*
8+
* The main recursion has base cases in both `ssaModulus` (for guarded reads) and `semExprModulus`
9+
* (for constant values). The most interesting recursive case is `phiModulusRankStep`, which
10+
* handles phi inputs.
11+
*/
12+
713
private import ModulusAnalysisSpecific::Private
814
private import experimental.semmle.code.cpp.semantic.Semantic
915
private import ConstantAnalysis
@@ -162,20 +168,37 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
162168
*/
163169
pragma[nomagic]
164170
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
171+
/*
172+
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
173+
* class for the phi node.
174+
*/
175+
165176
rix = 0 and
166177
phiModulusInit(phi, b, val, mod)
167178
or
168179
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
169180
mod != 1 and
170181
val = remainder(v1, mod)
171182
|
183+
/*
184+
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
185+
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
186+
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
187+
*/
188+
172189
exists(int v2, int m2 |
173190
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
174191
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
175192
ssaModulus(inp, edge, b, v2, m2) and
176193
mod = m1.gcd(m2).gcd(v1 - v2)
177194
)
178195
or
196+
/*
197+
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
198+
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
199+
* common denominator of `m1` and `m2`.
200+
*/
201+
179202
exists(int m2 |
180203
rankedPhiInput(phi, inp, edge, rix) and
181204
phiModulusRankStep(phi, b, v1, m1, rix - 1) and

docs/codeql/ql-language-reference/signatures.rst

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,11 @@ Type signatures
4040
===============
4141

4242
Type signatures declare module parameters that will be substituted with types when the module is instantiated.
43-
Type signatures are used to specify supertypes and are the simplest category of signatures.
43+
Type signatures may specify supertypes and required member predicates (in addition to those member predicates that are
44+
implied by the supertypes).
4445

4546
The substitution of type signatures relies on structural typing. That is, types do not have to be explicitly defined as
46-
implementing a type signature - they just need to have the specified (transitive) supertypes.
47+
implementing a type signature - they just need to have the specified (transitive) supertypes and member predicates.
4748

4849
In detail, a type signature definition consists of:
4950

@@ -52,14 +53,19 @@ In detail, a type signature definition consists of:
5253
#. The name of the type signature. This is an `identifier <https://codeql.github.com/docs/ql-language-reference/ql-language-specification/#identifiers>`_
5354
starting with a uppercase letter.
5455
#. Optionally, the keyword ``extends`` followed by a list of types, separated by commas.
55-
#. A semicolon ``;``.
56+
#. Either a semicolon ``;`` or a list of predicate signatures enclosed in braces.
57+
The ``signature`` keyword is omitted for these contained signatures.
5658

5759
For example:
5860

5961
.. code-block:: ql
6062
6163
signature class ExtendsInt extends int;
6264
65+
signature class CanBePrinted {
66+
string toString();
67+
}
68+
6369
Module signatures
6470
=================
6571

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
Framework name,URL,Package prefixes
22
Java Standard Library,,java.*
33
Java extensions,,javax.* jakarta.*
4+
Kotlin Standard Library,,kotlin*
5+
Android,,android.*
6+
Android extensions,,androidx.*
47
Apache Commons Collections,https://commons.apache.org/proper/commons-collections/,org.apache.commons.collections org.apache.commons.collections4
58
Apache Commons IO,https://commons.apache.org/proper/commons-io/,org.apache.commons.io
69
Apache Commons Lang,https://commons.apache.org/proper/commons-lang/,org.apache.commons.lang3
710
Apache Commons Text,https://commons.apache.org/proper/commons-text/,org.apache.commons.text
811
Apache HttpComponents,https://hc.apache.org/,org.apache.hc.core5.* org.apache.http
9-
Android,,android.*
12+
Apache Log4j 2,https://logging.apache.org/log4j/2.0/,org.apache.logging.log4j
1013
Google Guava,https://guava.dev/,com.google.common.*
14+
JBoss Logging,,org.jboss.logging
1115
JSON-java,https://github.com/stleary/JSON-java,org.json
1216
Spring,https://spring.io/,org.springframework.*

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaClass
2727
import org.jetbrains.kotlin.load.java.structure.JavaMethod
2828
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
2929
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
30+
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
3031
import org.jetbrains.kotlin.name.FqName
3132
import org.jetbrains.kotlin.types.Variance
3233
import org.jetbrains.kotlin.util.OperatorNameConventions
@@ -98,15 +99,29 @@ open class KotlinFileExtractor(
9899
}
99100
}
100101

102+
private fun javaBinaryDeclaresMethod(c: IrClass, name: String) =
103+
((c.source as? JavaSourceElement)?.javaElement as? BinaryJavaClass)?.methods?.any { it.name.asString() == name }
104+
105+
private fun isJavaBinaryDeclaration(f: IrFunction) =
106+
f.parentClassOrNull?.let { javaBinaryDeclaresMethod(it, f.name.asString()) } ?: false
107+
108+
private fun isJavaBinaryObjectMethodRedeclaration(d: IrDeclaration) =
109+
when (d) {
110+
is IrFunction ->
111+
when (d.name.asString()) {
112+
"toString" -> d.valueParameters.isEmpty()
113+
"hashCode" -> d.valueParameters.isEmpty()
114+
"equals" -> d.valueParameters.singleOrNull()?.type?.isNullableAny() ?: false
115+
else -> false
116+
} && isJavaBinaryDeclaration(d)
117+
else -> false
118+
}
119+
101120
@OptIn(ObsoleteDescriptorBasedAPI::class)
102121
private fun isFake(d: IrDeclarationWithVisibility): Boolean {
103-
val visibility = d.visibility
104-
if (visibility is DelegatedDescriptorVisibility && visibility.delegate == Visibilities.InvisibleFake) {
105-
return true
106-
}
107-
if (d.isFakeOverride) {
122+
val hasFakeVisibility = d.visibility.let { it is DelegatedDescriptorVisibility && it.delegate == Visibilities.InvisibleFake } || d.isFakeOverride
123+
if (hasFakeVisibility && !isJavaBinaryObjectMethodRedeclaration(d))
108124
return true
109-
}
110125
try {
111126
if ((d as? IrFunction)?.descriptor?.isHiddenToOvercomeSignatureClash == true) {
112127
return true
@@ -908,7 +923,9 @@ open class KotlinFileExtractor(
908923
else
909924
null
910925
} else {
911-
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses).also {
926+
// Work around an apparent bug causing redeclarations of `fun toString(): String` specifically in interfaces loaded from Java classes show up like fake overrides.
927+
val overriddenVisibility = if (f.isFakeOverride && isJavaBinaryObjectMethodRedeclaration(f)) OverriddenFunctionAttributes(visibility = DescriptorVisibilities.PUBLIC) else null
928+
forceExtractFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses, typeSubstitution, classTypeArgsIncludingOuterClasses, overriddenAttributes = overriddenVisibility).also {
912929
// The defaults-forwarder function is a static utility, not a member, so we only need to extract this for the unspecialised instance of this class.
913930
if (classTypeArgsIncludingOuterClasses.isNullOrEmpty())
914931
extractDefaultsFunction(f, parentId, extractBody, extractMethodAndParameterTypeAccesses)

java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.github.codeql
22

33
import com.github.codeql.utils.*
44
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
5+
import com.github.codeql.utils.versions.getKotlinType
56
import com.github.codeql.utils.versions.isRawType
67
import com.semmle.extractor.java.OdasaOutput
78
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
@@ -22,6 +23,7 @@ import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature
2223
import org.jetbrains.kotlin.load.java.JvmAbi
2324
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
2425
import org.jetbrains.kotlin.load.java.structure.*
26+
import org.jetbrains.kotlin.load.java.typeEnhancement.hasEnhancedNullability
2527
import org.jetbrains.kotlin.load.kotlin.getJvmModuleNameForDeserializedDescriptor
2628
import org.jetbrains.kotlin.name.FqName
2729
import org.jetbrains.kotlin.name.NameUtils
@@ -674,7 +676,8 @@ open class KotlinUsesExtractor(
674676
otherIsPrimitive: Boolean,
675677
javaClass: IrClass,
676678
kotlinPackageName: String, kotlinClassName: String): TypeResults {
677-
val javaResult = if ((context == TypeContext.RETURN || (context == TypeContext.OTHER && otherIsPrimitive)) && !s.isNullable() && primitiveName != null) {
679+
// Note the use of `hasEnhancedNullability` here covers cases like `@NotNull Integer`, which must be extracted as `Integer` not `int`.
680+
val javaResult = if ((context == TypeContext.RETURN || (context == TypeContext.OTHER && otherIsPrimitive)) && !s.isNullable() && getKotlinType(s)?.hasEnhancedNullability() != true && primitiveName != null) {
678681
val label: Label<DbPrimitive> = tw.getLabelFor("@\"type;$primitiveName\"", {
679682
tw.writePrimitives(it, primitiveName)
680683
})
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.github.codeql.utils.versions
2+
3+
import org.jetbrains.kotlin.ir.types.IrSimpleType
4+
import org.jetbrains.kotlin.ir.types.impl.IrTypeBase
5+
6+
fun getKotlinType(s: IrSimpleType) = (s as? IrTypeBase)?.kotlinType
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.github.codeql.utils.versions
2+
3+
import org.jetbrains.kotlin.ir.types.IrSimpleType
4+
5+
fun getKotlinType(s: IrSimpleType) = s.kotlinType
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
class ConstructorWithDefaults(x: Int, y: Int = 1) { }
2+
3+
fun topLevelWithDefaults(x: Int, y: Int = 1) = 0
4+
fun String.extensionWithDefaults(x: Int, y: Int = 1) = 0
5+
6+
class LibClass {
7+
8+
fun memberWithDefaults(x: Int, y: Int = 1) = 0
9+
fun String.extensionMemberWithDefaults(x: Int, y: Int = 1) = 0
10+
11+
fun multiParameterTest(x: Int, y: Int, z: Int, w: Int = 0) = 0
12+
fun Int.multiParameterExtensionTest(x: Int, y: Int, w: Int = 0) = 0
13+
14+
}
15+
16+
class SomeToken {}
17+
18+
fun topLevelArgSource(st: SomeToken, x: Int = 0) {}
19+
fun String.extensionArgSource(st: SomeToken, x: Int = 0) {}
20+
21+
class SourceClass {
22+
23+
fun memberArgSource(st: SomeToken, x: Int = 0) {}
24+
25+
}
26+
27+
fun topLevelSink(x: Int, y: Int = 1) {}
28+
fun String.extensionSink(x: Int, y: Int = 1) {}
29+
30+
class SinkClass(x: Int, y: Int = 1) {
31+
32+
fun memberSink(x: Int, y: Int = 1) {}
33+
fun String.extensionMemberSink(x: Int, y: Int = 1) {}
34+
35+
}

java/ql/integration-tests/posix-only/kotlin/default-parameter-mad-flow/test.expected

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from create_database_utils import *
2+
import subprocess
3+
4+
subprocess.check_call(["kotlinc", "lib.kt", "-d", "lib"])
5+
run_codeql_database_create(["kotlinc user.kt -cp lib"], lang="java")

0 commit comments

Comments
 (0)