Merge main into redsun82/swift-extraction

This commit is contained in:
Paolo Tranquilli
2022-06-22 16:54:52 +02:00
57 changed files with 924 additions and 69 deletions

View File

@@ -0,0 +1,9 @@
# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.236.0/containers/cpp/.devcontainer/base.Dockerfile
# [Choice] Debian / Ubuntu version (use Debian 11, Ubuntu 18.04/22.04 on local arm64/Apple Silicon): debian-11, debian-10, ubuntu-22.04, ubuntu-20.04, ubuntu-18.04
FROM mcr.microsoft.com/vscode/devcontainers/cpp:0-ubuntu-22.04
USER root
ADD root.sh /tmp/root.sh
ADD update-codeql.sh /usr/local/bin/update-codeql
RUN bash /tmp/root.sh && rm /tmp/root.sh

View File

@@ -0,0 +1,25 @@
{
"extensions": [
"github.vscode-codeql",
"hbenl.vscode-test-explorer",
"ms-vscode.test-adapter-converter",
"slevesque.vscode-zipexplorer",
"ms-vscode.cpptools"
],
"settings": {
"files.watcherExclude": {
"**/target/**": true
},
"codeQL.runningQueries.memory": 2048
},
"build": {
"dockerfile": "Dockerfile",
},
"runArgs": [
"--cap-add=SYS_PTRACE",
"--security-opt",
"seccomp=unconfined"
],
"remoteUser": "vscode",
"onCreateCommand": ".devcontainer/swift/user.sh"
}

View File

@@ -0,0 +1,22 @@
set -xe
BAZELISK_VERSION=v1.12.0
BAZELISK_DOWNLOAD_SHA=6b0bcb2ea15bca16fffabe6fda75803440375354c085480fe361d2cbf32501db
apt-get update
export DEBIAN_FRONTEND=noninteractive
apt-get -y install --no-install-recommends \
zlib1g-dev \
uuid-dev \
python3-distutils \
python3-pip \
bash-completion
# Install Bazel
curl -fSsL -o /usr/local/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/${BAZELISK_VERSION}/bazelisk-linux-amd64
echo "${BAZELISK_DOWNLOAD_SHA} */usr/local/bin/bazelisk" | sha256sum --check -
chmod 0755 /usr/local/bin/bazelisk
ln -s bazelisk /usr/local/bin/bazel
# install latest codeql
update-codeql

View File

@@ -0,0 +1,20 @@
#!/bin/bash -e
URL=https://github.com/github/codeql-cli-binaries/releases
LATEST_VERSION=$(curl -L -s -H 'Accept: application/json' $URL/latest | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
CURRENT_VERSION=v$(codeql version 2>/dev/null | sed -ne 's/.*release \([0-9.]*\)\./\1/p')
if [[ $CURRENT_VERSION != $LATEST_VERSION ]]; then
if [[ $UID != 0 ]]; then
echo "update required, please run this script with sudo:"
echo " sudo $0"
exit 1
fi
ZIP=$(mktemp codeql.XXXX.zip)
curl -fSqL -o $ZIP $URL/download/$LATEST_VERSION/codeql-linux64.zip
unzip -q $ZIP -d /opt
rm $ZIP
ln -sf /opt/codeql/codeql /usr/local/bin/codeql
echo installed version $LATEST_VERSION
else
echo current version $CURRENT_VERSION is up-to-date
fi

13
.devcontainer/swift/user.sh Executable file
View File

@@ -0,0 +1,13 @@
set -xe
# add the workspace to the codeql search path
mkdir -p /home/vscode/.config/codeql
echo "--search-path /workspaces/codeql" > /home/vscode/.config/codeql/config
# create a swift extractor pack with the current state
cd /workspaces/codeql
bazel run swift/create-extractor-pack
#install and set up pre-commit
python3 -m pip install pre-commit --no-warn-script-location
$HOME/.local/bin/pre-commit install

View File

@@ -0,0 +1,4 @@
---
category: fix
---
* `UserType.getADeclarationEntry()` now yields all forward declarations when the user type is a `class`, `struct`, or `union`.

View File

@@ -48,8 +48,8 @@ class UserType extends Type, Declaration, NameQualifyingElement, AccessHolder, @
}
override TypeDeclarationEntry getADeclarationEntry() {
if type_decls(_, underlyingElement(this), _)
then type_decls(unresolveElement(result), underlyingElement(this), _)
if type_decls(_, unresolveElement(this), _)
then type_decls(underlyingElement(result), unresolveElement(this), _)
else exists(Class t | this.(Class).isConstructedFrom(t) and result = t.getADeclarationEntry())
}

View File

@@ -33,3 +33,11 @@ public:
myTemplateClass<int> mtc_int;
myTemplateClass<short> mtc_short;
// Class (UserType)
class myClass
{
public:
int myMemberVariable;
};

View File

@@ -27,5 +27,11 @@
| declarationEntry.cpp:31:4:31:19 | myMemberVariable | declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | 1 | 1 |
| declarationEntry.cpp:34:22:34:28 | mtc_int | declarationEntry.cpp:34:22:34:28 | definition of mtc_int | 1 | 1 |
| declarationEntry.cpp:35:24:35:32 | mtc_short | declarationEntry.cpp:35:24:35:32 | definition of mtc_short | 1 | 1 |
| declarationEntry.cpp:39:7:39:7 | operator= | declarationEntry.cpp:39:7:39:7 | declaration of operator= | 1 | 1 |
| declarationEntry.cpp:39:7:39:7 | operator= | declarationEntry.cpp:39:7:39:7 | declaration of operator= | 1 | 1 |
| declarationEntry.cpp:39:7:39:13 | myClass | declarationEntry.cpp:39:7:39:13 | definition of myClass | 1 | 1 |
| declarationEntry.cpp:39:7:39:13 | myClass | forwardDeclaration.cpp:1:7:1:13 | declaration of myClass | 1 | 1 |
| declarationEntry.cpp:42:6:42:21 | myMemberVariable | declarationEntry.cpp:42:6:42:21 | definition of myMemberVariable | 1 | 1 |
| forwardDeclaration.cpp:3:10:3:19 | myClassPtr | forwardDeclaration.cpp:3:10:3:19 | definition of myClassPtr | 1 | 1 |
| macro.c:2:1:2:3 | foo | macro.c:2:1:2:3 | declaration of foo | 1 | 1 |
| macro.c:4:5:4:8 | main | macro.c:4:5:4:8 | definition of main | 1 | 1 |

View File

@@ -10,5 +10,7 @@
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | | 0 | |
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | | 0 | |
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | | 0 | |
| macro.c:2:1:2:3 | declaration of foo | | 2 | c_linkage, static |
| macro.c:4:5:4:8 | definition of main | | 1 | c_linkage |

View File

@@ -0,0 +1,3 @@
class myClass;
myClass *myClassPtr;

View File

