Skip to content

Commit

Permalink
Fix phpGH-16131: Prevent mixing PDO sub-classes with different DSN
Browse files Browse the repository at this point in the history
  • Loading branch information
kocsismate committed Oct 2, 2024
1 parent 341c26f commit 47b5174
Show file tree
Hide file tree
Showing 23 changed files with 212 additions and 31 deletions.
62 changes: 41 additions & 21 deletions ext/pdo/pdo_dbh.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,45 +237,64 @@ static bool create_driver_specific_pdo_object(pdo_driver_t *driver, zend_class_e
if (ce_based_on_driver_name) {
if (instanceof_function(ce_based_on_called_object, ce_based_on_driver_name) == false) {
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
"either %s::connect() or PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
"%s::%s() cannot be called when connecting to the \"%s\" driver, "
"either call %s::%s() or PDO::%s() instead",
ZSTR_VAL(called_scope->name),
new_object ? "connect" : "__construct",
driver->driver_name,
ZSTR_VAL(ce_based_on_driver_name->name),
new_object ? "connect" : "__construct",
new_object ? "connect" : "__construct"
);
return false;
}

/* A driver-specific implementation was instantiated via the connect() method of the appropriate driver class */
object_init_ex(new_object, ce_based_on_called_object);
/* A driver-specific implementation is instantiated with the appropriate driver class */
if (new_object) {
object_init_ex(new_object, ce_based_on_called_object);
}
return true;
} else {
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to an unknown driver, "
"PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name));
"%s::%s() cannot be called when connecting to an unknown driver, "
"call PDO::%s() instead",
ZSTR_VAL(called_scope->name),
new_object ? "connect" : "__construct",
new_object ? "connect" : "__construct"
);
return false;
}
}

if (ce_based_on_driver_name) {
if (called_scope != pdo_dbh_ce) {
/* A driver-specific implementation was instantiated via the connect method of a wrong driver class */
/* A driver-specific implementation is instantiated of a wrong driver class */
zend_throw_exception_ex(pdo_exception_ce, 0,
"%s::connect() cannot be called when connecting to the \"%s\" driver, "
"either %s::connect() or PDO::connect() must be called instead",
ZSTR_VAL(called_scope->name), driver->driver_name, ZSTR_VAL(ce_based_on_driver_name->name));
"%s::%s() cannot be called when connecting to the \"%s\" driver, "
"either call %s::%s() or PDO::%s() instead",
ZSTR_VAL(called_scope->name),
new_object ? "connect" : "__construct",
driver->driver_name,
ZSTR_VAL(ce_based_on_driver_name->name),
new_object ? "connect" : "__construct",
new_object ? "connect" : "__construct"
);
return false;
}

/* A driver-specific implementation was instantiated via PDO::__construct() */
object_init_ex(new_object, ce_based_on_driver_name);
} else {
if (new_object) {
object_init_ex(new_object, ce_based_on_driver_name);
}
} else if (new_object) {
/* No driver-specific implementation found */
object_init_ex(new_object, called_scope);
}

return true;
}

static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object)
PDO_API void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object)
{
pdo_dbh_t *dbh = NULL;
bool is_persistent = 0;
Expand Down Expand Up @@ -343,12 +362,13 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object
RETURN_THROWS();
}

if (new_zval_object != NULL) {
ZEND_ASSERT((driver->driver_name != NULL) && "PDO driver name is null");
if (!create_driver_specific_pdo_object(driver, current_scope, new_zval_object)) {
RETURN_THROWS();
}
ZEND_ASSERT((driver->driver_name != NULL) && "PDO driver name is null");

if (!create_driver_specific_pdo_object(driver, current_scope, new_zval_object)) {
RETURN_THROWS();
}

if (new_zval_object) {
dbh = Z_PDO_DBH_P(new_zval_object);
} else {
dbh = php_pdo_dbh_fetch_inner(object);
Expand Down Expand Up @@ -497,7 +517,7 @@ static void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object
/* {{{ */
PHP_METHOD(PDO, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), EX(This).value.ce, NULL);
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}
/* }}} */

Expand Down
2 changes: 2 additions & 0 deletions ext/pdo/php_pdo_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@ PDO_API void php_pdo_dbh_delref(pdo_dbh_t *dbh);
PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt);
PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count);

PDO_API void internal_construct(INTERNAL_FUNCTION_PARAMETERS, zend_object *object, zend_class_entry *current_scope, zval *new_zval_object);

/* Normalization for fetching long param for driver attributes */
PDO_API bool pdo_get_long_param(zend_long *lval, zval *value);
PDO_API bool pdo_get_bool_param(bool *bval, zval *value);
Expand Down
7 changes: 7 additions & 0 deletions ext/pdo_dblib/pdo_dblib.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "php_pdo_dblib.h"
#include "php_pdo_dblib_int.h"
#include "zend_exceptions.h"
#include "zend_attributes.h"
#include "pdo_dblib_arginfo.h"

ZEND_DECLARE_MODULE_GLOBALS(dblib)
Expand Down Expand Up @@ -241,3 +242,9 @@ PHP_MINFO_FUNCTION(pdo_dblib)
php_info_print_table_row(2, "Flavour", PDO_DBLIB_FLAVOUR);
php_info_print_table_end();
}

