mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-11 11:09:59 -04:00
[9.20] fix: usr: prevent rare named crash when notifies are cancelled
Under heavy load, named could occasionally crash when a queued outbound notify or zone refresh was cancelled at the moment it was being sent — for example, while a zone was being reloaded or removed. The race that caused the crash is now prevented. Closes #5915 Backport of MR !11918 Merge branch 'backport-5915-ratelimiter-dequeue-tick-uaf-9.20' into 'bind-9.20' See merge request isc-projects/bind9!11922
This commit is contained in:
commit
49509dcbae
1 changed files with 17 additions and 27 deletions
|
|
@ -218,14 +218,10 @@ isc_ratelimiter_dequeue(isc_ratelimiter_t *restrict rl, isc_rlevent_t **rlep) {
|
|||
static void
|
||||
isc__ratelimiter_tick(void *arg) {
|
||||
isc_ratelimiter_t *rl = (isc_ratelimiter_t *)arg;
|
||||
isc_rlevent_t *rle = NULL;
|
||||
uint32_t pertic;
|
||||
ISC_LIST(isc_rlevent_t) pending;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
||||
ISC_LIST_INIT(pending);
|
||||
|
||||
LOCK(&rl->lock);
|
||||
|
||||
REQUIRE(rl->timer != NULL);
|
||||
|
|
@ -237,12 +233,8 @@ isc__ratelimiter_tick(void *arg) {
|
|||
|
||||
pertic = rl->pertic;
|
||||
while (pertic != 0) {
|
||||
rle = ISC_LIST_HEAD(rl->pending);
|
||||
if (rle != NULL) {
|
||||
/* There is work to do. Let's do it after unlocking. */
|
||||
ISC_LIST_UNLINK(rl->pending, rle, link);
|
||||
ISC_LIST_APPEND(pending, rle, link);
|
||||
} else {
|
||||
isc_rlevent_t *rle = ISC_LIST_HEAD(rl->pending);
|
||||
if (rle == NULL) {
|
||||
/*
|
||||
* We processed all the scheduled work, but there's a
|
||||
* room for at least one more event (we haven't consumed
|
||||
|
|
@ -253,6 +245,15 @@ isc__ratelimiter_tick(void *arg) {
|
|||
rl->state = isc_ratelimiter_idle;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Unlink and dispatch under the lock: isc_async_run() is a
|
||||
* non-blocking enqueue, so this stays cheap, and once the
|
||||
* link is TOMBSTONEd a concurrent isc_ratelimiter_dequeue()
|
||||
* sees ISC_LINK_LINKED == false and returns ISC_R_NOTFOUND
|
||||
* cleanly instead of racing with our dispatch.
|
||||
*/
|
||||
ISC_LIST_UNLINK(rl->pending, rle, link);
|
||||
isc_async_run(rle->loop, rle->cb, rle->arg);
|
||||
pertic--;
|
||||
}
|
||||
|
||||
|
|
@ -262,11 +263,6 @@ isc__ratelimiter_tick(void *arg) {
|
|||
}
|
||||
unlock:
|
||||
UNLOCK(&rl->lock);
|
||||
|
||||
while ((rle = ISC_LIST_HEAD(pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(pending, rle, link);
|
||||
isc_async_run(rle->loop, rle->cb, rle->arg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -288,27 +284,21 @@ isc__ratelimiter_doshutdown(void *arg) {
|
|||
|
||||
void
|
||||
isc_ratelimiter_shutdown(isc_ratelimiter_t *restrict rl) {
|
||||
isc_rlevent_t *rle = NULL;
|
||||
ISC_LIST(isc_rlevent_t) pending;
|
||||
|
||||
REQUIRE(VALID_RATELIMITER(rl));
|
||||
|
||||
ISC_LIST_INIT(pending);
|
||||
|
||||
LOCK(&rl->lock);
|
||||
if (rl->state != isc_ratelimiter_shuttingdown) {
|
||||
isc_rlevent_t *rle = NULL;
|
||||
rl->state = isc_ratelimiter_shuttingdown;
|
||||
ISC_LIST_MOVE(pending, rl->pending);
|
||||
while ((rle = ISC_LIST_HEAD(rl->pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(rl->pending, rle, link);
|
||||
rle->canceled = true;
|
||||
isc_async_run(rl->loop, rle->cb, rle->arg);
|
||||
}
|
||||
isc_ratelimiter_ref(rl);
|
||||
isc_async_run(rl->loop, isc__ratelimiter_doshutdown, rl);
|
||||
}
|
||||
UNLOCK(&rl->lock);
|
||||
|
||||
while ((rle = ISC_LIST_HEAD(pending)) != NULL) {
|
||||
ISC_LIST_UNLINK(pending, rle, link);
|
||||
rle->canceled = true;
|
||||
isc_async_run(rl->loop, rle->cb, rle->arg);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Reference in a new issue