Skip to content

Commit 58f13c3

Browse files
committed
Handle the situation when MYSQLND_PROTOCOL's methods return NULL.
mysqlnd should not crash but gracefully return with an error.
1 parent bccf2ce commit 58f13c3

File tree

4 files changed

+77
-27
lines changed

4 files changed

+77
-27
lines changed

ext/mysqlnd/mysqlnd.c

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,18 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu
225225
zend_bool silent, enum php_mysqlnd_server_command command,
226226
zend_bool ignore_upsert_status TSRMLS_DC)
227227
{
228-
enum_func_status ret;
228+
enum_func_status ret = FAIL;
229229

230230
DBG_ENTER("mysqlnd_conn::simple_command_handle_response");
231231
DBG_INF_FMT("silent=%d packet=%d command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
232232

233233
switch (ok_packet) {
234234
case PROT_OK_PACKET:{
235235
MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
236+
if (!ok_response) {
237+
SET_OOM_ERROR(conn->error_info);
238+
break;
239+
}
236240
if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
237241
if (!silent) {
238242
DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
@@ -274,6 +278,10 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu
274278
}
275279
case PROT_EOF_PACKET:{
276280
MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC);
281+
if (!ok_response) {
282+
SET_OOM_ERROR(conn->error_info);
283+
break;
284+
}
277285
if (FAIL == (ret = PACKET_READ(ok_response, conn))) {
278286
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
279287
"Malformed packet");
@@ -300,7 +308,6 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu
300308
break;
301309
}
302310
default:
303-
ret = FAIL;
304311
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet");
305312
php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong response packet %d passed to the function", ok_packet);
306313
break;
@@ -344,6 +351,11 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_se
344351
SET_EMPTY_ERROR(conn->error_info);
345352

346353
cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE TSRMLS_CC);
354+
if (!cmd_packet) {
355+
SET_OOM_ERROR(conn->error_info);
356+
DBG_RETURN(FAIL);
357+
}
358+
347359
cmd_packet->command = command;
348360
if (arg && arg_len) {
349361
cmd_packet->argument = arg;
@@ -526,6 +538,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
526538
transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port);
527539
}
528540
if (!transport) {
541+
SET_OOM_ERROR(conn->error_info);
529542
goto err; /* OOM */
530543
}
531544
DBG_INF_FMT("transport=%s", transport);
@@ -542,6 +555,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
542555
auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC);
543556
ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
544557
if (!greet_packet || !auth_packet || !ok_packet) {
558+
SET_OOM_ERROR(conn->error_info);
545559
goto err; /* OOM */
546560
}
547561

@@ -613,6 +627,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
613627

614628
conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
615629
if (!conn->scramble) {
630+
SET_OOM_ERROR(conn->error_info);
616631
goto err; /* OOM */
617632
}
618633
memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH);
@@ -682,31 +697,36 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn,
682697
conn->connect_or_select_db_len = db_len;
683698

684699
if (!conn->user || !conn->passwd || !conn->connect_or_select_db) {
700+
SET_OOM_ERROR(conn->error_info);
685701
goto err; /* OOM */
686702
}
687703

688704
if (!unix_socket) {
689705
conn->host = mnd_pestrdup(host, conn->persistent);
690706
if (!conn->host) {
707+
SET_OOM_ERROR(conn->error_info);
691708
goto err; /* OOM */
692709
}
693710
conn->host_len = strlen(conn->host);
694711
{
695712
char *p;
696713
spprintf(&p, 0, "%s via TCP/IP", conn->host);
697714
if (!p) {
715+
SET_OOM_ERROR(conn->error_info);
698716
goto err; /* OOM */
699717
}
700718
conn->host_info = mnd_pestrdup(p, conn->persistent);
701719
efree(p); /* allocated by spprintf */
702720
if (!conn->host_info) {
721+
SET_OOM_ERROR(conn->error_info);
703722
goto err; /* OOM */
704723
}
705724
}
706725
} else {
707726
conn->unix_socket = mnd_pestrdup(socket, conn->persistent);
708727
conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent);
709728
if (!conn->unix_socket || !conn->host_info) {
729+
SET_OOM_ERROR(conn->error_info);
710730
goto err; /* OOM */
711731
}
712732
conn->unix_socket_len = strlen(conn->unix_socket);
@@ -1333,6 +1353,11 @@ MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND * conn, char **message, unsigned int
13331353
DBG_RETURN(FAIL);
13341354
}
13351355
stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE TSRMLS_CC);
1356+
if (!stats_header) {
1357+
SET_OOM_ERROR(conn->error_info);
1358+
DBG_RETURN(FAIL);
1359+
}
1360+
13361361
if (FAIL == (ret = PACKET_READ(stats_header, conn))) {
13371362
DBG_RETURN(FAIL);
13381363
}
@@ -1829,7 +1854,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
18291854
buffer overflows.
18301855
*/
18311856
size_t user_len;
1832-
enum_func_status ret;
1857+
enum_func_status ret = FAIL;
18331858
MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp;
18341859
char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1];
18351860
char *p = buffer;
@@ -1838,6 +1863,8 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
18381863
DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%d",
18391864
conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 );
18401865

1866+
SET_ERROR_AFF_ROWS(conn);
1867+
18411868
if (!user) {
18421869
user = "";
18431870
}
@@ -1878,6 +1905,10 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
18781905
}
18791906

