Add taint-check annotations to database methods
These were copied verbatim from MediaWikiSecurityCheckPlugin.php. The exception is selectRowCount(), whose return value was hardcoded as tainted in taint-check, but that's clearly not the case because it returns just an integer. Suppress a new issue in DbTestPreviewer that wasn't previously spotted because the code ends up using IReadableDatabase::selectRow, but the hardcoded data in taint-check only considers IDatabase and concrete classes, not IReadableDatabase. Bug: T321806 Change-Id: I0c59d286c50de4ea79571242649bdda8aec67b57
This commit is contained in:
parent
ebb742d04f
commit
d31d5bfa92
6 changed files with 72 additions and 2 deletions
|
|
@ -11,7 +11,9 @@ interface DbQuoter {
|
|||
* Escape and quote a raw value string for use in a SQL query
|
||||
*
|
||||
* @param string|int|float|null|bool|Blob $s
|
||||
* @param-taint $s escapes_sql
|
||||
* @return string
|
||||
* @return-taint none
|
||||
*/
|
||||
public function addQuotes( $s );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,10 +273,12 @@ interface IDatabase extends IReadableDatabase {
|
|||
* Methods like startAtomic(), endAtomic(), and cancelAtomic() can be used instead.
|
||||
*
|
||||
* @param string|Query $sql Single-statement SQL query
|
||||
* @param-taint $sql exec_sql
|
||||
* @param string $fname Caller name; used for profiling/SHOW PROCESSLIST comments
|
||||
* @param int $flags Bit field of IDatabase::QUERY_* constants.
|
||||
* @return bool|IResultWrapper True for a successful write query, IResultWrapper object
|
||||
* for a successful read query, or false on failure if QUERY_SILENCE_ERRORS is set.
|
||||
* @return-taint tainted
|
||||
* @throws DBQueryError If the query is issued, fails, and QUERY_SILENCE_ERRORS is not set.
|
||||
* @throws DBExpectedError If the query is not, and cannot, be issued yet (non-DBQueryError)
|
||||
* @throws DBError If the query is inherently not allowed (non-DBExpectedError)
|
||||
|
|
@ -356,19 +358,24 @@ interface IDatabase extends IReadableDatabase {
|
|||
* @internal callers outside of rdbms library should use InsertQueryBuilder instead.
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param-taint $table exec_sql
|
||||
* @param array|array[] $rows Row(s) to insert, as either:
|
||||
* - A string-keyed map of (column name => value) defining a new row. Values are
|
||||
* treated as literals and quoted appropriately; null is interpreted as NULL.
|
||||
* - An integer-keyed list of such string-keyed maps, defining a list of new rows.
|
||||
* The keys in each map must be identical to each other and in the same order.
|
||||
* The rows must not collide with each other.
|
||||
* @param-taint $rows exec_sql_numkey - NOTE: This does not work when inserting multiple rows (T290563)
|
||||
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options Combination map/list where each string-keyed entry maps
|
||||
* a non-boolean option to the option parameters and each integer-keyed value is the
|
||||
* name of a boolean option. Supported options are:
|
||||
* - IGNORE: Boolean: skip insertion of rows that would cause unique key conflicts.
|
||||
* IDatabase::affectedRows() can be used to determine how many rows were inserted.
|
||||
* @param-taint $options exec_sql
|
||||
* @return bool Return true if no exception was thrown (deprecated since 1.33)
|
||||
* @return-taint none
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function insert( $table, $rows, $fname = __METHOD__, $options = [] );
|
||||
|
|
@ -382,6 +389,7 @@ interface IDatabase extends IReadableDatabase {
|
|||
* @internal callers outside of rdbms library should use UpdateQueryBuilder instead.
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param-taint $table exec_sql
|
||||
* @param array $set Combination map/list where each string-keyed entry maps a column
|
||||
* to a literal assigned value and each integer-keyed value is a SQL expression in the
|
||||
* format of a column assignment within UPDATE...SET. The (column => value) entries are
|
||||
|
|
@ -389,17 +397,22 @@ interface IDatabase extends IReadableDatabase {
|
|||
* assignment format is useful for updates like "column = column + X". All assignments
|
||||
* have no defined execution order, so they should not depend on each other. Do not
|
||||
* modify AUTOINCREMENT or UUID columns in assignments.
|
||||
* @param-taint $set exec_sql_numkey
|
||||
* @param array|string $conds Condition in the format of IDatabase::select() conditions.
|
||||
* In order to prevent possible performance or replication issues or damaging a data
|
||||
* accidentally, an empty condition for 'update' queries isn't allowed.
|
||||
* IDatabase::ALL_ROWS should be passed explicitly in order to update all rows.
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
* @param string $fname Calling function name (use __METHOD__) for logs/profiling
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options Combination map/list where each string-keyed entry maps
|
||||
* a non-boolean option to the option parameters and each integer-keyed value is the
|
||||
* name of a boolean option. Supported options are:
|
||||
* - IGNORE: Boolean: skip update of rows that would cause unique key conflicts.
|
||||
* IDatabase::affectedRows() can be used to determine how many rows were updated.
|
||||
* @param-taint $options none
|
||||
* @return bool Return true if no exception was thrown (deprecated since 1.33)
|
||||
* @return-taint none
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function update( $table, $set, $conds, $fname = __METHOD__, $options = [] );
|
||||
|
|
@ -542,12 +555,16 @@ interface IDatabase extends IReadableDatabase {
|
|||
* @internal callers outside of rdbms library should use DeleteQueryBuilder instead.
|
||||
*
|
||||
* @param string $table Table name
|
||||
* @param-taint $table exec_sql
|
||||
* @param string|array $conds Array of conditions. See $conds in IDatabase::select()
|
||||
* In order to prevent possible performance or replication issues or damaging a data
|
||||
* accidentally, an empty condition for 'delete' queries isn't allowed.
|
||||
* IDatabase::ALL_ROWS should be passed explicitly in order to delete all rows.
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
* @param string $fname Name of the calling function
|
||||
* @param-taint $fname exec_sql
|
||||
* @return bool Return true if no exception was thrown (deprecated since 1.33)
|
||||
* @return-taint none
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function delete( $table, $conds, $fname = __METHOD__ );
|
||||
|
|
|
|||
|
|
@ -164,14 +164,21 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* @internal callers outside of rdbms library should use SelectQueryBuilder instead.
|
||||
*
|
||||
* @param string|array $table Table name. {@see select} for details.
|
||||
* @param-taint $table exec_sql
|
||||
* @param string|array $var The field name to select. This must be a valid SQL fragment: do not
|
||||
* use unvalidated user input. Can be an array, but must contain exactly 1 element then.
|
||||
* {@see select} for details.
|
||||
* @param-taint $var exec_sql
|
||||
* @param string|array $cond The condition array. {@see select} for details.
|
||||
* @param-taint $cond exec_sql_numkey
|
||||
* @param string $fname The function name of the caller.
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options The query options. {@see select} for details.
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param string|array $join_conds The query join conditions. {@see select} for details.
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @return mixed|false The value from the field, or false if nothing was found
|
||||
* @return-taint tainted
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function selectField(
|
||||
|
|
@ -189,14 +196,21 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* @internal callers outside of rdbms library should use SelectQueryBuilder instead.
|
||||
*
|
||||
* @param string|array $table Table name. {@see select} for details.
|
||||
* @param-taint $table exec_sql
|
||||
* @param string $var The field name to select. This must be a valid SQL
|
||||
* fragment: do not use unvalidated user input.
|
||||
* @param-taint $var exec_sql
|
||||
* @param string|array $cond The condition array. {@see select} for details.
|
||||
* @param-taint $cond exec_sql_numkey
|
||||
* @param string $fname The function name of the caller.
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options The query options. {@see select} for details.
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param string|array $join_conds The query join conditions. {@see select} for details.
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
*
|
||||
* @return array The values from the field in the order they were returned from the DB
|
||||
* @return-taint tainted
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
* @since 1.25
|
||||
*/
|
||||
|
|
@ -211,6 +225,7 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* instead, which is more readable and less error-prone.
|
||||
*
|
||||
* @param string|array $table Table name(s)
|
||||
* @param-taint $table exec_sql
|
||||
*
|
||||
* May be either an array of table names, or a single string holding a table
|
||||
* name. If an array is given, table aliases can be specified, for example:
|
||||
|
|
@ -246,6 +261,7 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* not have characters outside of the Basic multilingual plane.
|
||||
*
|
||||
* @param string|array $vars Field name(s)
|
||||
* @param-taint $vars exec_sql
|
||||
*
|
||||
* May be either a field name or an array of field names. The field names
|
||||
* can be complete fragments of SQL, for direct inclusion into the SELECT
|
||||
|
|
@ -261,6 +277,7 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* Untrusted user input must not be passed to this parameter.
|
||||
*
|
||||
* @param string|array $conds
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
*
|
||||
* May be either a string containing a single condition, or an array of
|
||||
* conditions. If an array is given, the conditions constructed from each
|
||||
|
|
@ -304,8 +321,10 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* 'actor' => [ 'JOIN', 'rev_actor = actor_id' ],
|
||||
*
|
||||
* @param string $fname Caller function name
|
||||
* @param-taint $fname exec_sql
|
||||
*
|
||||
* @param string|array $options Query options
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
*
|
||||
* Optional: Array of query options. Boolean options are specified by
|
||||
* including them in the array as a string value with a numeric key, for
|
||||
|
|
@ -371,6 +390,7 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* - SQL_CALC_FOUND_ROWS
|
||||
*
|
||||
* @param string|array $join_conds Join conditions
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
*
|
||||
* Optional associative array of table-specific join conditions.
|
||||
* Simple conditions can also be specified in the regular $conds,
|
||||
|
|
@ -386,6 +406,7 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
*
|
||||
* @internal
|
||||
* @return IResultWrapper Resulting rows
|
||||
* @return-taint tainted
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function select(
|
||||
|
|
@ -409,12 +430,19 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
*
|
||||
* @internal
|
||||
* @param string|array $table Table name
|
||||
* @param-taint $table exec_sql
|
||||
* @param string|array $vars Field names
|
||||
* @param-taint $vars exec_sql
|
||||
* @param string|array $conds Conditions
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
* @param string $fname Caller function name
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options Query options
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param array|string $join_conds Join conditions
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @return stdClass|false
|
||||
* @return-taint tainted
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function selectRow(
|
||||
|
|
@ -470,12 +498,19 @@ interface IReadableDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
*
|
||||
* @internal
|
||||
* @param string|string[] $tables Table name(s)
|
||||
* @param-taint $tables exec_sql
|
||||
* @param string $var Column for which NULL values are not counted [default "*"]
|
||||
* @param-taint $var exec_sql
|
||||
* @param array|string $conds Filters on the table
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
* @param string $fname Function name for profiling
|
||||
* @param-taint $fname exec_sql
|
||||
* @param array $options Options for select
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param array $join_conds Join conditions (since 1.27)
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @return int Row count
|
||||
* @return-taint none
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
*/
|
||||
public function selectRowCount(
|
||||
|
|
|
|||
|
|
@ -95,7 +95,9 @@ interface ISQLPlatform {
|
|||
* Depending on the database this will either be `backticks` or "double quotes"
|
||||
*
|
||||
* @param string $s
|
||||
* @param-taint $s escapes_sql NOTE: this is subpar, as addIdentifierQuotes isn't always the right type of escaping.
|
||||
* @return string
|
||||
* @return-taint none
|
||||
* @since 1.33
|
||||
*/
|
||||
public function addIdentifierQuotes( $s );
|
||||
|
|
@ -176,14 +178,17 @@ interface ISQLPlatform {
|
|||
* This would set $sql to "rev_page = '$id' AND (rev_minor = 1 OR rev_len < 500)"
|
||||
*
|
||||
* @param array $a Containing the data
|
||||
* @param-taint $a escapes_sql - Note, this is also special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param int $mode IDatabase class constant:
|
||||
* - IDatabase::LIST_COMMA: Comma separated, no field names
|
||||
* - IDatabase::LIST_AND: ANDed WHERE clause (without the WHERE).
|
||||
* - IDatabase::LIST_OR: ORed WHERE clause (without the WHERE)
|
||||
* - IDatabase::LIST_SET: Comma separated with field names, like a SET clause
|
||||
* - IDatabase::LIST_NAMES: Comma separated field names
|
||||
* @param-taint $mode none
|
||||
* @throws DBError If an error occurs, {@see IDatabase::query}
|
||||
* @return string
|
||||
* @return-taint none
|
||||
*/
|
||||
public function makeList( array $a, $mode = self::LIST_COMMA );
|
||||
|
||||
|
|
@ -292,8 +297,11 @@ interface ISQLPlatform {
|
|||
*
|
||||
* @since 1.16 in IDatabase, moved to ISQLPlatform in 1.39
|
||||
* @param array[]|string|LikeMatch $param
|
||||
* @param-taint $param escapes_sql
|
||||
* @param string|LikeMatch ...$params
|
||||
* @param-taint ...$params escapes_sql
|
||||
* @return string Fully built LIKE statement
|
||||
* @return-taint none
|
||||
*/
|
||||
public function buildLike( $param, ...$params );
|
||||
|
||||
|
|
@ -493,12 +501,19 @@ interface ISQLPlatform {
|
|||
* @see IDatabase::select()
|
||||
*
|
||||
* @param string|array $table Table name(s)
|
||||
* @param-taint $table exec_sql
|
||||
* @param string|array $vars Field names
|
||||
* @param-taint $vars exec_sql
|
||||
* @param string|array $conds Conditions
|
||||
* @param-taint $conds exec_sql_numkey
|
||||
* @param string $fname Caller function name
|
||||
* @param-taint $fname exec_sql
|
||||
* @param string|array $options Query options
|
||||
* @param-taint $options none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @param string|array $join_conds Join conditions
|
||||
* @param-taint $join_conds none This is special-cased in MediaWikiSecurityCheckPlugin
|
||||
* @return string SQL query string
|
||||
* @return-taint onlysafefor_sql
|
||||
*/
|
||||
public function selectSQLText(
|
||||
$table,
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ class DbTestPreviewer extends TestRecorder {
|
|||
printf( "\n%4d %s\n", $count, $label );
|
||||
|
||||
foreach ( $breakdown[$code] as $differing_test_name => $statusInfo ) {
|
||||
// @phan-suppress-next-line SecurityCheck-XSS CLI-only script
|
||||
print " * $differing_test_name [$statusInfo]\n";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ class TaintCheckAnnotationsTest {
|
|||
$db->selectRowCount( $_GET['a'], '' ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRowCount( '', $_GET['a'] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRowCount( '', '', [ $_GET['a'] ] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
echo $db->selectRowCount( 'safe', 'safe' ); // @phan-suppress-current-line SecurityCheck-XSS
|
||||
echo $db->selectRowCount( 'safe', 'safe' ); // Safe
|
||||
|
||||
$db->selectRow( $_GET['a'], '', [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRow( '', $_GET['a'], [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
|
|
@ -196,7 +196,7 @@ class TaintCheckAnnotationsTest {
|
|||
$db->selectRowCount( $_GET['a'], '' ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRowCount( '', $_GET['a'] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRowCount( '', '', [ $_GET['a'] ] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
echo $db->selectRowCount( 'safe', 'safe' ); // @phan-suppress-current-line SecurityCheck-XSS
|
||||
echo $db->selectRowCount( 'safe', 'safe' ); // Safe
|
||||
|
||||
$db->selectRow( $_GET['a'], '', [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
$db->selectRow( '', $_GET['a'], [] ); // @phan-suppress-current-line SecurityCheck-SQLInjection
|
||||
|
|
|
|||
Loading…
Reference in a new issue