]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: fix refcounting DnsScope's conflict_queue
authorDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Wed, 3 Jan 2018 12:26:53 +0000 (14:26 +0200)
committerDmitry Rozhkov <dmitry.rozhkov@linux.intel.com>
Wed, 3 Jan 2018 13:04:20 +0000 (15:04 +0200)
Refcounting for a RR's key is done separately from refcounting
for the RR itself, but in dns_scope_notify_conflict() we don't
do that. This may lead to a situation when a RR key put in the
conflict_queue hash as a value's key gets freed upon
cache reduction when it's still referenced by the hash.

Thus increase refcount for the key when putting it into the hash
and unreference it upon removing from the hash.

Closes #6456

src/resolve/resolved-dns-scope.c

index ea4459a89a31e7078f494e24ce0214af67a75cf3..9247bb34e6deb9668a2fadfdf83bc0bd3c6a1f4e 100644 (file)
@@ -885,13 +885,17 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata
         scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source);
 
         for (;;) {
+                _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
                 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
                 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
 
-                rr = ordered_hashmap_steal_first(scope->conflict_queue);
-                if (!rr)
+                key = ordered_hashmap_first_key(scope->conflict_queue);
+                if (!key)
                         break;
 
+                rr = ordered_hashmap_remove(scope->conflict_queue, key);
+                assert(rr);
+
                 r = dns_scope_make_conflict_packet(scope, rr, &p);
                 if (r < 0) {
                         log_error_errno(r, "Failed to make conflict packet: %m");
@@ -930,6 +934,7 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) {
         if (r < 0)
                 return log_debug_errno(r, "Failed to queue conflicting RR: %m");
 
+        dns_resource_key_ref(rr->key);
         dns_resource_record_ref(rr);
 
         if (scope->conflict_event_source)