mirror of
https://github.com/moodle/moodle.git
synced 2025-04-13 04:22:07 +02:00
MDL-62619 privacy: Prevent action when boolean queries are involved
Before the patch, queries like: SELECT 1 FROM dual UNION SELECT 2 FROM dual were failing badly, with everything but the first numeric element being ignored by the optimization. So, being conservative, now we reduce the query being analysed, ignoring any subquery, inline view (anything within parenthesis in general) and, in the remaining query, if a boolean query (UNION, MINUS, INTERSECT...) is found, we don't apply any optimization.
This commit is contained in:
parent
b76d8da4a6
commit
c9840c0144
@ -138,6 +138,12 @@ class contextlist extends contextlist_base {
|
||||
* @return string The field name or a numeric value representing the context id
|
||||
*/
|
||||
protected function guess_id_field_from_sql(string $sql) : string {
|
||||
// We are not interested in any subquery/view/conditions for the purpose of this method, so
|
||||
// let's reduce the query to the interesting parts by recursively cleaning all
|
||||
// contents within parenthesis. If there are problems (null), we keep the text unmodified.
|
||||
// So just top-level sql will remain after the reduction.
|
||||
$recursiveregexp = '/\((([^()]*|(?R))*)\)/';
|
||||
$sql = (preg_replace($recursiveregexp, '', $sql) ?: $sql);
|
||||
// Get the list of relevant words from the SQL Query.
|
||||
// We explode the SQL by the space character, then trim any extra whitespace (e.g. newlines), before we filter
|
||||
// empty value, and finally we re-index the array.
|
||||
@ -147,8 +153,15 @@ class contextlist extends contextlist_base {
|
||||
return $word !== '';
|
||||
});
|
||||
$words = array_values($words);
|
||||
$uwords = array_map('strtoupper', $words); // Uppercase all them.
|
||||
|
||||
if ($firstfrom = array_search('FROM', array_map('strtoupper', $words))) {
|
||||
// If the query has boolean operators (UNION, it is the only one we support cross-db)
|
||||
// then we cannot guarantee whats coming after the first query, it can be anything.
|
||||
if (array_search('UNION', $uwords)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($firstfrom = array_search('FROM', $uwords)) {
|
||||
// Found a FROM keyword.
|
||||
// Select the previous word.
|
||||
$fieldname = $words[$firstfrom - 1];
|
||||
|
@ -176,6 +176,27 @@ class contextlist_test extends advanced_testcase {
|
||||
'SELECT 4 FROM users',
|
||||
'4',
|
||||
],
|
||||
'select_with_complex_subqueries' => [
|
||||
'SELECT id FROM table WHERE id IN (
|
||||
SELECT x FROM xtable
|
||||
UNION
|
||||
SELECT y FROM (
|
||||
SELECT y FROM ytable
|
||||
JOIN ztable ON (z = y)))',
|
||||
'id'
|
||||
],
|
||||
'invalid_union_with_first_being_column_name' => [
|
||||
'SELECT id FROM table UNION SELECT 1 FROM table',
|
||||
''
|
||||
],
|
||||
'invalid_union_with_first_being_numeric' => [
|
||||
'SELECT 1 FROM table UNION SELECT id FROM table',
|
||||
''
|
||||
],
|
||||
'invalid_union_without_from' => [
|
||||
'SELECT 1 UNION SELECT id FROM table',
|
||||
''
|
||||
],
|
||||
'invalid_1' => [
|
||||
'SELECT 1+1',
|
||||
'',
|
||||
|
Loading…
x
Reference in New Issue
Block a user