18801907
chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC);
1908+
if (!chg_user_resp) {
1909+
SET_OOM_ERROR(conn->error_info);
1910+
goto end;
1911+
}
18811912
ret = PACKET_READ(chg_user_resp, conn);
18821913
conn->error_info = chg_user_resp->error_info;
18831914

@@ -1888,13 +1919,15 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
18881919
bug#25371 mysql_change_user() triggers "packets out of sync"
18891920
When it gets fixed, there should be one more check here
18901921
*/
1891-
if (mysqlnd_get_server_version(conn) > 50113L &&
1892-
mysqlnd_get_server_version(conn) < 50118L)
1893-
{
1922+
if (mysqlnd_get_server_version(conn) > 50113L && mysqlnd_get_server_version(conn) < 50118L) {
18941923
MYSQLND_PACKET_OK * redundant_error_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC);
1895-
PACKET_READ(redundant_error_packet, conn);
1896-
PACKET_FREE(redundant_error_packet);
1897-
DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn));
1924+
if (redundant_error_packet) {
1925+
PACKET_READ(redundant_error_packet, conn);
1926+
PACKET_FREE(redundant_error_packet);
1927+
DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn));
1928+
} else {
1929+
SET_OOM_ERROR(conn->error_info);
1930+
}
18981931
}
18991932
}
19001933
if (ret == PASS) {
@@ -1919,10 +1952,9 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn,
19191952
DBG_ERR(mysqlnd_old_passwd);
19201953
SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd);
19211954
}
1955+
end:
19221956
PACKET_FREE(chg_user_resp);
19231957

1924-
SET_ERROR_AFF_ROWS(conn);
1925-
19261958
/*
19271959
Here we should close all statements. Unbuffered queries should not be a
19281960
problem as we won't allow sending COM_CHANGE_USER.

ext/mysqlnd/mysqlnd_ps.c

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,10 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
243243
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
244244

245245
field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
246-
if (field_packet) {
246+
if (!field_packet) {
247+
SET_OOM_ERROR(stmt->error_info);
248+
SET_OOM_ERROR(stmt->conn->error_info);
249+
} else {
247250
ret = PASS;
248251
field_packet->skip_parsing = TRUE;
249252
for (;i < stmt->param_count; i++) {
@@ -266,23 +269,27 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
266269
{
267270
MYSQLND_STMT_DATA * stmt = s->data;
268271
MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
269-
enum_func_status ret = PASS;
272+
enum_func_status ret = FAIL;
270273

271274
DBG_ENTER("mysqlnd_stmt_read_prepare_response");
272275
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
273276

274277
prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
278+
if (!prepare_resp) {
279+
SET_OOM_ERROR(stmt->error_info);
280+
SET_OOM_ERROR(stmt->conn->error_info);
281+
goto done;
282+
}
283+
275284
if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
276-
ret = FAIL;
277285
goto done;
278286
}
279287

280288
if (0xFF == prepare_resp->error_code) {
281289
stmt->error_info = stmt->conn->error_info = prepare_resp->error_info;
282-
ret = FAIL;
283290
goto done;
284291
}
285-
292+
ret = PASS;
286293
stmt->stmt_id = prepare_resp->stmt_id;
287294
stmt->warning_count = stmt->conn->upsert_status.warning_count = prepare_resp->warning_count;
288295
stmt->field_count = stmt->conn->field_count = prepare_resp->field_count;
@@ -307,19 +314,24 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
307314
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
308315

309316
fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
310-
if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
311-
if (stmt->result) {
312-
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
313-
mnd_efree(stmt->result);
314-
memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
315-
stmt->state = MYSQLND_STMT_INITTED;
316-
}
317+
if (!fields_eof) {
318+
SET_OOM_ERROR(stmt->error_info);
319+
SET_OOM_ERROR(stmt->conn->error_info);
317320
} else {
318-
stmt->upsert_status.server_status = fields_eof->server_status;
319-
stmt->upsert_status.warning_count = fields_eof->warning_count;
320-
stmt->state = MYSQLND_STMT_PREPARED;
321+
if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
322+
if (stmt->result) {
323+
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
324+
mnd_efree(stmt->result);
325+
memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
326+
stmt->state = MYSQLND_STMT_INITTED;
327+
}
328+
} else {
329+
stmt->upsert_status.server_status = fields_eof->server_status;
330+
stmt->upsert_status.warning_count = fields_eof->warning_count;
331+
stmt->state = MYSQLND_STMT_PREPARED;
332+
}
333+
PACKET_FREE(fields_eof);
321334
}
322-
PACKET_FREE(fields_eof);
323335

324336
DBG_RETURN(ret);
325337
}

ext/mysqlnd/mysqlnd_result.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,11 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC)
493493

494494
/* Check for SERVER_STATUS_MORE_RESULTS if needed */
495495
fields_eof = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC);
496+
if (!fields_eof) {
497+
SET_OOM_ERROR(conn->error_info);
498+
ret = FAIL;
499+
break;
500+
}
496501
if (FAIL == (ret = PACKET_READ(fields_eof, conn))) {
497502
DBG_ERR("Error ocurred while reading the EOF packet");
498503
result->m.free_result_contents(result TSRMLS_CC);

ext/mysqlnd/mysqlnd_result_meta.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met
151151

152152
field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE TSRMLS_CC);
153153
if (!field_packet) {
154+
SET_OOM_ERROR(conn->error_info);
154155
DBG_RETURN(FAIL);
155156
}
156157
field_packet->persistent_alloc = meta->persistent;

0 commit comments

Comments
 (0)