PHP_METHOD(PdoDblib_ce, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}
ßß
2 changes: 2 additions & 0 deletions ext/pdo_dblib/pdo_dblib.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,6 @@ class Dblib extends \PDO

/** @cvalue PDO_DBLIB_ATTR_DATETIME_CONVERT */
public const int ATTR_DATETIME_CONVERT = UNKNOWN;

public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
}
21 changes: 19 additions & 2 deletions ext/pdo_dblib/pdo_dblib_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions ext/pdo_firebird/pdo_firebird.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "ext/pdo/php_pdo_driver.h"
#include "php_pdo_firebird.h"
#include "php_pdo_firebird_int.h"
#include "zend_attributes.h"
#include "pdo_firebird_arginfo.h"

static zend_class_entry *PdoFirebird_ce;
Expand Down Expand Up @@ -101,6 +102,11 @@ PHP_MINFO_FUNCTION(pdo_firebird) /* {{{ */
}
/* }}} */

PHP_METHOD(Pdo_Firebird, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}

PHP_METHOD(Pdo_Firebird, getApiVersion)
{
if (zend_parse_parameters_none() == FAILURE) {
Expand Down
2 changes: 2 additions & 0 deletions ext/pdo_firebird/pdo_firebird.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@ class Firebird extends \PDO
/** @cvalue PDO_FB_WRITABLE_TRANSACTION */
public const int WRITABLE_TRANSACTION = UNKNOWN;

public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}

public static function getApiVersion(): int {}
}
14 changes: 13 additions & 1 deletion ext/pdo_firebird/pdo_firebird_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions ext/pdo_mysql/pdo_mysql.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ext/pdo/php_pdo_driver.h"
#include "php_pdo_mysql.h"
#include "php_pdo_mysql_int.h"
#include "zend_attributes.h"
#include "pdo_mysql_arginfo.h"

static zend_class_entry *pdo_mysql_ce;
Expand Down Expand Up @@ -84,6 +85,11 @@ static const MYSQLND_REVERSE_API pdo_mysql_reverse_api = {
};
#endif

PHP_METHOD(Pdo_Mysql, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}

/* Returns the number of SQL warnings during the execution of the last statement */
PHP_METHOD(Pdo_Mysql, getWarningCount)
{
Expand Down
2 changes: 2 additions & 0 deletions ext/pdo_mysql/pdo_mysql.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,7 @@ class Mysql extends \PDO
public const int ATTR_LOCAL_INFILE_DIRECTORY = UNKNOWN;
#endif

public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}

public function getWarningCount(): int {}
}
14 changes: 13 additions & 1 deletion ext/pdo_mysql/pdo_mysql_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions ext/pdo_odbc/pdo_odbc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "ext/pdo/php_pdo_driver.h"
#include "php_pdo_odbc.h"
#include "php_pdo_odbc_int.h"
#include "zend_attributes.h"
#include "pdo_odbc_arginfo.h"

static zend_class_entry *pdo_odbc_ce;
Expand Down Expand Up @@ -61,6 +62,11 @@ zend_ulong pdo_odbc_pool_on = SQL_CP_OFF;
zend_ulong pdo_odbc_pool_mode = SQL_CP_ONE_PER_HENV;
#endif

PHP_METHOD(pdo_odbc, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_odbc)
{
Expand Down
2 changes: 2 additions & 0 deletions ext/pdo_odbc/pdo_odbc.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ class Odbc extends \PDO

/** @cvalue SQL_CUR_USE_ODBC */
public const int SQL_USE_ODBC = UNKNOWN;

public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}
}
}
21 changes: 19 additions & 2 deletions ext/pdo_odbc/pdo_odbc_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions ext/pdo_pgsql/pdo_pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "ext/pdo/php_pdo_driver.h"
#include "php_pdo_pgsql.h"
#include "php_pdo_pgsql_int.h"
#include "zend_attributes.h"
#include "pdo_pgsql_arginfo.h"

static zend_class_entry *PdoPgsql_ce;
Expand Down Expand Up @@ -57,6 +58,11 @@ zend_module_entry pdo_pgsql_module_entry = {
ZEND_GET_MODULE(pdo_pgsql)
#endif

PHP_METHOD(Pdo_Pgsql, __construct)
{
internal_construct(INTERNAL_FUNCTION_PARAM_PASSTHRU, Z_OBJ(EX(This)), execute_data->func->common.scope, NULL);
}

/* Escape an identifier for insertion into a text field */
PHP_METHOD(Pdo_Pgsql, escapeIdentifier)
{
Expand Down
2 changes: 2 additions & 0 deletions ext/pdo_pgsql/pdo_pgsql.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ class Pgsql extends \PDO
/** @cvalue PGSQL_TRANSACTION_UNKNOWN */
public const int TRANSACTION_UNKNOWN = UNKNOWN;

public function __construct(string $dsn, ?string $username = null, #[\SensitiveParameter] ?string $password = null, ?array $options = null) {}

public function escapeIdentifier(string $input): string {}

public function copyFromArray(string $tableName, array $rows, string $separator = "\t", string $nullAs = "\\\\N", ?string $fields = null): bool {}
Expand Down
Loading

0 comments on commit 47b5174

Please sign in to comment.