Page MenuHomePhabricator

Correctly process argument links when backpropagating EXEC taintedness
Open, Needs TriagePublic

Description

In backpropagateArgTaint we have:

$phanObjs = $this->getPhanObjsForNode( $argument, [ 'return' ] );
$this->doBackpropArgTaint( $phanObjs, $taint, $func );

which means that if the EXEC'ed expression is (or contains) a function call, it will not pick up the taintedness links of the arguments. This is not correct for functions that essentially pass their arguments through, e.g. most PHP internal functions. In fact, the following example:

function foobar() {
	renderTile( $_GET['x'] );
}

function renderTile( string $data ) {
	echo strtolower( $data );
}

will not warn (whereas it would if you remove the strtolower call).

Fixing this is not trivial given the current state of things, however it would fit very well with the changes starting from https://gerrit.wikimedia.org/r/c/mediawiki/tools/phan/SecurityCheckPlugin/+/663194, and in general with the work towards T269903.

Event Timeline

To expand a bit on this, the TODO in backpropagateArgTaint already explains this problem:

	 * @todo This has false negatives, because we don't collect function arguments in
	 * getPhanObjsForNode (we'd have to pass option 'all'), so we can't handle e.g. array_merge
	 * right now. However, collecting all args would create false positives with functions where
	 * the arg taint isn't propagated to the return value. Ideally, we'd want to include an argument
	 * iff the corresponding parameter passes $taint through.

The chain of patches linked above changes the taintedness links to be collected along the way, while visiting nodes in their order (as opposed to digging them again later). For function calls, this means that we can decide which links to add based on the taintedness of the current argument, somewhat similar to what r661819 does for caused-by lines.

Note (mostly to self): this can be easily resolved once r681443 is merged. In fact, that patch would already make this work if the function call happens outside of the echo, i.e. this would warn:

function foobar() {
	renderTile( $_GET['x'] );
}

function renderTile( string $data ) {
	$y = strtolower( $data );
	echo $y;
}

the case without intermediate variables can be addressed by handling AST_*CALL nodes in TaintednessBackpropVisitor similar to getArgTaint.

the case without intermediate variables can be addressed by handling AST_*CALL nodes in TaintednessBackpropVisitor similar to getArgTaint.

Or even better, avoiding TaintednessBackpropVisitor and just use the normal visitor to get the links (T281478). So this task is essentially the same as the subtask, modulo r681443 which should happen first.

Change 681443 had a related patch set uploaded (by Daimona Eaytoy; author: Daimona Eaytoy):

[mediawiki/tools/phan/SecurityCheckPlugin@master] [WIP] Return overhaul 3: pass links through function calls

https://gerrit.wikimedia.org/r/681443