@@ -0,0 +1,45 @@
| declarationEntry.c:2:6:2:20 | declaration of myFirstFunction | declarationEntry.c:2:6:2:20 | myFirstFunction | yes |
| declarationEntry.c:4:6:4:21 | definition of mySecondFunction | declarationEntry.c:4:6:4:21 | mySecondFunction | yes |
| declarationEntry.c:8:6:8:20 | definition of myThirdFunction | declarationEntry.c:8:6:8:20 | myThirdFunction | yes |
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | declarationEntry.c:13:2:13:2 | myFourthFunction | yes |
| declarationEntry.c:13:2:13:2 | declaration of myFourthFunction | declarationEntry.c:17:6:17:21 | myFourthFunction | yes |
| declarationEntry.c:14:2:14:2 | declaration of myFifthFunction | declarationEntry.c:14:2:14:2 | myFifthFunction | yes |
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | declarationEntry.c:13:2:13:2 | myFourthFunction | yes |
| declarationEntry.c:17:6:17:21 | declaration of myFourthFunction | declarationEntry.c:17:6:17:21 | myFourthFunction | yes |
| declarationEntry.cpp:3:12:3:21 | declaration of myVariable | declarationEntry.cpp:5:5:5:14 | myVariable | yes |
| declarationEntry.cpp:5:5:5:14 | definition of myVariable | declarationEntry.cpp:5:5:5:14 | myVariable | yes |
| declarationEntry.cpp:9:6:9:15 | declaration of myFunction | declarationEntry.cpp:11:6:11:15 | myFunction | yes |
| declarationEntry.cpp:9:21:9:31 | declaration of myParameter | declarationEntry.cpp:11:21:11:31 | myParameter | yes |
| declarationEntry.cpp:11:6:11:15 | definition of myFunction | declarationEntry.cpp:11:6:11:15 | myFunction | yes |
| declarationEntry.cpp:11:21:11:31 | definition of myParameter | declarationEntry.cpp:11:21:11:31 | myParameter | yes |
| declarationEntry.cpp:18:6:18:11 | declaration of myEnum | declarationEntry.cpp:20:6:20:11 | myEnum | yes |
| declarationEntry.cpp:20:6:20:11 | definition of myEnum | declarationEntry.cpp:20:6:20:11 | myEnum | yes |
| declarationEntry.cpp:27:20:27:20 | definition of T | declarationEntry.cpp:27:20:27:20 | T | yes |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
| declarationEntry.cpp:28:7:28:7 | declaration of operator= | declarationEntry.cpp:28:7:28:7 | operator= | yes |
| declarationEntry.cpp:28:7:28:21 | definition of myTemplateClass<T> | declarationEntry.cpp:28:7:28:21 | myTemplateClass<T> | yes |
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
| declarationEntry.cpp:31:4:31:19 | definition of myMemberVariable | declarationEntry.cpp:31:4:31:19 | myMemberVariable | yes |
| declarationEntry.cpp:34:22:34:28 | definition of mtc_int | declarationEntry.cpp:34:22:34:28 | mtc_int | yes |
| declarationEntry.cpp:35:24:35:32 | definition of mtc_short | declarationEntry.cpp:35:24:35:32 | mtc_short | yes |
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | declarationEntry.cpp:39:7:39:7 | operator= | yes |
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | declarationEntry.cpp:39:7:39:7 | operator= | yes |
| declarationEntry.cpp:39:7:39:13 | definition of myClass | declarationEntry.cpp:39:7:39:13 | myClass | yes |
| declarationEntry.cpp:42:6:42:21 | definition of myMemberVariable | declarationEntry.cpp:42:6:42:21 | myMemberVariable | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | definition of fp_offset | file://:0:0:0:0 | fp_offset | yes |
| file://:0:0:0:0 | definition of gp_offset | file://:0:0:0:0 | gp_offset | yes |
| file://:0:0:0:0 | definition of overflow_arg_area | file://:0:0:0:0 | overflow_arg_area | yes |
| file://:0:0:0:0 | definition of reg_save_area | file://:0:0:0:0 | reg_save_area | yes |
| forwardDeclaration.cpp:1:7:1:13 | declaration of myClass | declarationEntry.cpp:39:7:39:13 | myClass | yes |
| forwardDeclaration.cpp:3:10:3:19 | definition of myClassPtr | forwardDeclaration.cpp:3:10:3:19 | myClassPtr | yes |
| macro.c:2:1:2:3 | declaration of foo | macro.c:2:1:2:3 | foo | yes |
| macro.c:4:5:4:8 | definition of main | macro.c:4:5:4:8 | main | yes |

View File

@@ -0,0 +1,7 @@
import cpp
from DeclarationEntry de, Declaration d, string canRoundTrip
where
d = de.getDeclaration() and
if d.getADeclarationEntry() = de then canRoundTrip = "yes" else canRoundTrip = "no"
select de, d, canRoundTrip

View File

@@ -0,0 +1,4 @@
namespace aNameSpace {
int xs[] = { 1, 2 };
}

View File

@@ -0,0 +1,4 @@
namespace aNameSpace {
extern int xs[2];
}

View File

@@ -0,0 +1,2 @@
#include "d.h"

View File

@@ -10,6 +10,8 @@
| c.h:6:12:6:13 | declaration of ls | array of 4 {int} | 1 |
| c.h:8:12:8:14 | declaration of iss | array of {array of 2 {int}} | 1 |
| c.h:10:12:10:12 | declaration of i | int | 1 |
| d.cpp:3:7:3:8 | definition of xs | array of {int} | 1 |
| d.h:3:14:3:15 | declaration of xs | array of 2 {int} | 1 |
| file://:0:0:0:0 | definition of fp_offset | unsigned int | 1 |
| file://:0:0:0:0 | definition of gp_offset | unsigned int | 1 |
| file://:0:0:0:0 | definition of overflow_arg_area | pointer to {void} | 1 |

View File

@@ -7,6 +7,10 @@
| c.h:4:12:4:13 | ks | array of {int} | 1 |
| c.h:8:12:8:14 | iss | array of {array of 2 {int}} | 1 |
| c.h:10:12:10:12 | i | int | 1 |
| d.cpp:3:7:3:8 | xs | array of {int} | 1 |
| d.h:3:14:3:15 | xs | array of 2 {int} | 1 |
| file://:0:0:0:0 | (unnamed parameter 0) | reference to {const {struct __va_list_tag}} | 1 |
| file://:0:0:0:0 | (unnamed parameter 0) | rvalue reference to {struct __va_list_tag} | 1 |
| file://:0:0:0:0 | fp_offset | unsigned int | 1 |
| file://:0:0:0:0 | gp_offset | unsigned int | 1 |
| file://:0:0:0:0 | overflow_arg_area | pointer to {void} | 1 |

View File

