Mercurial > hg > nginx
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) |