comparison src/event/quic/ngx_event_quic_connid.c @ 8911:b09f055daa4e quic

QUIC: fixed handling of RETIRE_CONNECTION_ID frame. Previously, the retired socket was not closed if it didn't match active or backup. New sockets could not be created (due to count limit), since retired socket was not closed before calling ngx_quic_create_sockets(). When replacing retired socket, new socket is only requested after closing old one, to avoid hitting the limit on the number of active connection ids. Together with added restrictions, this fixes an issue when a current socket could be closed during migration, recreated and erroneously reused leading to null pointer dereference.
author Vladimir Homutov <vl@nginx.com>
date Thu, 18 Nov 2021 14:19:36 +0300
parents f8848f5a1014
children 9680f0badc95
comparison
equal deleted inserted replaced
8910:f8848f5a1014 8911:b09f055daa4e
401 qsock = ngx_quic_find_socket(c, f->sequence_number); 401 qsock = ngx_quic_find_socket(c, f->sequence_number);
402 if (qsock == NULL) { 402 if (qsock == NULL) {
403 return NGX_OK; 403 return NGX_OK;
404 } 404 }
405 405
406 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
407 "quic socket #%uL is retired", qsock->sid.seqnum);
408
409 /* check if client is willing to retire sid we have in use */
406 if (qsock->sid.seqnum == qc->socket->sid.seqnum) { 410 if (qsock->sid.seqnum == qc->socket->sid.seqnum) {
407 tmp = &qc->socket; 411 tmp = &qc->socket;
408 412
409 } else if (qc->backup && qsock->sid.seqnum == qc->backup->sid.seqnum) { 413 } else if (qc->backup && qsock->sid.seqnum == qc->backup->sid.seqnum) {
410 tmp = &qc->backup; 414 tmp = &qc->backup;
411 415
412 } else { 416 } else {
413 tmp = NULL; 417
414 } 418 ngx_quic_close_socket(c, qsock);
415 419
420 /* restore socket count up to a limit after deletion */
421 if (ngx_quic_create_sockets(c) != NGX_OK) {
422 return NGX_ERROR;
423 }
424
425 return NGX_OK;
426 }
427
428 /* preserve path/cid from retired socket */
429 path = qsock->path;
430 cid = qsock->cid;
431
432 /* ensure that closing_socket will not drop path and cid */
433 path->refcnt++;
434 cid->refcnt++;
435
436 ngx_quic_close_socket(c, qsock);
437
438 /* restore original values */
439 path->refcnt--;
440 cid->refcnt--;
441
442 /* restore socket count up to a limit after deletion */
416 if (ngx_quic_create_sockets(c) != NGX_OK) { 443 if (ngx_quic_create_sockets(c) != NGX_OK) {
417 return NGX_ERROR; 444 goto failed;
418 } 445 }
419 446
420 if (tmp) { 447 qsock = ngx_quic_get_unconnected_socket(c);
421 /* replace socket in use (active or backup) */ 448 if (qsock == NULL) {
422 449 qc->error = NGX_QUIC_ERR_CONNECTION_ID_LIMIT_ERROR;
423 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, 450 qc->error_reason = "not enough server IDs";
424 "quic %s socket #%uL:%uL:%uL retired", 451 goto failed;
425 (*tmp) == qc->socket ? "active" : "backup", 452 }
426 (*tmp)->sid.seqnum, (*tmp)->cid->seqnum, 453
427 (*tmp)->path->seqnum); 454 ngx_quic_connect(c, qsock, path, cid);
428 455
429 qsock = ngx_quic_get_unconnected_socket(c); 456 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
430 if (qsock == NULL) { 457 "quic %s socket is now #%uL:%uL:%uL (%s)",
431 return NGX_ERROR; 458 (*tmp) == qc->socket ? "active" : "backup",
432 } 459 qsock->sid.seqnum, qsock->cid->seqnum,
433 460 qsock->path->seqnum,
434 path = (*tmp)->path; 461 ngx_quic_path_state_str(qsock->path));
435 cid = (*tmp)->cid; 462
436 463 /* restore active/backup pointer in quic connection */
437 ngx_quic_connect(c, qsock, path, cid); 464 *tmp = qsock;
438 465
439 466 return NGX_OK;
440 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, 467
441 "quic %s socket is now #%uL:%uL:%uL (%s)", 468 failed:
442 (*tmp) == qc->socket ? "active" : "backup", 469
443 qsock->sid.seqnum, qsock->cid->seqnum, 470 /*
444 qsock->path->seqnum, 471 * socket was closed, path and cid were preserved artifically
445 ngx_quic_path_state_str(qsock->path)); 472 * to be reused, but it didn't happen, thus unref here
446 473 */
447 ngx_quic_close_socket(c, *tmp); /* no longer used */ 474
448 475 ngx_quic_unref_path(c, path);
449 *tmp = qsock; 476 ngx_quic_unref_client_id(c, cid);
450 } 477
451 478 return NGX_ERROR;
452 return NGX_OK;
453 } 479 }
454 480
455 481
456 ngx_int_t 482 ngx_int_t
457 ngx_quic_create_sockets(ngx_connection_t *c) 483 ngx_quic_create_sockets(ngx_connection_t *c)