@@ -507,6 +507,9 @@ open class KotlinFileExtractor(
return FieldResult(instanceId, instanceName)
}
@OptIn(ObsoleteDescriptorBasedAPI::class)
private fun hasSynthesizedParameterNames(f: IrFunction) = f.descriptor.hasSynthesizedParameterNames()
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
with("value parameter", vp) {
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
@@ -523,16 +526,19 @@ open class KotlinFileExtractor(
if (extractTypeAccess) {
extractTypeAccessRecursive(substitutedType, location, id, -1)
}
return extractValueParameter(id, substitutedType, vp.name.asString(), location, parent, idx, useValueParameter(vp, parentSourceDeclaration), vp.isVararg)
val syntheticParameterNames = (vp.parent as? IrFunction)?.let { hasSynthesizedParameterNames(it) } ?: true
return extractValueParameter(id, substitutedType, vp.name.asString(), location, parent, idx, useValueParameter(vp, parentSourceDeclaration), vp.isVararg, syntheticParameterNames)
}
}
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean): TypeResults {
private fun extractValueParameter(id: Label<out DbParam>, t: IrType, name: String, locId: Label<DbLocation>, parent: Label<out DbCallable>, idx: Int, paramSourceDeclaration: Label<out DbParam>, isVararg: Boolean, syntheticParameterNames: Boolean): TypeResults {
val type = useType(t)
tw.writeParams(id, type.javaResult.id, idx, parent, paramSourceDeclaration)
tw.writeParamsKotlinType(id, type.kotlinResult.id)
tw.writeHasLocation(id, locId)
tw.writeParamName(id, name)
if (!syntheticParameterNames) {
tw.writeParamName(id, name)
}
if (isVararg) {
tw.writeIsVarargsParam(id)
}
@@ -2952,7 +2958,7 @@ open class KotlinFileExtractor(
stmtIdx: Int
) {
val paramId = tw.getFreshIdLabel<DbParam>()
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, paramId, false)
val paramTypeRes = extractValueParameter(paramId, paramType, paramName, locId, ids.constructor, paramIdx, paramId, isVararg = false, syntheticParameterNames = false)
val assignmentStmtId = tw.getFreshIdLabel<DbExprstmt>()
tw.writeStmts_exprstmt(assignmentStmtId, ids.constructorBlock, stmtIdx, ids.constructor)
@@ -3588,7 +3594,7 @@ open class KotlinFileExtractor(
val parameters = parameterTypes.mapIndexed { idx, p ->
val paramId = tw.getFreshIdLabel<DbParam>()
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, paramId, false)
val paramType = extractValueParameter(paramId, p, "a$idx", locId, methodId, idx, paramId, isVararg = false, syntheticParameterNames = false)
Pair(paramId, paramType)
}

View File

@@ -637,14 +637,31 @@ open class KotlinUsesExtractor(
)
(s.isBoxedArray && s.arguments.isNotEmpty()) || s.isPrimitiveArray() -> {
var dimensions = 1
var isPrimitiveArray = s.isPrimitiveArray()
val componentType = s.getArrayElementType(pluginContext.irBuiltIns)
var elementType = componentType
fun replaceComponentTypeWithAny(t: IrSimpleType, dimensions: Int): IrSimpleType =
if (dimensions == 0)
pluginContext.irBuiltIns.anyType as IrSimpleType
else
t.toBuilder().also { it.arguments = (it.arguments[0] as IrTypeProjection)
.let { oldArg ->
listOf(makeTypeProjection(replaceComponentTypeWithAny(oldArg.type as IrSimpleType, dimensions - 1), oldArg.variance))
}
}.buildSimpleType()
var componentType = s.getArrayElementType(pluginContext.irBuiltIns)
var isPrimitiveArray = false
var dimensions = 0
var elementType: IrType = s
while (elementType.isBoxedArray || elementType.isPrimitiveArray()) {
dimensions++
if(elementType.isPrimitiveArray())
if (elementType.isPrimitiveArray())
isPrimitiveArray = true
if (((elementType as IrSimpleType).arguments.singleOrNull() as? IrTypeProjection)?.variance == Variance.IN_VARIANCE) {
// Because Java's arrays are covariant, Kotlin will render Array<in X> as Object[], Array<Array<in X>> as Object[][] etc.
componentType = replaceComponentTypeWithAny(s, dimensions - 1)
elementType = pluginContext.irBuiltIns.anyType as IrSimpleType
break
}
elementType = elementType.getArrayElementType(pluginContext.irBuiltIns)
}
@@ -857,13 +874,33 @@ open class KotlinUsesExtractor(
private val jvmWildcardAnnotation = FqName("kotlin.jvm.JvmWildcard")
private val jvmWildcardSuppressionAnnotaton = FqName("kotlin.jvm.JvmSuppressWildcards")
private fun arrayExtendsAdditionAllowed(t: IrSimpleType): Boolean =
// Note the array special case includes Array<*>, which does permit adding `? extends ...` (making `? extends Object[]` in that case)
// Surprisingly Array<in X> does permit this as well, though the contravariant array lowers to Object[] so this ends up `? extends Object[]` as well.
t.arguments[0].let {
when (it) {
is IrTypeProjection -> when (it.variance) {
Variance.INVARIANT -> false
Variance.IN_VARIANCE -> !(it.type.isAny() || it.type.isNullableAny())
Variance.OUT_VARIANCE -> extendsAdditionAllowed(it.type)
}
else -> true
}
}
private fun extendsAdditionAllowed(t: IrType) =
if (t.isBoxedArray)
arrayExtendsAdditionAllowed(t as IrSimpleType)
else
((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
private fun wildcardAdditionAllowed(v: Variance, t: IrType, addByDefault: Boolean) =
when {
t.hasAnnotation(jvmWildcardAnnotation) -> true
!addByDefault -> false
t.hasAnnotation(jvmWildcardSuppressionAnnotaton) -> false
v == Variance.IN_VARIANCE -> !(t.isNullableAny() || t.isAny())
v == Variance.OUT_VARIANCE -> ((t as? IrSimpleType)?.classOrNull?.owner?.isFinalClass) != true
v == Variance.OUT_VARIANCE -> extendsAdditionAllowed(t)
else -> false
}

View File

@@ -0,0 +1,22 @@
import java
string visibility(Method m) {
result = "public" and m.isPublic()
or
result = "protected" and m.isProtected()
or
result = "private" and m.isPrivate()
or
result = "internal" and m.isInternal()
}
// TODO: This ought to check more than just methods
from Method m
where
// TODO: This ought to work for everything, but for now we
// restrict to things in Kotlin source files
m.getFile().isKotlinSourceFile() and
// TODO: This ought to have visibility information
not m.getName() = "<clinit>" and
count(visibility(m)) != 1
select m, concat(visibility(m), ", ")

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
Added a flow step for `String.valueOf` calls on tainted `android.text.Editable` objects.

View File

@@ -29,7 +29,8 @@ class Stmt extends StmtParent, ExprParent, @stmt {
*/
Stmt getEnclosingStmt() {
result = this.getParent() or
result = this.getParent().(SwitchExpr).getEnclosingStmt()
result = this.getParent().(SwitchExpr).getEnclosingStmt() or
result = this.getParent().(WhenExpr).getEnclosingStmt()
}
/** Holds if this statement is the child of the specified parent at the specified (zero-based) position. */

View File

@@ -18,12 +18,20 @@ private class DefaultAndroidWidgetSources extends RemoteFlowSource {
private class EditableToStringStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess toString |
toString.getMethod().hasName("toString") and
toString.getReceiverType().hasQualifiedName("android.text", "Editable")
|
n1.asExpr() = toString.getQualifier() and
n2.asExpr() = toString
exists(MethodAccess ma |
ma.getMethod().hasName("toString") and
ma.getReceiverType().getASourceSupertype*().hasQualifiedName("android.text", "Editable") and
n1.asExpr() = ma.getQualifier() and
n2.asExpr() = ma
or
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf") and
ma.getArgument(0)
.getType()
.(RefType)
.getASourceSupertype*()
.hasQualifiedName("android.text", "Editable") and
n1.asExpr() = ma.getArgument(0) and
n2.asExpr() = ma
)
}
}

View File

@@ -17,5 +17,5 @@ import DataFlow::PathGraph
from LogInjectionConfiguration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This $@ flows to a log entry.", source.getNode(),
"user-provided value"
select source.getNode(), source, sink, "This user-provided value flows to a $@.", sink.getNode(),
"log entry"

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The query `java/log-injection` now reports problems at the source (user-controlled data) instead of at the ultimate logging call. This was changed because user functions that wrap the ultimate logging call could result in most alerts being reported in an uninformative location.

View File

@@ -0,0 +1,11 @@
public class User {
public static void test() {
TakesArrayList tal = new TakesArrayList();
tal.invarArray(null);
// Using one method suffices to get the extractor to describe all the methods defined on takesArrayList.
}
}

View File

@@ -0,0 +1,112 @@
public class TakesArrayList {
// There is a Java user to flag up any problems, as if the .class file differs from my
// claimed types above we'll see two overloads and two parameter types instead of one.
// Test how Array types with a variance should be lowered:
fun invarArray(a: Array<CharSequence>) { }
fun outArray(a: Array<out CharSequence>) { }
fun inArray(a: Array<in CharSequence>) { }
fun invarInvarArray(a: Array<Array<CharSequence>>) { }
fun invarOutArray(a: Array<Array<out CharSequence>>) { }
fun invarInArray(a: Array<Array<in CharSequence>>) { }
fun outInvarArray(a: Array<out Array<CharSequence>>) { }
fun outOutArray(a: Array<out Array<out CharSequence>>) { }
fun outInArray(a: Array<out Array<in CharSequence>>) { }
fun inInvarArray(a: Array<in Array<CharSequence>>) { }
fun inOutArray(a: Array<in Array<out CharSequence>>) { }
fun inInArray(a: Array<in Array<in CharSequence>>) { }
// Test how Array type arguments with a variance should acquire implicit wildcards:
fun invarArrayList(l: List<Array<CharSequence>>) { }
fun outArrayList(l: List<Array<out CharSequence>>) { }
fun inArrayList(l: List<Array<in CharSequence>>) { }
// Check the cases of nested arrays:
fun invarInvarArrayList(l: List<Array<Array<CharSequence>>>) { }
fun invarOutArrayList(l: List<Array<Array<out CharSequence>>>) { }
fun invarInArrayList(l: List<Array<Array<in CharSequence>>>) { }
fun outInvarArrayList(l: List<Array<out Array<CharSequence>>>) { }
fun outOutArrayList(l: List<Array<out Array<out CharSequence>>>) { }
fun outInArrayList(l: List<Array<out Array<in CharSequence>>>) { }
fun inInvarArrayList(l: List<Array<in Array<CharSequence>>>) { }
fun inOutArrayList(l: List<Array<in Array<out CharSequence>>>) { }
fun inInArrayList(l: List<Array<in Array<in CharSequence>>>) { }
// Now check all of that again for Comparable, whose type parameter is contravariant:
fun invarArrayComparable(c: Comparable<Array<CharSequence>>) { }
fun outArrayComparable(c: Comparable<Array<out CharSequence>>) { }
fun inArrayComparable(c: Comparable<Array<in CharSequence>>) { }
fun invarInvarArrayComparable(c: Comparable<Array<Array<CharSequence>>>) { }
fun invarOutArrayComparable(c: Comparable<Array<Array<out CharSequence>>>) { }
fun invarInArrayComparable(c: Comparable<Array<Array<in CharSequence>>>) { }
fun outInvarArrayComparable(c: Comparable<Array<out Array<CharSequence>>>) { }
fun outOutArrayComparable(c: Comparable<Array<out Array<out CharSequence>>>) { }
fun outInArrayComparable(c: Comparable<Array<out Array<in CharSequence>>>) { }
fun inInvarArrayComparable(c: Comparable<Array<in Array<CharSequence>>>) { }
fun inOutArrayComparable(c: Comparable<Array<in Array<out CharSequence>>>) { }
fun inInArrayComparable(c: Comparable<Array<in Array<in CharSequence>>>) { }
// ... duplicate all of that for a final array element (I choose String as a final type), which sometimes suppresses addition of `? extends ...`
fun invarArrayListFinal(l: List<Array<String>>) { }
fun outArrayListFinal(l: List<Array<out String>>) { }
fun inArrayListFinal(l: List<Array<in String>>) { }
fun invarInvarArrayListFinal(l: List<Array<Array<String>>>) { }
fun invarOutArrayListFinal(l: List<Array<Array<out String>>>) { }
fun invarInArrayListFinal(l: List<Array<Array<in String>>>) { }
fun outInvarArrayListFinal(l: List<Array<out Array<String>>>) { }
fun outOutArrayListFinal(l: List<Array<out Array<out String>>>) { }
fun outInArrayListFinal(l: List<Array<out Array<in String>>>) { }
fun inInvarArrayListFinal(l: List<Array<in Array<String>>>) { }
fun inOutArrayListFinal(l: List<Array<in Array<out String>>>) { }
fun inInArrayListFinal(l: List<Array<in Array<in String>>>) { }
fun invarArrayComparableFinal(c: Comparable<Array<String>>) { }
fun outArrayComparableFinal(c: Comparable<Array<out String>>) { }
fun inArrayComparableFinal(c: Comparable<Array<in String>>) { }
fun invarInvarArrayComparableFinal(c: Comparable<Array<Array<String>>>) { }
fun invarOutArrayComparableFinal(c: Comparable<Array<Array<out String>>>) { }
fun invarInArrayComparableFinal(c: Comparable<Array<Array<in String>>>) { }
fun outInvarArrayComparableFinal(c: Comparable<Array<out Array<String>>>) { }
fun outOutArrayComparableFinal(c: Comparable<Array<out Array<out String>>>) { }
fun outInArrayComparableFinal(c: Comparable<Array<out Array<in String>>>) { }
fun inInvarArrayComparableFinal(c: Comparable<Array<in Array<String>>>) { }
fun inOutArrayComparableFinal(c: Comparable<Array<in Array<out String>>>) { }
fun inInArrayComparableFinal(c: Comparable<Array<in Array<in String>>>) { }
// ... and duplicate it once more with Any as the array element, which can suppress adding `? super ...`
fun invarArrayListAny(l: List<Array<Any>>) { }
fun outArrayListAny(l: List<Array<out Any>>) { }
fun inArrayListAny(l: List<Array<in Any>>) { }
fun invarInvarArrayListAny(l: List<Array<Array<Any>>>) { }
fun invarOutArrayListAny(l: List<Array<Array<out Any>>>) { }
fun invarInArrayListAny(l: List<Array<Array<in Any>>>) { }
fun outInvarArrayListAny(l: List<Array<out Array<Any>>>) { }
fun outOutArrayListAny(l: List<Array<out Array<out Any>>>) { }
fun outInArrayListAny(l: List<Array<out Array<in Any>>>) { }
fun inInvarArrayListAny(l: List<Array<in Array<Any>>>) { }
fun inOutArrayListAny(l: List<Array<in Array<out Any>>>) { }
fun inInArrayListAny(l: List<Array<in Array<in Any>>>) { }
fun invarArrayComparableAny(c: Comparable<Array<Any>>) { }
fun outArrayComparableAny(c: Comparable<Array<out Any>>) { }
fun inArrayComparableAny(c: Comparable<Array<in Any>>) { }
fun invarInvarArrayComparableAny(c: Comparable<Array<Array<Any>>>) { }
fun invarOutArrayComparableAny(c: Comparable<Array<Array<out Any>>>) { }
fun invarInArrayComparableAny(c: Comparable<Array<Array<in Any>>>) { }
fun outInvarArrayComparableAny(c: Comparable<Array<out Array<Any>>>) { }
fun outOutArrayComparableAny(c: Comparable<Array<out Array<out Any>>>) { }
fun outInArrayComparableAny(c: Comparable<Array<out Array<in Any>>>) { }
fun inInvarArrayComparableAny(c: Comparable<Array<in Array<Any>>>) { }
fun inOutArrayComparableAny(c: Comparable<Array<in Array<out Any>>>) { }
fun inInArrayComparableAny(c: Comparable<Array<in Array<in Any>>>) { }
}

View File

@@ -0,0 +1,86 @@
broken
#select
| inArray | Object[] |
| inArrayComparable | Comparable<? super Object[]> |
| inArrayComparableAny | Comparable<? super Object[]> |
| inArrayComparableFinal | Comparable<? super Object[]> |
| inArrayList | List<? extends Object[]> |
| inArrayListAny | List<Object[]> |
| inArrayListFinal | List<? extends Object[]> |
| inInArray | Object[] |
| inInArrayComparable | Comparable<? super Object[]> |
| inInArrayComparableAny | Comparable<? super Object[]> |
| inInArrayComparableFinal | Comparable<? super Object[]> |
| inInArrayList | List<? extends Object[]> |
| inInArrayListAny | List<? extends Object[]> |
| inInArrayListFinal | List<? extends Object[]> |
| inInvarArray | Object[] |
| inInvarArrayComparable | Comparable<? super Object[]> |
| inInvarArrayComparableAny | Comparable<? super Object[]> |
| inInvarArrayComparableFinal | Comparable<? super Object[]> |
| inInvarArrayList | List<? extends Object[]> |
| inInvarArrayListAny | List<? extends Object[]> |
| inInvarArrayListFinal | List<? extends Object[]> |
| inOutArray | Object[] |
| inOutArrayComparable | Comparable<? super Object[]> |
| inOutArrayComparableAny | Comparable<? super Object[]> |
| inOutArrayComparableFinal | Comparable<? super Object[]> |
| inOutArrayList | List<? extends Object[]> |
| inOutArrayListAny | List<? extends Object[]> |
| inOutArrayListFinal | List<? extends Object[]> |
| invarArray | CharSequence[] |
| invarArrayComparable | Comparable<? super CharSequence[]> |
| invarArrayComparableAny | Comparable<? super Object[]> |
| invarArrayComparableFinal | Comparable<? super String[]> |
| invarArrayList | List<CharSequence[]> |
| invarArrayListAny | List<Object[]> |
| invarArrayListFinal | List<String[]> |
| invarInArray | Object[][] |
| invarInArrayComparable | Comparable<? super Object[][]> |
| invarInArrayComparableAny | Comparable<? super Object[][]> |
| invarInArrayComparableFinal | Comparable<? super Object[][]> |
| invarInArrayList | List<Object[][]> |
| invarInArrayListAny | List<Object[][]> |
| invarInArrayListFinal | List<Object[][]> |
| invarInvarArray | CharSequence[][] |
| invarInvarArrayComparable | Comparable<? super CharSequence[][]> |
| invarInvarArrayComparableAny | Comparable<? super Object[][]> |
| invarInvarArrayComparableFinal | Comparable<? super String[][]> |
| invarInvarArrayList | List<CharSequence[][]> |
| invarInvarArrayListAny | List<Object[][]> |
| invarInvarArrayListFinal | List<String[][]> |
| invarOutArray | CharSequence[][] |
| invarOutArrayComparable | Comparable<? super CharSequence[][]> |
| invarOutArrayComparableAny | Comparable<? super Object[][]> |
| invarOutArrayComparableFinal | Comparable<? super String[][]> |
| invarOutArrayList | List<CharSequence[][]> |
| invarOutArrayListAny | List<Object[][]> |
| invarOutArrayListFinal | List<String[][]> |
| outArray | CharSequence[] |
| outArrayComparable | Comparable<? super CharSequence[]> |
| outArrayComparableAny | Comparable<? super Object[]> |
| outArrayComparableFinal | Comparable<? super String[]> |
| outArrayList | List<? extends CharSequence[]> |
| outArrayListAny | List<? extends Object[]> |
| outArrayListFinal | List<String[]> |
| outInArray | Object[][] |
| outInArrayComparable | Comparable<? super Object[][]> |
| outInArrayComparableAny | Comparable<? super Object[][]> |
| outInArrayComparableFinal | Comparable<? super Object[][]> |
| outInArrayList | List<? extends Object[][]> |
| outInArrayListAny | List<Object[][]> |
| outInArrayListFinal | List<? extends Object[][]> |
| outInvarArray | CharSequence[][] |
| outInvarArrayComparable | Comparable<? super CharSequence[][]> |
| outInvarArrayComparableAny | Comparable<? super Object[][]> |
| outInvarArrayComparableFinal | Comparable<? super String[][]> |
| outInvarArrayList | List<CharSequence[][]> |
| outInvarArrayListAny | List<Object[][]> |
| outInvarArrayListFinal | List<String[][]> |
| outOutArray | CharSequence[][] |
| outOutArrayComparable | Comparable<? super CharSequence[][]> |
| outOutArrayComparableAny | Comparable<? super Object[][]> |
| outOutArrayComparableFinal | Comparable<? super String[][]> |
| outOutArrayList | List<? extends CharSequence[][]> |
| outOutArrayListAny | List<? extends Object[][]> |
| outOutArrayListFinal | List<String[][]> |

View File

@@ -0,0 +1,13 @@
import java
class InterestingMethod extends Method {
InterestingMethod() { this.getDeclaringType().getName() = "TakesArrayList" }
}
query predicate broken(string methodName) {
methodName = any(InterestingMethod m).getName() and
count(Type t, InterestingMethod m | methodName = m.getName() and t = m.getAParamType() | t) != 1
}
from InterestingMethod m
select m.getName(), m.getAParamType().toString()

View File

@@ -1,3 +1,53 @@
enclosing
| stmts.kt:3:5:6:5 | <Expr>; | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:3:8:4:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
| stmts.kt:3:15:4:5 | { ... } | stmts.kt:3:8:4:5 | ... -> ... |
| stmts.kt:4:15:5:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
| stmts.kt:4:22:5:5 | { ... } | stmts.kt:4:15:5:5 | ... -> ... |
| stmts.kt:5:12:6:5 | ... -> ... | stmts.kt:3:5:6:5 | <Expr>; |
| stmts.kt:5:12:6:5 | { ... } | stmts.kt:5:12:6:5 | ... -> ... |
| stmts.kt:7:5:8:16 | while (...) | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:8:9:8:16 | return ... | stmts.kt:7:5:8:16 | while (...) |
| stmts.kt:9:5:11:5 | while (...) | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:9:18:11:5 | { ... } | stmts.kt:9:5:11:5 | while (...) |
| stmts.kt:10:9:10:16 | return ... | stmts.kt:9:18:11:5 | { ... } |
| stmts.kt:12:5:14:18 | do ... while (...) | stmts.kt:12:5:14:18 | { ... } |
| stmts.kt:12:5:14:18 | { ... } | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:12:8:14:5 | { ... } | stmts.kt:12:5:14:18 | do ... while (...) |
| stmts.kt:13:9:13:16 | return ... | stmts.kt:12:8:14:5 | { ... } |
| stmts.kt:15:5:15:13 | var ...; | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:17:5:17:58 | var ...; | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:17:26:17:58 | ... -> ... | stmts.kt:17:5:17:58 | var ...; |
| stmts.kt:17:26:17:58 | ... -> ... | stmts.kt:17:5:17:58 | var ...; |
| stmts.kt:17:35:17:43 | { ... } | stmts.kt:17:26:17:58 | ... -> ... |
| stmts.kt:17:37:17:37 | <Expr>; | stmts.kt:17:35:17:43 | { ... } |
| stmts.kt:17:50:17:58 | { ... } | stmts.kt:17:26:17:58 | ... -> ... |
| stmts.kt:17:52:17:52 | <Expr>; | stmts.kt:17:50:17:58 | { ... } |
| stmts.kt:18:5:18:56 | var ...; | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:18:26:18:56 | ... -> ... | stmts.kt:18:5:18:56 | var ...; |
| stmts.kt:18:26:18:56 | ... -> ... | stmts.kt:18:5:18:56 | var ...; |
| stmts.kt:18:37:18:37 | <Expr>; | stmts.kt:18:26:18:56 | ... -> ... |
| stmts.kt:18:52:18:52 | <Expr>; | stmts.kt:18:26:18:56 | ... -> ... |
| stmts.kt:19:5:19:16 | return ... | stmts.kt:2:41:20:1 | { ... } |
| stmts.kt:23:11:27:5 | while (...) | stmts.kt:22:27:30:1 | { ... } |
| stmts.kt:23:27:27:5 | { ... } | stmts.kt:23:11:27:5 | while (...) |
| stmts.kt:24:9:26:25 | do ... while (...) | stmts.kt:24:9:26:25 | { ... } |
| stmts.kt:24:9:26:25 | { ... } | stmts.kt:23:27:27:5 | { ... } |
| stmts.kt:24:13:26:9 | { ... } | stmts.kt:24:9:26:25 | do ... while (...) |
| stmts.kt:25:13:25:33 | ... -> ... | stmts.kt:25:13:25:33 | <Expr>; |
| stmts.kt:25:13:25:33 | <Expr>; | stmts.kt:24:13:26:9 | { ... } |
| stmts.kt:25:24:25:33 | break | stmts.kt:25:13:25:33 | ... -> ... |
| stmts.kt:28:5:29:16 | while (...) | stmts.kt:22:27:30:1 | { ... } |
| stmts.kt:29:9:29:16 | continue | stmts.kt:28:5:29:16 | while (...) |
| stmts.kt:33:5:41:5 | try ... | stmts.kt:32:23:42:1 | { ... } |
| stmts.kt:33:9:35:5 | { ... } | stmts.kt:33:5:41:5 | try ... |
| stmts.kt:34:9:34:30 | throw ... | stmts.kt:33:9:35:5 | { ... } |
| stmts.kt:36:5:38:5 | catch (...) | stmts.kt:33:5:41:5 | try ... |
| stmts.kt:36:26:38:5 | { ... } | stmts.kt:36:5:38:5 | catch (...) |
| stmts.kt:37:9:37:16 | return ... | stmts.kt:36:26:38:5 | { ... } |
| stmts.kt:39:13:41:5 | { ... } | stmts.kt:33:5:41:5 | try ... |
| stmts.kt:40:9:40:16 | return ... | stmts.kt:39:13:41:5 | { ... } |
#select
| stmts.kt:2:41:20:1 | { ... } | BlockStmt |
| stmts.kt:3:5:6:5 | <Expr>; | ExprStmt |
| stmts.kt:3:8:4:5 | ... -> ... | WhenBranch |

View File

@@ -2,3 +2,5 @@ import java
from Stmt s
select s, s.getPrimaryQlClasses()
query predicate enclosing(Stmt s, Stmt encl) { s.getEnclosingStmt() = encl }

View File

@@ -2,10 +2,14 @@ import android.widget.EditText;
public class TestWidget {
private EditText source() {
return null;
}
private void sink(Object sink) {}
public void test(EditText t) {
sink(t.getText().toString()); // $ hasTaintFlow
public void test() {
sink(source().getText().toString()); // $ hasTaintFlow
}
}

View File

@@ -0,0 +1,16 @@
import android.text.Editable
class TestWidgetKt {
fun source() : Editable? { return null }
fun sink(sink : String) {}
fun test() {
val t = source()
sink(t.toString()); // $ hasTaintFlow
val t2 : Any? = source()
sink(t2.toString()); // $ MISSING: hasTaintFlow
}
}

View File

@@ -1 +1,2 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0
//codeql-extractor-kotlin-options: ${testdir}/../../../../stubs/google-android-9.0.0

View File

@@ -0,0 +1,4 @@
failures
valueOf
| TestWidgetKt.kt:10:16:10:25 | valueOf(...) |
| TestWidgetKt.kt:13:17:13:26 | valueOf(...) |

View File

@@ -2,6 +2,6 @@ import java
import semmle.code.java.dataflow.FlowSources
import TestUtilities.InlineFlowTest
class SourceTaintFlowConf extends DefaultTaintFlowConf {
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
query predicate valueOf(MethodAccess ma) {
ma.getMethod().hasQualifiedName("java.lang", "String", "valueOf")
}

View File

@@ -78,7 +78,7 @@ private import internal.FlowSummaryImplSpecific
* ensuring that they are visible to the taint tracking / data flow library.
*/
private module Frameworks {
/* TODO */
private import codeql.swift.frameworks.StandardLibrary.String
}
/**
@@ -344,11 +344,86 @@ private predicate elementSpec(
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
}
private string paramsStringPart(AbstractFunctionDecl c, int i) {
i = -1 and result = "(" and exists(c)
or
exists(int n, string p | c.getParam(n).getType().toString() = p |
i = 2 * n and result = p
or
i = 2 * n - 1 and result = "," and n != 0
)
or
i = 2 * c.getNumberOfParams() and result = ")"
}
/**
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
*
* Returns the empty string if the callable has no parameters.
* Parameter types are represented by their type erasure.
*/
cached
string paramsString(AbstractFunctionDecl c) {
result = concat(int i | | paramsStringPart(c, i) order by i)
}
bindingset[func]
predicate matchesSignature(AbstractFunctionDecl func, string signature) {
signature = "" or
paramsString(func) = signature
}
private NominalType getDeclType(IterableDeclContext decl) {
result = decl.(ClassDecl).getType()
or
result = decl.(StructDecl).getType()
or
result = getDeclType(decl.(ExtensionDecl).getExtendedTypeDecl())
or
result = decl.(EnumDecl).getType()
or
result = decl.(ProtocolDecl).getType()
}
/**
* Gets the element in module `namespace` that satisfies the following properties:
* 1. If the element is a member of a class-like type, then the class-like type has name `type`
* 2. If `subtypes = true` and the element is a member of a class-like type, then overrides of the element
* are also returned.
* 3. The element has name `name`
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
*
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
*/
pragma[nomagic]
private Element interpretElement0(
string namespace, string type, boolean subtypes, string name, string signature
) {
none() // TODO
namespace = "" and // TODO: Fill out when we properly extract modules.
(
exists(AbstractFunctionDecl func |
func.getName() = name and
type = "" and
matchesSignature(func, signature) and
subtypes = false and
not result instanceof MethodDecl and
result = func
)
or
exists(NominalType nomType, IterableDeclContext decl, MethodDecl method |
method.getName() = name and
method = decl.getAMember() and
nomType.getName() = type and
matchesSignature(method, signature) and
result = method
|
subtypes = true and
getDeclType(decl) = nomType.getADerivedType*()
or
subtypes = false and
getDeclType(decl) = nomType
)
)
}
/** Gets the source/sink/summary element corresponding to the supplied parameters. */

View File

@@ -0,0 +1,18 @@
/**
* Provides classes representing various flow sources for taint tracking.
*/
private import ExternalFlow
private import internal.DataFlowPublic
/** A data flow source of remote user input. */
abstract class RemoteFlowSource extends Node {
/** Gets a string that describes the type of this remote flow source. */
abstract string getSourceType();
}
private class ExternalRemoteFlowSource extends RemoteFlowSource {
ExternalRemoteFlowSource() { sourceNode(this, "remote") }
override string getSourceType() { result = "external" }
}

View File

@@ -181,6 +181,12 @@ class ParameterPosition extends TParameterPosition {
class PositionalParameterPosition extends ParameterPosition, TPositionalParameter {
int getIndex() { this = TPositionalParameter(result) }
override string toString() { result = this.getIndex().toString() }
}
class ThisParameterPosition extends ParameterPosition, TThisParameter {
override string toString() { result = "this" }
}
/** An argument position. */
@@ -191,6 +197,12 @@ class ArgumentPosition extends TArgumentPosition {
class PositionalArgumentPosition extends ArgumentPosition, TPositionalArgument {
int getIndex() { this = TPositionalArgument(result) }
override string toString() { result = this.getIndex().toString() }
}
class ThisArgumentPosition extends ArgumentPosition, TThisArgument {
override string toString() { result = "this" }
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */

View File

@@ -17,7 +17,7 @@ class SummarizedCallableBase = AbstractFunctionDecl;
DataFlowCallable inject(SummarizedCallable c) { result = TDataFlowFunc(c) }
/** Gets the parameter position of the instance parameter. */
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
ArgumentPosition instanceParameterPosition() { result instanceof ThisArgumentPosition }
/** Gets the synthesized summary data-flow node for the given values. */
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
@@ -31,7 +31,7 @@ DataFlowType getContentType(Content c) { any() }
/** Gets the return type of kind `rk` for callable `c`. */
bindingset[c]
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
any() // TODO
any() // TODO once we have type pruning
}
/**
@@ -39,7 +39,7 @@ DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
* synthesized call that targets a callback of type `t`.
*/
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
none() // TODO
any() // TODO once we have type pruning
}
/**
@@ -47,7 +47,7 @@ DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
* callback of type `t`.
*/
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
none() // TODO
any() // TODO once we have type pruning
}
/**
@@ -97,12 +97,12 @@ predicate sinkElement(Element e, string input, string kind, boolean generated) {
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
none() // TODO
none() // TODO once we have field flow
}
/** Gets the textual representation of the content in the format used for flow summaries. */
private string getContentSpecificCsv(Content c) {
none() // TODO
none() // TODO once we have field flow
}
/** Gets the textual representation of a summary component in the format used for flow summaries. */
@@ -117,14 +117,10 @@ string getComponentSpecificCsv(SummaryComponent sc) {
}
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
string getParameterPositionCsv(ParameterPosition pos) {
none() // TODO
}
string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() }
/** Gets the textual representation of an argument position in the format used for flow summaries. */
string getArgumentPositionCsv(ArgumentPosition pos) {
none() // TODO
}
string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() }
/** Holds if input specification component `c` needs a reference. */
predicate inputNeedsReferenceSpecific(string c) { none() }
@@ -187,11 +183,21 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
bindingset[s]
ArgumentPosition parseParamBody(string s) {
none() // TODO
exists(int index | index = AccessPath::parseInt(s) |
result.(PositionalArgumentPosition).getIndex() = index
or
index = -1 and
result instanceof ThisArgumentPosition
)
}
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
bindingset[s]
ParameterPosition parseArgBody(string s) {
none() // TODO
exists(int index | index = AccessPath::parseInt(s) |
result.(PositionalParameterPosition).getIndex() = index
or
index = -1 and
result instanceof ThisParameterPosition
)
}

View File

@@ -0,0 +1,24 @@
private import swift
private Decl getAMember(IterableDeclContext ctx) {
ctx.getAMember() = result
or
exists(VarDecl var |
ctx.getAMember() = var and
var.getAnAccessorDecl() = result
)
}
class MethodDecl extends AbstractFunctionDecl {
MethodDecl() {
this = getAMember(any(ClassDecl c))
or
this = getAMember(any(StructDecl c))
or
this = getAMember(any(ExtensionDecl c))
or
this = getAMember(any(EnumDecl c))
or
this = getAMember(any(ProtocolDecl c))
}
}

View File

@@ -1,9 +1,9 @@
private import codeql.swift.generated.expr.ApplyExpr
private import codeql.swift.elements.decl.FuncDecl
private import codeql.swift.elements.decl.AbstractFunctionDecl
private import codeql.swift.elements.expr.DeclRefExpr
class ApplyExpr extends ApplyExprBase {
FuncDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
AbstractFunctionDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
override string toString() {
result = "call to " + this.getStaticTarget().toString()

View File

@@ -1,4 +1,6 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.type.AnyGenericType
private import codeql.swift.elements.decl.GenericTypeDecl
class AnyGenericType extends AnyGenericTypeBase { }
class AnyGenericType extends AnyGenericTypeBase {
string getName() { result = this.getDeclaration().(GenericTypeDecl).getName() }
}

View File

@@ -1,4 +1,8 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.type.NominalType
private import codeql.swift.elements.decl.NominalTypeDecl
class NominalType extends NominalTypeBase { }
class NominalType extends NominalTypeBase {
NominalType getABaseType() { result = this.getDeclaration().(NominalTypeDecl).getABaseType() }
NominalType getADerivedType() { result.getABaseType() = this }
}

View File

@@ -0,0 +1,12 @@
import swift
private import codeql.swift.dataflow.ExternalFlow
private class StringSource extends SourceModelCsv {
override predicate row(string row) {
row =
[
// String(contentsOf:) is a remote flow source
";String;true;init(contentsOf:);(URL);;ReturnValue;remote"
]
}
}

View File

@@ -2,3 +2,4 @@
import codeql.swift.elements
import codeql.swift.elements.expr.LogicalOperation
import codeql.swift.elements.decl.MethodDecl

View File

@@ -0,0 +1,15 @@
/**
* @name String length conflation
* @description TODO
* @kind problem
* @problem.severity TODO
* @security-severity TODO
* @precision TODO
* @id swift/string-length-conflation
* @tags security
* external/cwe/cwe-135
*/
import swift
select "TODO"

View File

@@ -44,7 +44,7 @@
| expressions.swift:21:6:21:16 | call to failure(_:) | CallExpr |
| expressions.swift:21:14:21:14 | 11 | IntegerLiteralExpr |
| expressions.swift:27:13:27:13 | Klass.Type | TypeExpr |
| expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr |
| expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr |
| expressions.swift:27:13:27:13 | init | DeclRefExpr |
| expressions.swift:27:13:27:19 | call to ... | CallExpr |
| expressions.swift:29:9:29:19 | [...] | DictionaryExpr |
@@ -164,7 +164,7 @@
| expressions.swift:79:11:79:11 | init | OtherConstructorDeclRefExpr |
| expressions.swift:79:19:79:19 | 22 | IntegerLiteralExpr |
| expressions.swift:83:15:83:15 | Derived.Type | TypeExpr |
| expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr |
| expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr |
| expressions.swift:83:15:83:15 | init | DeclRefExpr |
| expressions.swift:83:15:83:23 | call to ... | CallExpr |
| expressions.swift:84:1:84:1 | _ | DiscardAssignmentExpr |
@@ -185,7 +185,7 @@
| expressions.swift:92:14:92:55 | call to ... | CallExpr |
| expressions.swift:92:24:92:24 | passRetained(_:) | DeclRefExpr |
| expressions.swift:92:37:92:37 | ToPtr.Type | TypeExpr |
| expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr |
| expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr |
| expressions.swift:92:37:92:37 | init | DeclRefExpr |
| expressions.swift:92:37:92:43 | call to ... | CallExpr |
| expressions.swift:92:46:92:46 | toOpaque() | DeclRefExpr |

View File

@@ -1,6 +1,3 @@
| main.swift:5:6:5:8 | ... .x | getBase: | main.swift:5:6:5:6 | (no string representation) | getName: | x |
| main.swift:11:6:11:8 | ... .a | getBase: | main.swift:11:6:11:6 | (no string representation) | getName: | a |
| main.swift:11:6:11:10 | ... .x | getBase: | main.swift:11:6:11:8 | ... .a | getName: | x |
| unresolved_dot_expr.swift:5:6:5:8 | ... .x | getBase: | unresolved_dot_expr.swift:5:6:5:6 | (no string representation) | getName: | x |
| unresolved_dot_expr.swift:11:6:11:8 | ... .a | getBase: | unresolved_dot_expr.swift:11:6:11:6 | (no string representation) | getName: | a |
| unresolved_dot_expr.swift:11:6:11:10 | ... .x | getBase: | unresolved_dot_expr.swift:11:6:11:8 | ... .a | getName: | x |

View File

@@ -13,15 +13,15 @@
| types.swift:3:9:3:9 | call to +(_:_:) | (Int, Int) -> Int |
| types.swift:3:11:3:11 | 10 | Int |
| types.swift:7:16:7:16 | X.Type | X.Type |
| types.swift:7:16:7:16 | call to ... | () -> X |
| types.swift:7:16:7:16 | call to init | () -> X |
| types.swift:7:16:7:16 | init | (X.Type) -> () -> X |
| types.swift:7:16:7:18 | call to ... | X |
| types.swift:13:17:13:17 | C.Type | C.Type |
| types.swift:13:17:13:17 | call to ... | () -> C |
| types.swift:13:17:13:17 | call to init | () -> C |
| types.swift:13:17:13:17 | init | (C.Type) -> () -> C |
| types.swift:13:17:13:19 | call to ... | C |
| types.swift:14:22:14:24 | C.Nested.Type | C.Nested.Type |
| types.swift:14:22:14:24 | call to ... | () -> C.Nested |
| types.swift:14:22:14:24 | call to init | () -> C.Nested |
| types.swift:14:22:14:31 | call to ... | C.Nested |
| types.swift:14:24:14:24 | init | (C.Nested.Type) -> () -> C.Nested |
| types.swift:17:10:17:10 | x | Int |

View File

@@ -613,9 +613,9 @@ cfg.swift:
#-----| match -> init
# 71| Int.Type
#-----| -> call to ...
#-----| -> call to init
# 71| call to ...
# 71| call to init
#-----| -> s
# 71| init
@@ -903,9 +903,9 @@ cfg.swift:
#-----| -> n1
# 110| C.Type
#-----| -> call to ...
#-----| -> call to init
# 110| call to ...
# 110| call to init
#-----| -> 42
# 110| init

View File

@@ -148,8 +148,8 @@
| declarations.swift:76:19:79:1 | { ... } | BraceStmt | declarations.swift:77:20:77:20 | x | ConcreteVarDecl |
| declarations.swift:76:19:79:1 | { ... } | BraceStmt | declarations.swift:78:3:78:10 | return ... | ReturnStmt |
| declarations.swift:77:4:77:4 | ZeroWrapper.Type | TypeExpr | declarations.swift:77:4:77:4 | FixedTypeRepr | FixedTypeRepr |
| declarations.swift:77:4:77:4 | call to ... | CallExpr | declarations.swift:77:4:77:4 | call to ... | ConstructorRefCallExpr |
| declarations.swift:77:4:77:4 | call to ... | ConstructorRefCallExpr | declarations.swift:77:4:77:4 | init | DeclRefExpr |
| declarations.swift:77:4:77:4 | call to ... | CallExpr | declarations.swift:77:4:77:4 | call to init | ConstructorRefCallExpr |
| declarations.swift:77:4:77:4 | call to init | ConstructorRefCallExpr | declarations.swift:77:4:77:4 | init | DeclRefExpr |
| declarations.swift:77:16:77:23 | var ... = ... | PatternBindingDecl | declarations.swift:77:20:77:23 | ... as ... | TypedPattern |
| declarations.swift:77:20:77:20 | ... as ... | TypedPattern | declarations.swift:77:20:77:20 | _x | NamedPattern |
| declarations.swift:77:20:77:20 | get | AccessorDecl | declarations.swift:77:20:77:20 | { ... } | BraceStmt |
@@ -414,8 +414,8 @@
| expressions.swift:27:1:27:19 | { ... } | BraceStmt | expressions.swift:27:1:27:19 | var ... = ... | PatternBindingDecl |
| expressions.swift:27:1:27:19 | { ... } | TopLevelCodeDecl | expressions.swift:27:1:27:19 | { ... } | BraceStmt |
| expressions.swift:27:13:27:13 | Klass.Type | TypeExpr | expressions.swift:27:13:27:13 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
| expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr | expressions.swift:27:13:27:13 | init | DeclRefExpr |
| expressions.swift:27:13:27:19 | call to ... | CallExpr | expressions.swift:27:13:27:13 | call to ... | ConstructorRefCallExpr |
| expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr | expressions.swift:27:13:27:13 | init | DeclRefExpr |
| expressions.swift:27:13:27:19 | call to ... | CallExpr | expressions.swift:27:13:27:13 | call to init | ConstructorRefCallExpr |
| expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl | expressions.swift:29:5:29:5 | d | NamedPattern |
| expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl | expressions.swift:29:9:29:19 | [...] | DictionaryExpr |
| expressions.swift:29:1:29:19 | { ... } | BraceStmt | expressions.swift:29:1:29:19 | var ... = ... | PatternBindingDecl |
@@ -578,8 +578,8 @@
| expressions.swift:83:1:83:23 | { ... } | BraceStmt | expressions.swift:83:1:83:23 | var ... = ... | PatternBindingDecl |
| expressions.swift:83:1:83:23 | { ... } | TopLevelCodeDecl | expressions.swift:83:1:83:23 | { ... } | BraceStmt |
| expressions.swift:83:15:83:15 | Derived.Type | TypeExpr | expressions.swift:83:15:83:15 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
| expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr | expressions.swift:83:15:83:15 | init | DeclRefExpr |
| expressions.swift:83:15:83:23 | call to ... | CallExpr | expressions.swift:83:15:83:15 | call to ... | ConstructorRefCallExpr |
| expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr | expressions.swift:83:15:83:15 | init | DeclRefExpr |
| expressions.swift:83:15:83:23 | call to ... | CallExpr | expressions.swift:83:15:83:15 | call to init | ConstructorRefCallExpr |
| expressions.swift:84:1:84:13 | ... = ... | AssignExpr | expressions.swift:84:1:84:1 | _ | DiscardAssignmentExpr |
| expressions.swift:84:1:84:13 | ... = ... | AssignExpr | expressions.swift:84:5:84:13 | .xx | MemberRefExpr |
| expressions.swift:84:1:84:13 | { ... } | BraceStmt | expressions.swift:84:1:84:13 | ... = ... | AssignExpr |
@@ -612,8 +612,8 @@
| expressions.swift:92:14:92:46 | call to toOpaque() | DotSyntaxCallExpr | expressions.swift:92:46:92:46 | toOpaque() | DeclRefExpr |
| expressions.swift:92:14:92:55 | call to ... | CallExpr | expressions.swift:92:14:92:46 | call to toOpaque() | DotSyntaxCallExpr |
| expressions.swift:92:37:92:37 | ToPtr.Type | TypeExpr | expressions.swift:92:37:92:37 | SimpleIdentTypeRepr | SimpleIdentTypeRepr |
| expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr | expressions.swift:92:37:92:37 | init | DeclRefExpr |
| expressions.swift:92:37:92:43 | call to ... | CallExpr | expressions.swift:92:37:92:37 | call to ... | ConstructorRefCallExpr |
| expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr | expressions.swift:92:37:92:37 | init | DeclRefExpr |
| expressions.swift:92:37:92:43 | call to ... | CallExpr | expressions.swift:92:37:92:37 | call to init | ConstructorRefCallExpr |
| expressions.swift:93:1:93:16 | Unmanaged<ToPtr>.Type | TypeExpr | expressions.swift:93:1:93:16 | ...<...> | GenericIdentTypeRepr |
| expressions.swift:93:1:93:18 | call to fromOpaque(_:) | DotSyntaxCallExpr | expressions.swift:93:18:93:18 | fromOpaque(_:) | DeclRefExpr |
| expressions.swift:93:1:93:35 | call to ... | CallExpr | expressions.swift:93:1:93:18 | call to fromOpaque(_:) | DotSyntaxCallExpr |

View File

@@ -2,5 +2,6 @@ name: codeql-swift-tests
version: 0.0.0
dependencies:
codeql/swift-all: "*"
codeql/swift-queries: "*"
tests: .
extractor: swift

View File

@@ -0,0 +1 @@
| TODO |

View File

@@ -0,0 +1 @@
queries/Security/CWE-135/StringLengthConflation.ql

View File

@@ -0,0 +1,125 @@
// --- stubs ---
func print(_ items: Any...) {}
typealias unichar = UInt16
class NSObject
{
}
class NSString : NSObject
{
init(string: String) { length = string.count }
func character(at: Int) -> unichar { return 0 }
func substring(from: Int) -> String { return "" }
func substring(to: Int) -> String { return "" }
private(set) var length: Int
}
class NSMutableString : NSString
{
func insert(_: String, at: Int) {}
}
class NSRange
{
init(location: Int, length: Int) { self.description = "" }
private(set) var description: String
}
func NSMakeRange(_ loc: Int, _ len: Int) -> NSRange { return NSRange(location: loc, length: len) }
// --- tests ---
func test(s: String) {
let ns = NSString(string: s)
let nms = NSMutableString(string: s)
print("'\(s)'")
print("count \(s.count) length \(ns.length)")
print("utf8.count \(s.utf8.count) utf16.count \(s.utf16.count) unicodeScalars.count \(s.unicodeScalars.count)")
// --- constructing a String.Index from integer ---
let ix1 = String.Index(encodedOffset: s.count) // GOOD
let ix2 = String.Index(encodedOffset: ns.length) // BAD: NSString length used in String.Index
let ix3 = String.Index(encodedOffset: s.utf8.count) // BAD: String.utf8 length used in String.Index
let ix4 = String.Index(encodedOffset: s.utf16.count) // BAD: String.utf16 length used in String.Index
let ix5 = String.Index(encodedOffset: s.unicodeScalars.count) // BAD: string.unicodeScalars length used in String.Index
print("String.Index '\(ix1.encodedOffset)' / '\(ix2.encodedOffset)' '\(ix3.encodedOffset)' '\(ix4.encodedOffset)' '\(ix5.encodedOffset)'")
let ix6 = s.index(s.startIndex, offsetBy: s.count / 2) // GOOD
let ix7 = s.index(s.startIndex, offsetBy: ns.length / 2) // BAD: NSString length used in String.Index
print("index '\(ix6.encodedOffset)' / '\(ix7.encodedOffset)'")
var ix8 = s.startIndex
s.formIndex(&ix8, offsetBy: s.count / 2) // GOOD
var ix9 = s.startIndex
s.formIndex(&ix9, offsetBy: ns.length / 2) // BAD: NSString length used in String.Index
print("formIndex '\(ix8.encodedOffset)' / '\(ix9.encodedOffset)'")
// --- constructing an NSRange from integers ---
let range1 = NSMakeRange(0, ns.length) // GOOD
let range2 = NSMakeRange(0, s.count) // BAD: String length used in NSMakeRange
let range3 = NSMakeRange(0, s.reversed().count) // BAD: String length used in NSMakeRange
let range4 = NSMakeRange(0, s.distance(from: s.startIndex, to: s.endIndex)) // BAD: String length used in NSMakeRange
print("NSMakeRange '\(range1.description)' / '\(range2.description)' '\(range3.description)' '\(range4.description)'")
let range5 = NSRange(location: 0, length: ns.length) // GOOD
let range6 = NSRange(location: 0, length: s.count) // BAD: String length used in NSMakeRange
print("NSRange '\(range5.description)' / '\(range6.description)'")
// --- String operations using an integer directly ---
let str1 = s.dropFirst(s.count - 1) // GOOD
let str2 = s.dropFirst(ns.length - 1) // BAD: NSString length used in String
print("dropFirst '\(str1)' / '\(str2)'")
let str3 = s.dropLast(s.count - 1) // GOOD
let str4 = s.dropLast(ns.length - 1) // BAD: NSString length used in String
print("dropLast '\(str3)' / '\(str4)'")
let str5 = s.prefix(s.count - 1) // GOOD
let str6 = s.prefix(ns.length - 1) // BAD: NSString length used in String
print("prefix '\(str5)' / '\(str6)'")
let str7 = s.suffix(s.count - 1) // GOOD
let str8 = s.suffix(ns.length - 1) // BAD: NSString length used in String
print("suffix '\(str7)' / '\(str8)'")
let nstr1 = ns.character(at: ns.length - 1) // GOOD
let nmstr1 = nms.character(at: nms.length - 1) // GOOD
let nstr2 = ns.character(at: s.count - 1) // BAD: String length used in NSString
let nmstr2 = nms.character(at: s.count - 1) // BAD: String length used in NString
print("character '\(nstr1)' '\(nmstr1)' / '\(nstr2)' '\(nmstr2)'")
let nstr3 = ns.substring(from: ns.length - 1) // GOOD
let nmstr3 = nms.substring(from: nms.length - 1) // GOOD
let nstr4 = ns.substring(from: s.count - 1) // BAD: String length used in NSString
let nmstr4 = nms.substring(from: s.count - 1) // BAD: String length used in NString
print("substring from '\(nstr3)' '\(nmstr3)' / '\(nstr4)' '\(nmstr4)'")
let nstr5 = ns.substring(to: ns.length - 1) // GOOD
let nmstr5 = nms.substring(to: nms.length - 1) // GOOD
let nstr6 = ns.substring(to: s.count - 1) // BAD: String length used in NSString
let nmstr6 = nms.substring(to: s.count - 1) // BAD: String length used in NString
print("substring to '\(nstr5)' '\(nmstr5)' / '\(nstr6)' '\(nmstr6)'")
let nmstr7 = NSMutableString(string: s)
nmstr7.insert("*", at: nms.length - 1) // GOOD
let nmstr8 = NSMutableString(string: s)
nmstr8.insert("*", at: s.count - 1) // BAD: String length used in NSString
print("insert '\(nmstr7)' / '\(nmstr8)'")
}
// `begin :thumbsup: end`, with thumbs up emoji and skin tone modifier
test(s: "begin \u{0001F44D}\u{0001F3FF} end")