Skip to content
Snippets Groups Projects
Commit d3f74bd1 authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman
Browse files

notify/out: use RCU_lock to protect from SOA change during event

parent 24b5bb63
No related branches found
No related tags found
1 merge request!1670Fix notify rcu
......@@ -15,6 +15,7 @@
*/
#include <assert.h>
#include <urcu.h>
#include "contrib/openbsd/siphash.h"
#include "knot/common/log.h"
......@@ -150,7 +151,13 @@ int event_notify(conf_t *conf, zone_t *zone)
// NOTIFY content
int timeout = conf->cache.srv_tcp_remote_io_timeout;
rcu_read_lock();
knot_rrset_t soa = node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA);
knot_rrset_t *soa_cpy = knot_rrset_copy(&soa, NULL);
rcu_read_unlock();
if (soa_cpy == NULL) {
return KNOT_ENOMEM;
}
// in case of re-try, NOTIFY only failed remotes
pthread_mutex_lock(&zone->preferred_lock);
......@@ -175,7 +182,7 @@ int event_notify(conf_t *conf, zone_t *zone)
for (int i = 0; i < addr_count; i++) {
conf_remote_t slave = conf_remote(conf, iter.id, i);
ret = send_notify(conf, zone, &soa, &slave, timeout, retry);
ret = send_notify(conf, zone, soa_cpy, &slave, timeout, retry);
if (ret == KNOT_EOK) {
break;
}
......@@ -195,7 +202,7 @@ int event_notify(conf_t *conf, zone_t *zone)
if (failed) {
notifailed_rmt_dynarray_sort_dedup(&zone->notifailed);
uint32_t retry_in = knot_soa_retry(soa.rrs.rdata);
uint32_t retry_in = knot_soa_retry(soa_cpy->rrs.rdata);
conf_val_t val = conf_zone_get(conf, C_RETRY_MIN_INTERVAL, zone->name);
retry_in = MAX(retry_in, conf_int(&val));
val = conf_zone_get(conf, C_RETRY_MAX_INTERVAL, zone->name);
......@@ -204,6 +211,7 @@ int event_notify(conf_t *conf, zone_t *zone)
zone_events_schedule_at(zone, ZONE_EVENT_NOTIFY, time(NULL) + retry_in);
}
pthread_mutex_unlock(&zone->preferred_lock);
knot_rrset_free(soa_cpy, NULL);
return failed ? KNOT_ERROR : KNOT_EOK;
}
#!/usr/bin/env python3
'''Test of crash when NOTIFY is sent during zone CTL update.'''
from dnstest.utils import *
from dnstest.test import Test
import random
import threading
import time
loop_stop = False
def background_notify(server, zone_name):
try:
server.ctl("zone-notify " + zone_name)
except:
pass
def background_notify_loop(server, zone_name):
global loop_stop
while not loop_stop:
background_notify(server, zone_name)
def run_thr(fun, server, zone_name):
threading.Thread(target=fun, args=[server, zone_name]).start()
t = Test()
master = t.server("knot")
slave = t.server("knot")
zones = t.zone_rnd(1, dnssec=False, records=40)
t.link(zones, master, slave)
ZONE = zones[0].name
t.start()
serials = slave.zones_wait(zones)
try:
run_thr(background_notify_loop, master, ZONE)
for i in range(10):
master.ctl("zone-begin " + ZONE)
master.ctl("zone-set %s dhowedhhjewodw 3600 A 1.2.3.%d" % (ZONE, i + 1))
master.ctl("zone-commit " + ZONE)
finally:
loop_stop = True
t.end()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment