Skip to content

Commit 05fcc2e

Browse files
committed
PHPC-671: Avoid mongoc_client_t use-after-free by Cursor and Server
1 parent 1978caa commit 05fcc2e

File tree

11 files changed

+171
-42
lines changed

11 files changed

+171
-42
lines changed

php_phongo.c

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ static void php_phongo_log(mongoc_log_level_t log_level, const char *log_domain,
224224
/* }}} */
225225

226226
/* {{{ Init objects */
227-
static void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, mongoc_client_t *client TSRMLS_DC) /* {{{ */
227+
static void phongo_cursor_init(zval *return_value, zval *manager, mongoc_cursor_t *cursor TSRMLS_DC) /* {{{ */
228228
{
229229
php_phongo_cursor_t *intern;
230230

@@ -233,18 +233,32 @@ static void phongo_cursor_init(zval *return_value, mongoc_cursor_t *cursor, mong
233233
intern = Z_CURSOR_OBJ_P(return_value);
234234
intern->cursor = cursor;
235235
intern->server_id = mongoc_cursor_get_hint(cursor);
236-
intern->client = client;
236+
intern->client = Z_MANAGER_OBJ_P(manager)->client;
237+
238+
#if PHP_VERSION_ID >= 70000
239+
ZVAL_COPY(&intern->manager, manager);
240+
#else
241+
Z_ADDREF_P(manager);
242+
intern->manager = manager;
243+
#endif
237244
} /* }}} */
238245

239-
void phongo_server_init(zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC) /* {{{ */
246+
void phongo_server_init(zval *return_value, zval *manager, int server_id TSRMLS_DC) /* {{{ */
240247
{
241248
php_phongo_server_t *server;
242249

243250
object_init_ex(return_value, php_phongo_server_ce);
244251

245252
server = Z_SERVER_OBJ_P(return_value);
246-
server->client = client;
247253
server->server_id = server_id;
254+
server->client = Z_MANAGER_OBJ_P(manager)->client;
255+
256+
#if PHP_VERSION_ID >= 70000
257+
ZVAL_COPY(&server->manager, manager);
258+
#else
259+
Z_ADDREF_P(manager);
260+
server->manager = manager;
261+
#endif
248262
}
249263
/* }}} */
250264

@@ -467,16 +481,23 @@ zend_bool phongo_writeerror_init(zval *return_value, bson_t *bson TSRMLS_DC) /*
467481
return true;
468482
} /* }}} */
469483

470-
php_phongo_writeresult_t *phongo_writeresult_init(zval *return_value, bson_t *reply, mongoc_client_t *client, int server_id TSRMLS_DC) /* {{{ */
484+
php_phongo_writeresult_t *phongo_writeresult_init(zval *return_value, bson_t *reply, zval *manager, int server_id TSRMLS_DC) /* {{{ */
471485
{
472486
php_phongo_writeresult_t *writeresult;
473487

474488
object_init_ex(return_value, php_phongo_writeresult_ce);
475489

476490
writeresult = Z_WRITERESULT_OBJ_P(return_value);
477491
writeresult->reply = bson_copy(reply);
478-
writeresult->client = client;
479492
writeresult->server_id = server_id;
493+
writeresult->client = Z_MANAGER_OBJ_P(manager)->client;
494+
495+
#if PHP_VERSION_ID >= 70000
496+
ZVAL_COPY(&writeresult->manager, manager);
497+
#else
498+
Z_ADDREF_P(manager);
499+
writeresult->manager = manager;
500+
#endif
480501

481502
return writeresult;
482503
} /* }}} */
@@ -506,15 +527,18 @@ mongoc_bulk_operation_t *phongo_bulkwrite_init(zend_bool ordered) { /* {{{ */
506527
return mongoc_bulk_operation_new(ordered);
507528
} /* }}} */
508529

509-
bool phongo_execute_write(mongoc_client_t *client, const char *namespace, mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
530+
bool phongo_execute_write(zval *manager, const char *namespace, mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
510531
{
532+
mongoc_client_t *client;
511533
bson_error_t error;
512534
char *dbname;
513535
char *collname;
514536
int success;
515537
bson_t reply = BSON_INITIALIZER;
516538
php_phongo_writeresult_t *writeresult;
517539

540+
client = Z_MANAGER_OBJ_P(manager)->client;
541+
518542
if (!phongo_split_namespace(namespace, &dbname, &collname)) {
519543
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s: %s", "Invalid namespace provided", namespace);
520544
return false;
@@ -553,7 +577,7 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, mongoc
553577
return false;
554578
}
555579

556-
writeresult = phongo_writeresult_init(return_value, &reply, client, bulk->hint TSRMLS_CC);
580+
writeresult = phongo_writeresult_init(return_value, &reply, manager, bulk->hint TSRMLS_CC);
557581
writeresult->write_concern = mongoc_write_concern_copy(write_concern);
558582

559583
/* The Write failed */
@@ -571,14 +595,17 @@ bool phongo_execute_write(mongoc_client_t *client, const char *namespace, mongoc
571595
return success;
572596
} /* }}} */
573597

574-
int phongo_execute_query(mongoc_client_t *client, const char *namespace, const php_phongo_query_t *query, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
598+
int phongo_execute_query(zval *manager, const char *namespace, const php_phongo_query_t *query, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
575599
{
600+
mongoc_client_t *client;
576601
const bson_t *doc = NULL;
577602
mongoc_cursor_t *cursor;
578603
char *dbname;
579604
char *collname;
580605
mongoc_collection_t *collection;
581606

607+
client = Z_MANAGER_OBJ_P(manager)->client;
608+
582609
if (!phongo_split_namespace(namespace, &dbname, &collname)) {
583610
phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT TSRMLS_CC, "%s: %s", "Invalid namespace provided", namespace);
584611
return false;
@@ -626,17 +653,19 @@ int phongo_execute_query(mongoc_client_t *client, const char *namespace, const p
626653
return true;
627654
}
628655

629-
phongo_cursor_init(return_value, cursor, client TSRMLS_CC);
656+
phongo_cursor_init(return_value, manager, cursor TSRMLS_CC);
630657
return true;
631658
} /* }}} */
632659

633-
int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
660+
int phongo_execute_command(zval *manager, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC) /* {{{ */
634661
{
662+
mongoc_client_t *client;
635663
mongoc_cursor_t *cursor;
636664
const bson_t *doc;
637665
bson_iter_t iter;
638666
bson_iter_t child;
639667

668+
client = Z_MANAGER_OBJ_P(manager)->client;
640669

641670
cursor = mongoc_client_command(client, db, MONGOC_QUERY_NONE, 0, 1, 0, command, NULL, read_preference);
642671
if (server_id > 0) {
@@ -702,7 +731,7 @@ int phongo_execute_command(mongoc_client_t *client, const char *db, const bson_t
702731
mongoc_cursor_next(cursor, &doc);
703732
}
704733

705-
phongo_cursor_init(return_value, cursor, client TSRMLS_CC);
734+
phongo_cursor_init(return_value, manager, cursor TSRMLS_CC);
706735
return true;
707736
} /* }}} */
708737

php_phongo.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,15 @@ void phongo_throw_exception_from_bson_error_t(bson_error_t *error TSRMLS_DC);
114114

115115
PHONGO_API zend_object_handlers *phongo_get_std_object_handlers(void);
116116

117-
void phongo_server_init (zval *return_value, mongoc_client_t *client, int server_id TSRMLS_DC);
117+
void phongo_server_init (zval *return_value, zval *manager, int server_id TSRMLS_DC);
118118
void phongo_readconcern_init (zval *return_value, const mongoc_read_concern_t *read_concern TSRMLS_DC);
119119
void phongo_readpreference_init (zval *return_value, const mongoc_read_prefs_t *read_prefs TSRMLS_DC);
120120
void phongo_writeconcern_init (zval *return_value, const mongoc_write_concern_t *write_concern TSRMLS_DC);
121121
bool phongo_query_init (php_phongo_query_t *query, bson_t *filter, bson_t *options TSRMLS_DC);
122122
mongoc_bulk_operation_t* phongo_bulkwrite_init (zend_bool ordered);
123-
bool phongo_execute_write (mongoc_client_t *client, const char *namespace, mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
124-
int phongo_execute_command (mongoc_client_t *client, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
125-
int phongo_execute_query (mongoc_client_t *client, const char *namespace, const php_phongo_query_t *query, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
123+
bool phongo_execute_write (zval *manager, const char *namespace, mongoc_bulk_operation_t *bulk, const mongoc_write_concern_t *write_concern, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
124+
int phongo_execute_command (zval *manager, const char *db, const bson_t *command, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
125+
int phongo_execute_query (zval *manager, const char *namespace, const php_phongo_query_t *query, const mongoc_read_prefs_t *read_preference, int server_id, zval *return_value, int return_value_used TSRMLS_DC);
126126

127127
mongoc_stream_t* phongo_stream_initiator (const mongoc_uri_t *uri, const mongoc_host_list_t *host, void *user_data, bson_error_t *error);
128128
const mongoc_read_concern_t* phongo_read_concern_from_zval (zval *zread_concern TSRMLS_DC);

php_phongo_structs-5.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ typedef struct {
4040
typedef struct {
4141
zend_object std;
4242
mongoc_cursor_t *cursor;
43+
zval *manager;
4344
mongoc_client_t *client;
4445
int server_id;
4546
php_phongo_bson_state visitor_data;
@@ -80,6 +81,7 @@ typedef struct {
8081

8182
typedef struct {
8283
zend_object std;
84+
zval *manager;
8385
mongoc_client_t *client;
8486
int server_id;
8587
} php_phongo_server_t;
@@ -113,6 +115,7 @@ typedef struct {
113115
zend_object std;
114116
mongoc_write_concern_t *write_concern;
115117
bson_t *reply;
118+
zval *manager;
116119
mongoc_client_t *client;
117120
int server_id;
118121
} php_phongo_writeresult_t;

php_phongo_structs-7.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ typedef struct {
3939

4040
typedef struct {
4141
mongoc_cursor_t *cursor;
42+
zval manager;
4243
mongoc_client_t *client;
4344
int server_id;
4445
php_phongo_bson_state visitor_data;
@@ -79,6 +80,7 @@ typedef struct {
7980
} php_phongo_readpreference_t;
8081

8182
typedef struct {
83+
zval manager;
8284
mongoc_client_t *client;
8385
int server_id;
8486
zend_object std;
@@ -112,6 +114,7 @@ typedef struct {
112114
typedef struct {
113115
mongoc_write_concern_t *write_concern;
114116
bson_t *reply;
117+
zval manager;
115118
mongoc_client_t *client;
116119
int server_id;
117120
zend_object std;

src/MongoDB/Cursor.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,11 @@ PHP_METHOD(Cursor, getServer)
157157
return;
158158
}
159159

160-
161-
phongo_server_init(return_value, intern->cursor->client, intern->server_id TSRMLS_CC);
160+
#if PHP_VERSION_ID >= 70000
161+
phongo_server_init(return_value, &intern->manager, intern->server_id TSRMLS_CC);
162+
#else
163+
phongo_server_init(return_value, intern->manager, intern->server_id TSRMLS_CC);
164+
#endif
162165
}
163166
/* }}} */
164167

@@ -222,6 +225,8 @@ static void php_phongo_cursor_free_object(phongo_free_object_arg *object TSRMLS_
222225

223226
php_phongo_cursor_free(intern);
224227

228+
zval_ptr_dtor(&intern->manager);
229+
225230
#if PHP_VERSION_ID < 70000
226231
efree(intern);
227232
#endif

src/MongoDB/Manager.c

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ PHP_METHOD(Manager, __construct)
8989
Execute a command */
9090
PHP_METHOD(Manager, executeCommand)
9191
{
92-
php_phongo_manager_t *intern;
9392
char *db;
9493
phongo_zpp_char_len db_len;
9594
zval *command;
@@ -98,46 +97,38 @@ PHP_METHOD(Manager, executeCommand)
9897
DECLARE_RETURN_VALUE_USED
9998
SUPPRESS_UNUSED_WARNING(return_value_ptr)
10099

101-
102-
intern = Z_MANAGER_OBJ_P(getThis());
103-
104100
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &db, &db_len, &command, php_phongo_command_ce, &readPreference, php_phongo_readpreference_ce) == FAILURE) {
105101
return;
106102
}
107103

108104

109105
cmd = Z_COMMAND_OBJ_P(command);
110-
phongo_execute_command(intern->client, db, cmd->bson, phongo_read_preference_from_zval(readPreference TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
106+
phongo_execute_command(getThis(), db, cmd->bson, phongo_read_preference_from_zval(readPreference TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
111107
}
112108
/* }}} */
113109
/* {{{ proto MongoDB\Driver\Cursor Manager::executeQuery(string $namespace, MongoDB\Driver\Query $zquery[, MongoDB\Driver\ReadPreference $readPreference = null])
114110
Execute a Query */
115111
PHP_METHOD(Manager, executeQuery)
116112
{
117-
php_phongo_manager_t *intern;
118113
char *namespace;
119114
phongo_zpp_char_len namespace_len;
120115
zval *zquery;
121116
zval *readPreference = NULL;
122117
DECLARE_RETURN_VALUE_USED
123118
SUPPRESS_UNUSED_WARNING(return_value_ptr)
124119

125-
126-
intern = Z_MANAGER_OBJ_P(getThis());
127-
128120
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &namespace, &namespace_len, &zquery, php_phongo_query_ce, &readPreference, php_phongo_readpreference_ce) == FAILURE) {
129121
return;
130122
}
131123

132124

133-
phongo_execute_query(intern->client, namespace, phongo_query_from_zval(zquery TSRMLS_CC), phongo_read_preference_from_zval(readPreference TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
125+
phongo_execute_query(getThis(), namespace, phongo_query_from_zval(zquery TSRMLS_CC), phongo_read_preference_from_zval(readPreference TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
134126
}
135127
/* }}} */
136128
/* {{{ proto MongoDB\Driver\WriteResult Manager::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $zbulk[, MongoDB\Driver\WriteConcern $writeConcern = null])
137129
Executes a write operation bulk (e.g. insert, update, delete) */
138130
PHP_METHOD(Manager, executeBulkWrite)
139131
{
140-
php_phongo_manager_t *intern;
141132
char *namespace;
142133
phongo_zpp_char_len namespace_len;
143134
zval *zbulk;
@@ -146,16 +137,13 @@ PHP_METHOD(Manager, executeBulkWrite)
146137
DECLARE_RETURN_VALUE_USED
147138
SUPPRESS_UNUSED_WARNING(return_value_ptr)
148139

149-
150-
intern = Z_MANAGER_OBJ_P(getThis());
151-
152140
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sO|O!", &namespace, &namespace_len, &zbulk, php_phongo_bulkwrite_ce, &zwrite_concern, php_phongo_writeconcern_ce) == FAILURE) {
153141
return;
154142
}
155143

156144

157145
bulk = Z_BULKWRITE_OBJ_P(zbulk);
158-
phongo_execute_write(intern->client, namespace, bulk->bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
146+
phongo_execute_write(getThis(), namespace, bulk->bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), -1, return_value, return_value_used TSRMLS_CC);
159147
}
160148
/* }}} */
161149

@@ -230,12 +218,12 @@ PHP_METHOD(Manager, getServers)
230218
}
231219

232220
#if PHP_VERSION_ID >= 70000
233-
phongo_server_init(&obj, intern->client, ((mongoc_server_description_t *)set->items[i].item)->id TSRMLS_CC);
221+
phongo_server_init(&obj, getThis(), ((mongoc_server_description_t *)set->items[i].item)->id TSRMLS_CC);
234222
add_next_index_zval(return_value, &obj);
235223
#else
236224
MAKE_STD_ZVAL(obj);
237225

238-
phongo_server_init(obj, intern->client, sd->id TSRMLS_CC);
226+
phongo_server_init(obj, getThis(), sd->id TSRMLS_CC);
239227
add_next_index_zval(return_value, obj);
240228
#endif
241229
}
@@ -281,7 +269,7 @@ PHP_METHOD(Manager, selectServer)
281269
readPreference = phongo_read_preference_from_zval(zreadPreference TSRMLS_CC);
282270
selected_server = mongoc_topology_select(intern->client->topology, MONGOC_SS_READ, readPreference, MONGOC_SS_DEFAULT_LOCAL_THRESHOLD_MS, &error);
283271
if (selected_server) {
284-
phongo_server_init(return_value, intern->client, selected_server->id TSRMLS_CC);
272+
phongo_server_init(return_value, getThis(), selected_server->id TSRMLS_CC);
285273
mongoc_server_description_destroy(selected_server);
286274
} else {
287275
/* Check for connection related exceptions */

src/MongoDB/Server.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,11 @@ PHP_METHOD(Server, executeCommand)
8080

8181

8282
cmd = Z_COMMAND_OBJ_P(command);
83-
phongo_execute_command(intern->client, db, cmd->bson, phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
83+
#if PHP_VERSION_ID >= 70000
84+
phongo_execute_command(&intern->manager, db, cmd->bson, phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
85+
#else
86+
phongo_execute_command(intern->manager, db, cmd->bson, phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
87+
#endif
8488
}
8589
/* }}} */
8690
/* {{{ proto MongoDB\Driver\Cursor Server::executeQuery(string $namespace, MongoDB\Driver\Query $zquery[, MongoDB\Driver\ReadPreference $readPreference = null]))
@@ -102,8 +106,11 @@ PHP_METHOD(Server, executeQuery)
102106
return;
103107
}
104108

105-
106-
phongo_execute_query(intern->client, namespace, phongo_query_from_zval(zquery TSRMLS_CC), phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
109+
#if PHP_VERSION_ID >= 70000
110+
phongo_execute_query(&intern->manager, namespace, phongo_query_from_zval(zquery TSRMLS_CC), phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
111+
#else
112+
phongo_execute_query(intern->manager, namespace, phongo_query_from_zval(zquery TSRMLS_CC), phongo_read_preference_from_zval(readPreference TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
113+
#endif
107114
}
108115
/* }}} */
109116
/* {{{ proto MongoDB\Driver\WriteResult Server::executeBulkWrite(string $namespace, MongoDB\Driver\BulkWrite $zbulk[, MongoDB\Driver\WriteConcern $writeConcern = null])
@@ -128,7 +135,11 @@ PHP_METHOD(Server, executeBulkWrite)
128135

129136

130137
bulk = Z_BULKWRITE_OBJ_P(zbulk);
131-
phongo_execute_write(intern->client, namespace, bulk->bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
138+
#if PHP_VERSION_ID >= 70000
139+
phongo_execute_write(&intern->manager, namespace, bulk->bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
140+
#else
141+
phongo_execute_write(intern->manager, namespace, bulk->bulk, phongo_write_concern_from_zval(zwrite_concern TSRMLS_CC), intern->server_id, return_value, return_value_used TSRMLS_CC);
142+
#endif
132143
}
133144
/* }}} */
134145
/* {{{ proto string Server::getHost()
@@ -522,6 +533,8 @@ static void php_phongo_server_free_object(phongo_free_object_arg *object TSRMLS_
522533

523534
zend_object_std_dtor(&intern->std TSRMLS_CC);
524535

536+
zval_ptr_dtor(&intern->manager);
537+
525538
#if PHP_VERSION_ID < 70000
526539
efree(intern);
527540
#endif

0 commit comments

Comments
 (0)