diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 647968e9bc6..bec8d711ab2 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -95,6 +95,12 @@ private module Frameworks { private import semmle.code.java.security.LdapInjection private import semmle.code.java.security.XPath private import semmle.code.java.security.JexlInjection + private import semmle.code.java.frameworks.android.SQLite + private import semmle.code.java.frameworks.Jdbc + private import semmle.code.java.frameworks.SpringJdbc + private import semmle.code.java.frameworks.MyBatis + private import semmle.code.java.frameworks.Hibernate + private import semmle.code.java.frameworks.jOOQ } private predicate sourceModelCsv(string row) { diff --git a/java/ql/src/semmle/code/java/frameworks/Hibernate.qll b/java/ql/src/semmle/code/java/frameworks/Hibernate.qll index 5ad0448249f..e4eb2516f2c 100644 --- a/java/ql/src/semmle/code/java/frameworks/Hibernate.qll +++ b/java/ql/src/semmle/code/java/frameworks/Hibernate.qll @@ -3,6 +3,7 @@ */ import java +import semmle.code.java.dataflow.ExternalFlow /** The interface `org.hibernate.query.QueryProducer`. */ class HibernateQueryProducer extends RefType { @@ -21,19 +22,18 @@ class HibernateSession extends RefType { HibernateSession() { this.hasQualifiedName("org.hibernate", "Session") } } -/** - * Holds if `m` is a method on `HibernateQueryProducer`, or `HibernateSharedSessionContract` - * or `HibernateSession`, or a subclass, taking an SQL string as its first argument. - */ -predicate hibernateSqlMethod(Method m) { - exists(RefType t | - t = m.getDeclaringType().getASourceSupertype*() and - ( - t instanceof HibernateQueryProducer or - t instanceof HibernateSharedSessionContract or - t instanceof HibernateSession - ) - ) and - m.getParameterType(0) instanceof TypeString and - m.hasName(["createQuery", "createNativeQuery", "createSQLQuery"]) +private class SqlSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "org.hibernate;QueryProducer;true;createQuery;;;Argument[0];sql", + "org.hibernate;QueryProducer;true;createNativeQuery;;;Argument[0];sql", + "org.hibernate;QueryProducer;true;createSQLQuery;;;Argument[0];sql", + "org.hibernate;SharedSessionContract;true;createQuery;;;Argument[0];sql", + "org.hibernate;SharedSessionContract;true;createSQLQuery;;;Argument[0];sql", + "org.hibernate;Session;true;createQuery;;;Argument[0];sql", + "org.hibernate;Session;true;createSQLQuery;;;Argument[0];sql" + ] + } } diff --git a/java/ql/src/semmle/code/java/frameworks/Jdbc.qll b/java/ql/src/semmle/code/java/frameworks/Jdbc.qll index c0681305756..b851842dfd3 100644 --- a/java/ql/src/semmle/code/java/frameworks/Jdbc.qll +++ b/java/ql/src/semmle/code/java/frameworks/Jdbc.qll @@ -3,6 +3,7 @@ */ import semmle.code.java.Type +import semmle.code.java.dataflow.ExternalFlow /*--- Types ---*/ /** The interface `java.sql.Connection`. */ @@ -26,62 +27,6 @@ class TypeStatement extends Interface { } /*--- Methods ---*/ -/** A method with the name `prepareStatement` declared in `java.sql.Connection`. */ -class ConnectionPrepareStatement extends Method { - ConnectionPrepareStatement() { - getDeclaringType() instanceof TypeConnection and - hasName("prepareStatement") - } -} - -/** A method with the name `prepareCall` declared in `java.sql.Connection`. */ -class ConnectionPrepareCall extends Method { - ConnectionPrepareCall() { - getDeclaringType() instanceof TypeConnection and - hasName("prepareCall") - } -} - -/** A method with the name `executeQuery` declared in `java.sql.Statement`. */ -class StatementExecuteQuery extends Method { - StatementExecuteQuery() { - getDeclaringType() instanceof TypeStatement and - hasName("executeQuery") - } -} - -/** A method with the name `execute` declared in `java.sql.Statement`. */ -class MethodStatementExecute extends Method { - MethodStatementExecute() { - getDeclaringType() instanceof TypeStatement and - hasName("execute") - } -} - -/** A method with the name `executeUpdate` declared in `java.sql.Statement`. */ -class MethodStatementExecuteUpdate extends Method { - MethodStatementExecuteUpdate() { - getDeclaringType() instanceof TypeStatement and - hasName("executeUpdate") - } -} - -/** A method with the name `executeLargeUpdate` declared in `java.sql.Statement`. */ -class MethodStatementExecuteLargeUpdate extends Method { - MethodStatementExecuteLargeUpdate() { - getDeclaringType() instanceof TypeStatement and - hasName("executeLargeUpdate") - } -} - -/** A method with the name `addBatch` declared in `java.sql.Statement`. */ -class MethodStatementAddBatch extends Method { - MethodStatementAddBatch() { - getDeclaringType() instanceof TypeStatement and - hasName("addBatch") - } -} - /** A method with the name `getString` declared in `java.sql.ResultSet`. */ class ResultSetGetStringMethod extends Method { ResultSetGetStringMethod() { @@ -92,24 +37,18 @@ class ResultSetGetStringMethod extends Method { } /*--- Other definitions ---*/ -/** - * An expression representing SQL code that occurs as an argument of - * a method in `java.sql.Connection` or `java.sql.Statement`. - */ -class SqlExpr extends Expr { - SqlExpr() { - exists(MethodAccess call, Method method | - call.getArgument(0) = this and - method = call.getMethod() and - ( - method instanceof ConnectionPrepareStatement or - method instanceof ConnectionPrepareCall or - method instanceof StatementExecuteQuery or - method instanceof MethodStatementExecute or - method instanceof MethodStatementExecuteUpdate or - method instanceof MethodStatementExecuteLargeUpdate or - method instanceof MethodStatementAddBatch - ) - ) +private class SqlSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "java.sql;Connection;true;prepareStatement;;;Argument[0];sql", + "java.sql;Connection;true;prepareCall;;;Argument[0];sql", + "java.sql;Statement;true;execute;;;Argument[0];sql", + "java.sql;Statement;true;executeQuery;;;Argument[0];sql", + "java.sql;Statement;true;executeUpdate;;;Argument[0];sql", + "java.sql;Statement;true;executeLargeUpdate;;;Argument[0];sql", + "java.sql;Statement;true;addBatch;;;Argument[0];sql" + ] } } diff --git a/java/ql/src/semmle/code/java/frameworks/MyBatis.qll b/java/ql/src/semmle/code/java/frameworks/MyBatis.qll index 46827d0fb4f..c527463a788 100644 --- a/java/ql/src/semmle/code/java/frameworks/MyBatis.qll +++ b/java/ql/src/semmle/code/java/frameworks/MyBatis.qll @@ -3,25 +3,24 @@ */ import java +import semmle.code.java.dataflow.ExternalFlow /** The class `org.apache.ibatis.jdbc.SqlRunner`. */ class MyBatisSqlRunner extends RefType { MyBatisSqlRunner() { this.hasQualifiedName("org.apache.ibatis.jdbc", "SqlRunner") } } -/** - * Holds if `m` is a method on `MyBatisSqlRunner` taking an SQL string as its - * first argument. - */ -predicate mybatisSqlMethod(Method m) { - m.getDeclaringType() instanceof MyBatisSqlRunner and - m.getParameterType(0) instanceof TypeString and - ( - m.hasName("delete") or - m.hasName("insert") or - m.hasName("run") or - m.hasName("selectAll") or - m.hasName("selectOne") or - m.hasName("update") - ) +private class SqlSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "org.apache.ibatis.jdbc;SqlRunner;false;delete;(String,Object[]);;Argument[0];sql", + "org.apache.ibatis.jdbc;SqlRunner;false;insert;(String,Object[]);;Argument[0];sql", + "org.apache.ibatis.jdbc;SqlRunner;false;run;(String);;Argument[0];sql", + "org.apache.ibatis.jdbc;SqlRunner;false;selectAll;(String,Object[]);;Argument[0];sql", + "org.apache.ibatis.jdbc;SqlRunner;false;selectOne;(String,Object[]);;Argument[0];sql", + "org.apache.ibatis.jdbc;SqlRunner;false;update;(String,Object[]);;Argument[0];sql" + ] + } } diff --git a/java/ql/src/semmle/code/java/frameworks/SpringJdbc.qll b/java/ql/src/semmle/code/java/frameworks/SpringJdbc.qll index d563438951f..3eba5b41065 100644 --- a/java/ql/src/semmle/code/java/frameworks/SpringJdbc.qll +++ b/java/ql/src/semmle/code/java/frameworks/SpringJdbc.qll @@ -3,33 +3,28 @@ */ import java +import semmle.code.java.dataflow.ExternalFlow /** The class `org.springframework.jdbc.core.JdbcTemplate`. */ class JdbcTemplate extends RefType { JdbcTemplate() { this.hasQualifiedName("org.springframework.jdbc.core", "JdbcTemplate") } } -/** - * Holds if `m` is a method on `JdbcTemplate` taking an SQL string as its first - * argument. - */ -predicate jdbcSqlMethod(Method m) { - m.getDeclaringType() instanceof JdbcTemplate and - m.getParameterType(0) instanceof TypeString and - ( - m.hasName("batchUpdate") or - m.hasName("execute") or - m.getName().matches("query%") or - m.hasName("update") - ) -} - -/** The method `JdbcTemplate.batchUpdate(String... sql)` */ -class BatchUpdateVarargsMethod extends Method { - BatchUpdateVarargsMethod() { - this.getDeclaringType() instanceof JdbcTemplate and - this.hasName("batchUpdate") and - this.getParameterType(0).(Array).getComponentType() instanceof TypeString and - this.getParameter(0).isVarargs() +private class SqlSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "org.springframework.jdbc.core;JdbcTemplate;false;batchUpdate;(String[]);;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;batchUpdate;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;execute;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;update;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;query;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;queryForList;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;queryForMap;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;queryForObject;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;queryForRowSet;;;Argument[0];sql", + "org.springframework.jdbc.core;JdbcTemplate;false;queryForStream;;;Argument[0];sql" + ] } } diff --git a/java/ql/src/semmle/code/java/frameworks/android/SQLite.qll b/java/ql/src/semmle/code/java/frameworks/android/SQLite.qll index 97ac1fd87bc..d53d8db5519 100644 --- a/java/ql/src/semmle/code/java/frameworks/android/SQLite.qll +++ b/java/ql/src/semmle/code/java/frameworks/android/SQLite.qll @@ -1,6 +1,7 @@ import java import Android import semmle.code.java.dataflow.FlowSteps +import semmle.code.java.dataflow.ExternalFlow /** * The class `android.database.sqlite.SQLiteDatabase`. @@ -23,209 +24,90 @@ class TypeDatabaseUtils extends Class { TypeDatabaseUtils() { hasQualifiedName("android.database", "DatabaseUtils") } } -abstract class SQLiteRunner extends Method { - abstract int sqlIndex(); -} - -private class ExecSqlMethod extends SQLiteRunner { - ExecSqlMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - // execPerConnectionSQL(String sql, Object[] bindArgs) - // execSQL(String sql) - // execSQL(String sql, Object[] bindArgs) - this.hasName(["execPerConnectionSQL", "execSQL"]) +private class SQLiteSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "android.database.sqlite;SQLiteDatabase;false;compileStatement;(String);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;execSQL;(String);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;execSQL;(String,Object[]);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;execPerConnectionSQL;(String,Object[]);;Argument[0];sql", + // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) + // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) + // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) + // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) + // Each String / String[] arg except for selectionArgs is a sink + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String,String);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String,String);;Argument[1];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String,String);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String,String);;Argument[4..7];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String);;Argument[0..2];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(String,String[],String,String[],String,String,String);;Argument[4..6];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String);;Argument[1];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String);;Argument[3];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String);;Argument[5..8];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[1];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[3];sql", + "android.database.sqlite;SQLiteDatabase;false;query;(boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[5..8];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String);;Argument[3];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String);;Argument[4];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String);;Argument[6..9];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[3];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[4];sql", + "android.database.sqlite;SQLiteDatabase;false;queryWithFactory;(CursorFactory,boolean,String,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[6..9];sql", + "android.database.sqlite;SQLiteDatabase;false;rawQuery;(String,String[]);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;rawQuery;(String,String[],CancellationSignal);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;rawQueryWithFactory;(CursorFactory,String,String[],String);;Argument[1];sql", + "android.database.sqlite;SQLiteDatabase;false;rawQueryWithFactory;(CursorFactory,String,String[],String,CancellationSignal);;Argument[1];sql", + "android.database.sqlite;SQLiteDatabase;false;delete;(String,String,String[]);;Argument[0..1];sql", + "android.database.sqlite;SQLiteDatabase;false;update;(String,ContentValues,String,String[]);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;update;(String,ContentValues,String,String[]);;Argument[2];sql", + "android.database.sqlite;SQLiteDatabase;false;updateWithOnConflict;(String,ContentValues,String,String[],int);;Argument[0];sql", + "android.database.sqlite;SQLiteDatabase;false;updateWithOnConflict;(String,ContentValues,String,String[],int);;Argument[2];sql", + "android.database;DatabaseUtils;false;longForQuery;(SQLiteDatabase,String,String[]);;Argument[1];sql", + "android.database;DatabaseUtils;false;stringForQuery;(SQLiteDatabase,String,String[]);;Argument[1];sql", + "android.database;DatabaseUtils;false;blobFileDescriptorForQuery;(SQLiteDatabase,String,String[]);;Argument[1];sql", + "android.database;DatabaseUtils;false;createDbFromSqlStatements;(Context,String,int,String);;Argument[3];sql", + "android.database;DatabaseUtils;false;queryNumEntries;(SQLiteDatabase,String);;Argument[1];sql", + "android.database;DatabaseUtils;false;queryNumEntries;(SQLiteDatabase,String,String);;Argument[1..2];sql", + "android.database;DatabaseUtils;false;queryNumEntries;(SQLiteDatabase,String,String,String[]);;Argument[1..2];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;delete;(SQLiteDatabase,String,String[]);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;delete;(SQLiteDatabase,String,String[]);;Argument[1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;insert;(SQLiteDatabase,ContentValues);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;update;(SQLiteDatabase,ContentValues,String,String[]);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;update;(SQLiteDatabase,ContentValues,String,String[]);;Argument[2];sql", + // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder) + // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit) + // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit, CancellationSignal cancellationSignal) + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String);;Argument[1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String);;Argument[2];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String);;Argument[4..6];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String);;Argument[1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String);;Argument[2];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String);;Argument[4..7];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[-1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[1];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[2];sql", + "android.database.sqlite;SQLiteQueryBuilder;true;query;(SQLiteDatabase,String[],String,String[],String,String,String,String,CancellationSignal);;Argument[4..7];sql", + "android.content;ContentProvider;true;delete;(Uri,String,String[]);;Argument[1];sql", + "android.content;ContentProvider;true;update;(Uri,ContentValues,String,String[]);;Argument[2];sql", + "android.content;ContentProvider;true;query;(Uri,String[],String,String[],String,CancellationSignal);;Argument[2];sql", + "android.content;ContentProvider;true;query;(Uri,String[],String,String[],String);;Argument[2];sql", + "android.content;ContentResolver;true;delete;(Uri,String,String[]);;Argument[1];sql", + "android.content;ContentResolver;true;update;(Uri,ContentValues,String,String[]);;Argument[2];sql", + "android.content;ContentResolver;true;query;(Uri,String[],String,String[],String,CancellationSignal);;Argument[2];sql", + "android.content;ContentResolver;true;query;(Uri,String[],String,String[],String);;Argument[2];sql" + ] } - - override int sqlIndex() { result = 0 } -} - -private class QueryMethod extends SQLiteRunner { - QueryMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - this.hasName(["query", "queryWithFactory"]) - } - - override int sqlIndex() { - // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) - // query(boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) - // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) - // query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy) - this.getName() = "query" and - ( - if this.getParameter(0).getType() instanceof TypeString - then result = [0, 1, 2, 4, 5, 6, 7] - else result = [1, 2, 3, 5, 6, 7, 8] - ) - or - // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit, CancellationSignal cancellationSignal) - // queryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit) - this.getName() = "queryWithFactory" and result = [2, 3, 4, 6, 7, 8, 9] - } -} - -private class RawQueryMethod extends SQLiteRunner { - RawQueryMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - this.hasName(["rawQuery", "rawQueryWithFactory"]) - } - - override int sqlIndex() { - // rawQuery(String sql, String[] selectionArgs, CancellationSignal cancellationSignal) - // rawQuery(String sql, String[] selectionArgs) - this.getName() = "rawQuery" and result = 0 - or - // rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable, CancellationSignal cancellationSignal) - // rawQueryWithFactory(SQLiteDatabase.CursorFactory cursorFactory, String sql, String[] selectionArgs, String editTable) - this.getName() = "rawQueryWithFactory" and result = 1 - } -} - -private class CompileStatementMethod extends SQLiteRunner { - CompileStatementMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - // compileStatement(String sql) - this.hasName("compileStatement") - } - - override int sqlIndex() { result = 0 } -} - -private class DeleteMethod extends SQLiteRunner { - DeleteMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - // delete(String table, String whereClause, String[] whereArgs) - this.hasName("delete") - } - - override int sqlIndex() { result = 1 } -} - -private class UpdateMethod extends SQLiteRunner { - UpdateMethod() { - this.getDeclaringType() instanceof TypeSQLiteDatabase and - // update(String table, ContentValues values, String whereClause, String[] whereArgs) - // updateWithOnConflict(String table, ContentValues values, String whereClause, String[] whereArgs, int conflictAlgorithm) - this.hasName(["update", "updateWithOnConflict"]) - } - - override int sqlIndex() { result = 2 } -} - -private class ForQueryMethod extends SQLiteRunner { - ForQueryMethod() { - // (blobFileDescriptor|long|string)ForQuery(SQLiteDatabase db, String query, String[] selectionArgs) - this.getDeclaringType() instanceof TypeDatabaseUtils and - this.hasName(["blobFileDescriptorForQuery", "longForQuery", "stringForQuery"]) and - this.getNumberOfParameters() = 3 - } - - override int sqlIndex() { result = 1 } -} - -private class CreateDbFromSqlStatementsMethod extends SQLiteRunner { - CreateDbFromSqlStatementsMethod() { - // createDbFromSqlStatements(Context context, String dbName, int dbVersion, String sqlStatements) - this.getDeclaringType() instanceof TypeDatabaseUtils and - this.hasName("createDbFromSqlStatements") - } - - override int sqlIndex() { result = 3 } -} - -private class QueryNumEntriesMethod extends SQLiteRunner { - QueryNumEntriesMethod() { - // queryNumEntries(SQLiteDatabase db, String table, String selection) - // queryNumEntries(SQLiteDatabase db, String table, String selection, String[] selectionArgs) - this.getDeclaringType() instanceof TypeDatabaseUtils and - this.hasName("queryNumEntries") - } - - override int sqlIndex() { result = 2 } -} - -private class QueryBuilderDeleteMethod extends SQLiteRunner { - QueryBuilderDeleteMethod() { - // delete(SQLiteDatabase db, String selection, String[] selectionArgs) - this.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and - this.hasName("delete") - } - - override int sqlIndex() { result = [-1, 1] } -} - -private class QueryBuilderInsertMethod extends SQLiteRunner { - QueryBuilderInsertMethod() { - // insert(SQLiteDatabase db, ContentValues values) - this.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and - this.hasName("insert") - } - - override int sqlIndex() { result = -1 } -} - -private class QueryBuilderQueryMethod extends SQLiteRunner { - QueryBuilderQueryMethod() { - // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder) - // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit) - // query(SQLiteDatabase db, String[] projectionIn, String selection, String[] selectionArgs, String groupBy, String having, String sortOrder, String limit, CancellationSignal cancellationSignal) - this.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and - this.hasName("query") - } - - override int sqlIndex() { result = [-1, 2, 4, 5, 6, 7] } -} - -private class QueryBuilderUpdateMethod extends SQLiteRunner { - QueryBuilderUpdateMethod() { - // update(SQLiteDatabase db, ContentValues values, String selection, String[] selectionArgs) - this.getDeclaringType().getASourceSupertype*() instanceof TypeSQLiteQueryBuilder and - this.hasName("update") - } - - override int sqlIndex() { result = [-1, 2] } -} - -private class ContentProviderDeleteMethod extends SQLiteRunner { - ContentProviderDeleteMethod() { - // delete(Uri uri, String selection, String[] selectionArgs) - ( - this.getDeclaringType() instanceof AndroidContentProvider or - this.getDeclaringType() instanceof AndroidContentResolver - ) and - this.hasName("delete") and - this.getNumberOfParameters() = 3 - } - - override int sqlIndex() { result = 1 } -} - -private class ContentProviderQueryMethod extends SQLiteRunner { - ContentProviderQueryMethod() { - // query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) - // query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) - ( - this.getDeclaringType() instanceof AndroidContentProvider or - this.getDeclaringType() instanceof AndroidContentResolver - ) and - this.hasName("query") and - this.getNumberOfParameters() = [5, 6] - } - - override int sqlIndex() { result = 2 } -} - -private class ContentProviderUpdateMethod extends SQLiteRunner { - ContentProviderUpdateMethod() { - // update(Uri uri, ContentValues values, String selection, String[] selectionArgs) - ( - this.getDeclaringType() instanceof AndroidContentProvider or - this.getDeclaringType() instanceof AndroidContentResolver - ) and - this.hasName("update") and - this.getNumberOfParameters() = 4 - } - - override int sqlIndex() { result = 2 } } private class QueryBuilderBuildMethod extends TaintPreservingCallable { diff --git a/java/ql/src/semmle/code/java/frameworks/jOOQ.qll b/java/ql/src/semmle/code/java/frameworks/jOOQ.qll index 5f473a18f33..c95c9f4c90f 100644 --- a/java/ql/src/semmle/code/java/frameworks/jOOQ.qll +++ b/java/ql/src/semmle/code/java/frameworks/jOOQ.qll @@ -3,6 +3,7 @@ */ import java +import semmle.code.java.dataflow.ExternalFlow /** * Methods annotated with this allow for generation of "plain SQL" @@ -21,3 +22,13 @@ predicate jOOQSqlMethod(Method m) { m.getAnAnnotation() instanceof PlainSQLType and m.getParameterType(0) instanceof TypeString } + +private class SqlSinkCsv extends SinkModelCsv { + override predicate row(string row) { + row = + [ + //"package;type;overrides;name;signature;ext;spec;kind" + "org.jooq;PlainSQL;false;;;Annotated;Argument[0];sql" + ] + } +} diff --git a/java/ql/src/semmle/code/java/security/QueryInjection.qll b/java/ql/src/semmle/code/java/security/QueryInjection.qll index 604a5bacc12..86bd6dac4ad 100644 --- a/java/ql/src/semmle/code/java/security/QueryInjection.qll +++ b/java/ql/src/semmle/code/java/security/QueryInjection.qll @@ -2,13 +2,8 @@ import java import semmle.code.java.dataflow.DataFlow -import semmle.code.java.frameworks.Jdbc -import semmle.code.java.frameworks.jOOQ -import semmle.code.java.frameworks.android.SQLite import semmle.code.java.frameworks.javaee.Persistence -import semmle.code.java.frameworks.SpringJdbc -import semmle.code.java.frameworks.MyBatis -import semmle.code.java.frameworks.Hibernate +import semmle.code.java.dataflow.ExternalFlow /** A sink for database query language injection vulnerabilities. */ abstract class QueryInjectionSink extends DataFlow::Node { } @@ -29,28 +24,7 @@ class AdditionalQueryInjectionTaintStep extends Unit { /** A sink for SQL injection vulnerabilities. */ private class SqlInjectionSink extends QueryInjectionSink { - SqlInjectionSink() { - this.asExpr() instanceof SqlExpr - or - exists(MethodAccess ma, Method m, int index | - ma.getMethod() = m and - if index = -1 - then this.asExpr() = ma.getQualifier() - else ma.getArgument(index) = this.asExpr() - | - index = m.(SQLiteRunner).sqlIndex() - or - m instanceof BatchUpdateVarargsMethod - or - index = 0 and jdbcSqlMethod(m) - or - index = 0 and mybatisSqlMethod(m) - or - index = 0 and hibernateSqlMethod(m) - or - index = 0 and jOOQSqlMethod(m) - ) - } + SqlInjectionSink() { sinkNode(this, "sql") } } /** A sink for Java Persistence Query Language injection vulnerabilities. */ diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/FlowSteps.java b/java/ql/test/library-tests/frameworks/android/taint-database/FlowSteps.java index c53df505671..afaf28fe03d 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/FlowSteps.java +++ b/java/ql/test/library-tests/frameworks/android/taint-database/FlowSteps.java @@ -27,155 +27,160 @@ public class FlowSteps { } public static String[] appendSelectionArgs() { - String[] originalValues = taint(); - String[] newValues = taint(); + String[] originalValues = {taint()}; // $ MISSING: taintReachesReturn + String[] newValues = {taint()}; // $ MISSING: taintReachesReturn return DatabaseUtils.appendSelectionArgs(originalValues, newValues); } public static String concatenateWhere() { - String a = taint(); - String b = taint(); + String a = taint(); // $taintReachesReturn + String b = taint(); // $taintReachesReturn return DatabaseUtils.concatenateWhere(a, b); } public static String buildQueryString(MySQLiteQueryBuilder target) { target = taint(); - boolean distinct = taint(); - String tables = taint(); - String[] columns = taint(); - String where = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + boolean distinct = taint(); + String tables = taint(); // $taintReachesReturn + String[] columns = {taint()}; // $ MISSING: taintReachesReturn + String where = taint(); // $taintReachesReturn + String groupBy = taint(); // $taintReachesReturn + String having = taint(); // $taintReachesReturn + String orderBy = taint(); // $taintReachesReturn + String limit = taint(); // $taintReachesReturn return SQLiteQueryBuilder.buildQueryString(distinct, tables, columns, where, groupBy, having, orderBy, limit); } public static String buildQuery(MySQLiteQueryBuilder target) { - target = taint(); - String[] projectionIn = taint(); - String selection = taint(); - String groupBy = taint(); - String having = taint(); - String sortOrder = taint(); - String limit = taint(); + target = taint(); // $taintReachesReturn + String[] projectionIn = {taint()};// $ MISSING: taintReachesReturn + String selection = taint(); // $taintReachesReturn + String groupBy = taint(); // $taintReachesReturn + String having = taint(); // $taintReachesReturn + String sortOrder = taint(); // $taintReachesReturn + String limit = taint(); // $taintReachesReturn return target.buildQuery(projectionIn, selection, groupBy, having, sortOrder, limit); } public static String buildQuery2(MySQLiteQueryBuilder target) { - target = taint(); - String[] projectionIn = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String sortOrder = taint(); - String limit = taint(); + target = taint(); // $taintReachesReturn + String[] projectionIn = {taint()}; // $ MISSING: taintReachesReturn + String selection = taint(); // $taintReachesReturn + String[] selectionArgs = {taint()}; // $ MISSING: taintReachesReturn + String groupBy = taint(); // $taintReachesReturn + String having = taint(); // $taintReachesReturn + String sortOrder = taint(); // $taintReachesReturn + String limit = taint(); // $taintReachesReturn return target.buildQuery(projectionIn, selection, selectionArgs, groupBy, having, sortOrder, limit); } public static String buildUnionQuery(MySQLiteQueryBuilder target) { - target = taint(); - String[] subQueries = taint(); - String sortOrder = taint(); - String limit = taint(); + target = taint(); // $taintReachesReturn + String[] subQueries = {taint()}; // $ MISSING: taintReachesReturn + String sortOrder = taint(); // $taintReachesReturn + String limit = taint(); // $taintReachesReturn return target.buildUnionQuery(subQueries, sortOrder, limit); } public static String buildUnionSubQuery2(MySQLiteQueryBuilder target) { - target = taint(); - String typeDiscriminatorColumn = taint(); - String[] unionColumns = taint(); - Set columnsPresentInTable = taint(); + target = taint(); // $taintReachesReturn + String typeDiscriminatorColumn = taint(); // $taintReachesReturn + String[] unionColumns = {taint()}; // $ MISSING: taintReachesReturn + Set columnsPresentInTable = taint(); // $taintReachesReturn int computedColumnsOffset = taint(); - String typeDiscriminatorValue = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); + String typeDiscriminatorValue = taint(); // $taintReachesReturn + String selection = taint(); // $taintReachesReturn + String[] selectionArgs = {taint()}; // $ MISSING: taintReachesReturn + String groupBy = taint(); // $taintReachesReturn + String having = taint(); // $taintReachesReturn return target.buildUnionSubQuery(typeDiscriminatorColumn, unionColumns, columnsPresentInTable, computedColumnsOffset, typeDiscriminatorValue, selection, selectionArgs, groupBy, having); } - public static void buildUnionSubQuery3(MySQLiteQueryBuilder target) { - target = taint(); - String typeDiscriminatorColumn = taint(); - String[] unionColumns = taint(); - Set columnsPresentInTable = taint(); + public static String buildUnionSubQuery3(MySQLiteQueryBuilder target) { + target = taint(); // $taintReachesReturn + String typeDiscriminatorColumn = taint(); // $taintReachesReturn + String[] unionColumns = {taint()}; // $ MISSING: taintReachesReturn + Set columnsPresentInTable = taint(); // $taintReachesReturn int computedColumnsOffset = taint(); - String typeDiscriminatorValue = taint(); - String selection = taint(); - String groupBy = taint(); - String having = taint(); - target.buildUnionSubQuery(typeDiscriminatorColumn, unionColumns, columnsPresentInTable, computedColumnsOffset, + String typeDiscriminatorValue = taint(); // $taintReachesReturn + String selection = taint(); // $taintReachesReturn + String groupBy = taint(); // $taintReachesReturn + String having = taint(); // $taintReachesReturn + return target.buildUnionSubQuery(typeDiscriminatorColumn, unionColumns, columnsPresentInTable, computedColumnsOffset, typeDiscriminatorValue, selection, groupBy, having); } public static Cursor query(MyContentResolver target) { - Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + Uri uri = taint(); // $taintReachesReturn + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); CancellationSignal cancellationSignal = taint(); return target.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); } public static Cursor query(MyContentProvider target) { - Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + Uri uri = taint(); // $taintReachesReturn + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); CancellationSignal cancellationSignal = taint(); return target.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); } public static Cursor query2(MyContentResolver target) { - Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + Uri uri = taint(); // $taintReachesReturn + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); return target.query(uri, projection, selection, selectionArgs, sortOrder); } public static Cursor query2(MyContentProvider target) { - Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + Uri uri = taint(); // $taintReachesReturn + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); return target.query(uri, projection, selection, selectionArgs, sortOrder); } - public static void appendColumns() { - StringBuilder s = taint(); - String[] columns = taint(); + public static StringBuilder appendColumns() { + StringBuilder s = taint(); // $taintReachesReturn + String[] columns = {taint()}; // $ MISSING: taintReachesReturn SQLiteQueryBuilder.appendColumns(s, columns); + return s; } - public static void setProjectionMap(MySQLiteQueryBuilder target) { - target = taint(); - Map columnMap = taint(); + public static SQLiteQueryBuilder setProjectionMap(MySQLiteQueryBuilder target) { + target = taint(); // $taintReachesReturn + Map columnMap = taint(); // $taintReachesReturn target.setProjectionMap(columnMap); + return target; } - public static void setTables(MySQLiteQueryBuilder target) { - target = taint(); - String inTables = taint(); + public static SQLiteQueryBuilder setTables(MySQLiteQueryBuilder target) { + target = taint(); // $taintReachesReturn + String inTables = taint(); // $taintReachesReturn target.setTables(inTables); + return target; } - public static void appendWhere(MySQLiteQueryBuilder target) { - target = taint(); - CharSequence inWhere = taint(); + public static SQLiteQueryBuilder appendWhere(MySQLiteQueryBuilder target) { + target = taint(); // $taintReachesReturn + CharSequence inWhere = taint(); // $taintReachesReturn target.appendWhere(inWhere); + return target; } - public static void appendWhereStandalone(MySQLiteQueryBuilder target) { - target = taint(); - CharSequence inWhere = taint(); + public static SQLiteQueryBuilder appendWhereStandalone(MySQLiteQueryBuilder target) { + target = taint(); // $taintReachesReturn + CharSequence inWhere = taint(); // $taintReachesReturn target.appendWhereStandalone(inWhere); + return target; } } diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/Sinks.java b/java/ql/test/library-tests/frameworks/android/taint-database/Sinks.java index 5cf8426e2a0..d236368e089 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/Sinks.java +++ b/java/ql/test/library-tests/frameworks/android/taint-database/Sinks.java @@ -25,58 +25,58 @@ public class Sinks { } public static void compileStatement(SQLiteDatabase target) { - String sql = taint(); + String sql = taint(); // $taintReachesSink target.compileStatement(sql); } public static void delete1(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.delete(db, selection, selectionArgs); } public static void delete(SQLiteDatabase target) { - String table = taint(); - String whereClause = taint(); - String[] whereArgs = taint(); + String table = taint(); // $taintReachesSink + String whereClause = taint(); // $taintReachesSink + String[] whereArgs = {taint()}; target.delete(table, whereClause, whereArgs); } public static void delete(MyContentResolver target) { Uri uri = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.delete(uri, selection, selectionArgs); } public static void delete(MyContentProvider target) { Uri uri = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.delete(uri, selection, selectionArgs); } public static void execPerConnectionSQL(SQLiteDatabase target) { - String sql = taint(); - Object[] bindArgs = taint(); + String sql = taint(); // $taintReachesSink + Object[] bindArgs = {taint()}; target.execPerConnectionSQL(sql, bindArgs); } public static void execSQL(SQLiteDatabase target) { - String sql = taint(); + String sql = taint(); // $taintReachesSink target.execSQL(sql); } public static void execSQL2(SQLiteDatabase target) { - String sql = taint(); - Object[] bindArgs = taint(); + String sql = taint(); // $taintReachesSink + Object[] bindArgs = {taint()}; target.execSQL(sql, bindArgs); } public static void insert(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); ContentValues values = taint(); target.insert(db, values); @@ -84,108 +84,108 @@ public class Sinks { public static void query(SQLiteDatabase target) { boolean distinct = taint(); - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink target.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); } public static void query2(SQLiteDatabase target) { boolean distinct = taint(); - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink CancellationSignal cancellationSignal = taint(); target.query(distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, cancellationSignal); } public static void query3(SQLiteDatabase target) { - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink target.query(table, columns, selection, selectionArgs, groupBy, having, orderBy); } public static void query4(SQLiteDatabase target) { - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink target.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); } public static void query(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); - String[] projectionIn = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String sortOrder = taint(); + String[] projectionIn = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String sortOrder = taint(); // $taintReachesSink target.query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder); } public static void query2(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); - String[] projectionIn = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String sortOrder = taint(); - String limit = taint(); + String[] projectionIn = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String sortOrder = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink target.query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder, limit); } public static void query3(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); - String[] projectionIn = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String sortOrder = taint(); - String limit = taint(); + String[] projectionIn = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String sortOrder = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink CancellationSignal cancellationSignal = taint(); target.query(db, projectionIn, selection, selectionArgs, groupBy, having, sortOrder, limit, cancellationSignal); } public static void query3(MyContentProvider target) { Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); target.query(uri, projection, selection, selectionArgs, sortOrder); } public static void query(MyContentProvider target) { Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); CancellationSignal cancellationSignal = taint(); target.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); @@ -193,18 +193,18 @@ public class Sinks { public static void query3(MyContentResolver target) { Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); target.query(uri, projection, selection, selectionArgs, sortOrder); } public static void query(MyContentResolver target) { Uri uri = taint(); - String[] projection = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String[] projection = {taint()}; + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String sortOrder = taint(); CancellationSignal cancellationSignal = taint(); target.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal); @@ -213,14 +213,14 @@ public class Sinks { public static void queryWithFactory(SQLiteDatabase target) { SQLiteDatabase.CursorFactory cursorFactory = taint(); boolean distinct = taint(); - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink target.queryWithFactory(cursorFactory, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit); } @@ -228,103 +228,103 @@ public class Sinks { public static void queryWithFactory2(SQLiteDatabase target) { SQLiteDatabase.CursorFactory cursorFactory = taint(); boolean distinct = taint(); - String table = taint(); - String[] columns = taint(); - String selection = taint(); - String[] selectionArgs = taint(); - String groupBy = taint(); - String having = taint(); - String orderBy = taint(); - String limit = taint(); + String table = taint(); // $taintReachesSink + String[] columns = {taint()}; // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; + String groupBy = taint(); // $taintReachesSink + String having = taint(); // $taintReachesSink + String orderBy = taint(); // $taintReachesSink + String limit = taint(); // $taintReachesSink CancellationSignal cancellationSignal = taint(); target.queryWithFactory(cursorFactory, distinct, table, columns, selection, selectionArgs, groupBy, having, orderBy, limit, cancellationSignal); } public static void rawQuery(SQLiteDatabase target) { - String sql = taint(); - String[] selectionArgs = taint(); + String sql = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.rawQuery(sql, selectionArgs); } public static void rawQuery2(SQLiteDatabase target) { - String sql = taint(); - String[] selectionArgs = taint(); + String sql = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; CancellationSignal cancellationSignal = taint(); target.rawQuery(sql, selectionArgs, cancellationSignal); } public static void rawQueryWithFactory(SQLiteDatabase target) { SQLiteDatabase.CursorFactory cursorFactory = taint(); - String sql = taint(); - String[] selectionArgs = taint(); + String sql = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String editTable = taint(); target.rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable); } public static void rawQueryWithFactory2(SQLiteDatabase target) { SQLiteDatabase.CursorFactory cursorFactory = taint(); - String sql = taint(); - String[] selectionArgs = taint(); + String sql = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; String editTable = taint(); CancellationSignal cancellationSignal = taint(); target.rawQueryWithFactory(cursorFactory, sql, selectionArgs, editTable, cancellationSignal); } public static void update(MySQLiteQueryBuilder target) { - target = taint();; + target = taint(); // $taintReachesSink SQLiteDatabase db = taint(); ContentValues values = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.update(db, values, selection, selectionArgs); } public static void update(SQLiteDatabase target) { - String table = taint(); + String table = taint(); // $taintReachesSink ContentValues values = taint(); - String whereClause = taint(); - String[] whereArgs = taint(); + String whereClause = taint(); // $taintReachesSink + String[] whereArgs = {taint()}; target.update(table, values, whereClause, whereArgs); } public static void update(MyContentResolver target) { Uri uri = taint(); ContentValues values = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.update(uri, values, selection, selectionArgs); } public static void update(MyContentProvider target) { Uri uri = taint(); ContentValues values = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; target.update(uri, values, selection, selectionArgs); } public static void updateWithOnConflict(SQLiteDatabase target) { - String table = taint(); + String table = taint(); // $taintReachesSink ContentValues values = taint(); - String whereClause = taint(); - String[] whereArgs = taint(); + String whereClause = taint(); // $taintReachesSink + String[] whereArgs = {taint()}; int conflictAlgorithm = taint(); target.updateWithOnConflict(table, values, whereClause, whereArgs, conflictAlgorithm); } public static void queryNumEntries() { SQLiteDatabase db = taint(); - String table = taint(); - String selection = taint(); + String table = taint(); // $taintReachesSink + String selection = taint(); // $taintReachesSink DatabaseUtils.queryNumEntries(db, table, selection); } public static void queryNumEntries2() { SQLiteDatabase db = taint(); - String table = taint(); - String selection = taint(); - String[] selectionArgs = taint(); + String table = taint(); // $taintReachesSink + String selection = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; DatabaseUtils.queryNumEntries(db, table, selection, selectionArgs); } @@ -332,28 +332,28 @@ public class Sinks { Context context = taint(); String dbName = taint(); int dbVersion = taint(); - String sqlStatements = taint(); + String sqlStatements = taint(); // $taintReachesSink DatabaseUtils.createDbFromSqlStatements(context, dbName, dbVersion, sqlStatements); } public static void blobFileDescriptorForQuery() { SQLiteDatabase db = taint(); - String query = taint(); - String[] selectionArgs = taint(); + String query = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; DatabaseUtils.blobFileDescriptorForQuery(db, query, selectionArgs); } public static void longForQuery() { SQLiteDatabase db = taint(); - String query = taint(); - String[] selectionArgs = taint(); + String query = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; DatabaseUtils.longForQuery(db, query, selectionArgs); } public static void stringForQuery() { SQLiteDatabase db = taint(); - String query = taint(); - String[] selectionArgs = taint(); + String query = taint(); // $taintReachesSink + String[] selectionArgs = {taint()}; DatabaseUtils.stringForQuery(db, query, selectionArgs); } } diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected index fd4565cea71..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected +++ b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.expected @@ -1,56 +0,0 @@ -| FlowSteps.java:32:44:32:57 | originalValues | FlowSteps.java:32:10:32:69 | appendSelectionArgs(...) | -| FlowSteps.java:32:60:32:68 | newValues | FlowSteps.java:32:10:32:69 | appendSelectionArgs(...) | -| FlowSteps.java:38:41:38:41 | a | FlowSteps.java:38:10:38:45 | concatenateWhere(...) | -| FlowSteps.java:38:44:38:44 | b | FlowSteps.java:38:10:38:45 | concatenateWhere(...) | -| FlowSteps.java:51:56:51:61 | tables | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:64:51:70 | columns | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:73:51:77 | where | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:80:51:86 | groupBy | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:89:51:94 | having | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:97:51:103 | orderBy | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:51:106:51:110 | limit | FlowSteps.java:51:10:51:111 | buildQueryString(...) | -| FlowSteps.java:62:10:62:15 | target | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:28:62:39 | projectionIn | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:42:62:50 | selection | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:53:62:59 | groupBy | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:62:62:67 | having | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:70:62:78 | sortOrder | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:62:81:62:85 | limit | FlowSteps.java:62:10:62:86 | buildQuery(...) | -| FlowSteps.java:74:10:74:15 | target | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:28:74:39 | projectionIn | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:42:74:50 | selection | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:53:74:65 | selectionArgs | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:68:74:74 | groupBy | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:77:74:82 | having | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:85:74:93 | sortOrder | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:74:96:74:100 | limit | FlowSteps.java:74:10:74:101 | buildQuery(...) | -| FlowSteps.java:82:10:82:15 | target | FlowSteps.java:82:10:82:61 | buildUnionQuery(...) | -| FlowSteps.java:82:33:82:42 | subQueries | FlowSteps.java:82:10:82:61 | buildUnionQuery(...) | -| FlowSteps.java:82:45:82:53 | sortOrder | FlowSteps.java:82:10:82:61 | buildUnionQuery(...) | -| FlowSteps.java:82:56:82:60 | limit | FlowSteps.java:82:10:82:61 | buildUnionQuery(...) | -| FlowSteps.java:96:10:96:15 | target | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:96:36:96:58 | typeDiscriminatorColumn | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:96:61:96:72 | unionColumns | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:96:75:96:95 | columnsPresentInTable | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:97:28:97:49 | typeDiscriminatorValue | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:97:52:97:60 | selection | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:97:63:97:75 | selectionArgs | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:97:78:97:84 | groupBy | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:97:87:97:92 | having | FlowSteps.java:96:10:97:93 | buildUnionSubQuery(...) | -| FlowSteps.java:110:3:110:8 | target | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:110:29:110:51 | typeDiscriminatorColumn | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:110:54:110:65 | unionColumns | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:110:68:110:88 | columnsPresentInTable | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:111:5:111:26 | typeDiscriminatorValue | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:111:29:111:37 | selection | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:111:40:111:46 | groupBy | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:111:49:111:54 | having | FlowSteps.java:110:3:111:55 | buildUnionSubQuery(...) | -| FlowSteps.java:121:23:121:25 | uri | FlowSteps.java:121:10:121:95 | query(...) | -| FlowSteps.java:131:23:131:25 | uri | FlowSteps.java:131:10:131:95 | query(...) | -| FlowSteps.java:140:23:140:25 | uri | FlowSteps.java:140:10:140:75 | query(...) | -| FlowSteps.java:149:23:149:25 | uri | FlowSteps.java:149:10:149:75 | query(...) | -| FlowSteps.java:155:39:155:45 | columns | FlowSteps.java:155:36:155:36 | s [post update] | -| FlowSteps.java:161:27:161:35 | columnMap | FlowSteps.java:161:3:161:8 | target [post update] | -| FlowSteps.java:167:20:167:27 | inTables | FlowSteps.java:167:3:167:8 | target [post update] | -| FlowSteps.java:173:22:173:28 | inWhere | FlowSteps.java:173:3:173:8 | target [post update] | -| FlowSteps.java:179:32:179:38 | inWhere | FlowSteps.java:179:3:179:8 | target [post update] | diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.ql b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.ql index 32fde9c66c0..fda36e5ff75 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.ql +++ b/java/ql/test/library-tests/frameworks/android/taint-database/flowSteps.ql @@ -2,21 +2,30 @@ import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection +import TestUtilities.InlineExpectationsTest class Conf extends TaintTracking::Configuration { Conf() { this = "qltest:dataflow:android::flow" } override predicate isSource(DataFlow::Node source) { - exists(VarAccess va, MethodAccess ma | - source.asExpr() = va and - va.getVariable().getAnAssignedValue() = ma and - ma.getMethod().hasName("taint") - ) + source.asExpr().(MethodAccess).getMethod().hasName("taint") } - override predicate isSink(DataFlow::Node sink) { not isSource(sink) } + override predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(ReturnStmt r).getResult() } } -from DataFlow::Node source, DataFlow::Node sink, Conf config -where config.hasFlow(source, sink) and sink.getLocation().getFile().getBaseName() = "FlowSteps.java" -select source, sink +class FlowStepTest extends InlineExpectationsTest { + FlowStepTest() { this = "FlowStepTest" } + + override string getARelevantTag() { result = "taintReachesReturn" } + + override predicate hasActualResult(Location l, string element, string tag, string value) { + tag = "taintReachesReturn" and + value = "" and + exists(Conf conf, DataFlow::Node source, DataFlow::Node sink | + conf.hasFlow(source, sink) and + l = source.getLocation() and + element = source.toString() + ) + } +} diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected index 7c0bdc30dc8..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected +++ b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.expected @@ -1,88 +0,0 @@ -| Sinks.java:29:27:29:29 | sql | -| Sinks.java:37:3:37:8 | target | -| Sinks.java:37:21:37:29 | selection | -| Sinks.java:44:24:44:34 | whereClause | -| Sinks.java:51:22:51:30 | selection | -| Sinks.java:58:22:58:30 | selection | -| Sinks.java:64:31:64:33 | sql | -| Sinks.java:69:18:69:20 | sql | -| Sinks.java:75:18:75:20 | sql | -| Sinks.java:82:3:82:8 | target | -| Sinks.java:95:26:95:30 | table | -| Sinks.java:95:33:95:39 | columns | -| Sinks.java:95:42:95:50 | selection | -| Sinks.java:95:68:95:74 | groupBy | -| Sinks.java:95:77:95:82 | having | -| Sinks.java:95:85:95:91 | orderBy | -| Sinks.java:95:94:95:98 | limit | -| Sinks.java:109:26:109:30 | table | -| Sinks.java:109:33:109:39 | columns | -| Sinks.java:109:42:109:50 | selection | -| Sinks.java:109:68:109:74 | groupBy | -| Sinks.java:109:77:109:82 | having | -| Sinks.java:109:85:109:91 | orderBy | -| Sinks.java:109:94:109:98 | limit | -| Sinks.java:121:16:121:20 | table | -| Sinks.java:121:23:121:29 | columns | -| Sinks.java:121:32:121:40 | selection | -| Sinks.java:121:58:121:64 | groupBy | -| Sinks.java:121:67:121:72 | having | -| Sinks.java:121:75:121:81 | orderBy | -| Sinks.java:133:16:133:20 | table | -| Sinks.java:133:23:133:29 | columns | -| Sinks.java:133:32:133:40 | selection | -| Sinks.java:133:58:133:64 | groupBy | -| Sinks.java:133:67:133:72 | having | -| Sinks.java:133:75:133:81 | orderBy | -| Sinks.java:133:84:133:88 | limit | -| Sinks.java:145:3:145:8 | target | -| Sinks.java:145:34:145:42 | selection | -| Sinks.java:145:60:145:66 | groupBy | -| Sinks.java:145:69:145:74 | having | -| Sinks.java:145:77:145:85 | sortOrder | -| Sinks.java:158:3:158:8 | target | -| Sinks.java:158:34:158:42 | selection | -| Sinks.java:158:60:158:66 | groupBy | -| Sinks.java:158:69:158:74 | having | -| Sinks.java:158:77:158:85 | sortOrder | -| Sinks.java:158:88:158:92 | limit | -| Sinks.java:172:3:172:8 | target | -| Sinks.java:172:34:172:42 | selection | -| Sinks.java:172:60:172:66 | groupBy | -| Sinks.java:172:69:172:74 | having | -| Sinks.java:172:77:172:85 | sortOrder | -| Sinks.java:172:88:172:92 | limit | -| Sinks.java:181:33:181:41 | selection | -| Sinks.java:191:33:191:41 | selection | -| Sinks.java:200:33:200:41 | selection | -| Sinks.java:210:33:210:41 | selection | -| Sinks.java:224:52:224:56 | table | -| Sinks.java:224:59:224:65 | columns | -| Sinks.java:224:68:224:76 | selection | -| Sinks.java:224:94:224:100 | groupBy | -| Sinks.java:224:103:224:108 | having | -| Sinks.java:225:5:225:11 | orderBy | -| Sinks.java:225:14:225:18 | limit | -| Sinks.java:240:52:240:56 | table | -| Sinks.java:240:59:240:65 | columns | -| Sinks.java:240:68:240:76 | selection | -| Sinks.java:240:94:240:100 | groupBy | -| Sinks.java:240:103:240:108 | having | -| Sinks.java:241:5:241:11 | orderBy | -| Sinks.java:241:14:241:18 | limit | -| Sinks.java:247:19:247:21 | sql | -| Sinks.java:254:19:254:21 | sql | -| Sinks.java:262:45:262:47 | sql | -| Sinks.java:271:45:271:47 | sql | -| Sinks.java:280:3:280:8 | target | -| Sinks.java:280:29:280:37 | selection | -| Sinks.java:288:32:288:42 | whereClause | -| Sinks.java:296:30:296:38 | selection | -| Sinks.java:304:30:304:38 | selection | -| Sinks.java:313:46:313:56 | whereClause | -| Sinks.java:320:44:320:52 | selection | -| Sinks.java:328:44:328:52 | selection | -| Sinks.java:336:71:336:83 | sqlStatements | -| Sinks.java:343:48:343:52 | query | -| Sinks.java:350:34:350:38 | query | -| Sinks.java:357:36:357:40 | query | diff --git a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.ql b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.ql index d898b4f073d..c6cb03dcd7b 100644 --- a/java/ql/test/library-tests/frameworks/android/taint-database/sinks.ql +++ b/java/ql/test/library-tests/frameworks/android/taint-database/sinks.ql @@ -1,5 +1,31 @@ +import semmle.code.java.dataflow.DataFlow +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.QueryInjection +import TestUtilities.InlineExpectationsTest -from QueryInjectionSink sink -where sink.getLocation().getFile().getBaseName() = "Sinks.java" -select sink +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest:dataflow:android::flow" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr().(MethodAccess).getMethod().hasName("taint") + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof QueryInjectionSink } +} + +class SinkTest extends InlineExpectationsTest { + SinkTest() { this = "SinkTest" } + + override string getARelevantTag() { result = "taintReachesSink" } + + override predicate hasActualResult(Location l, string element, string tag, string value) { + tag = "taintReachesSink" and + value = "" and + exists(Conf conf, DataFlow::Node source, DataFlow::Node sink | + conf.hasFlow(source, sink) and + l = source.getLocation() and + element = source.toString() + ) + } +}