626085
From 47ef5ccd0edbff6610badc8c0f543f0e1d18bdc2 Mon Sep 17 00:00:00 2001
7eab74
From: Michal Sekletar <msekleta@redhat.com>
7eab74
Date: Thu, 4 Aug 2022 11:11:58 +0200
7eab74
Subject: [PATCH] resolve: introduce reference counting on DnsStream
7eab74
7eab74
(cherry picked from commit b30bf55d5c9942f15f27a641c2c34bbb646ec981)
7eab74
7eab74
Related: #2110544
7eab74
7eab74
[msekleta: in order to protect against freeing the DnsStream by the
7eab74
callback we need to pin it by increasing the reference count. Reference
7eab74
counting for DnsStream was introduced in the b30bf55d5c as part of the
7eab74
much bigger change. We are very late in RHEL-7 release cycle and we want
7eab74
to keep code changes to a minimum, so let's backport just relevant part
7eab74
of that commit and leave everything else unchanged.]
7eab74
---
7eab74
 src/resolve/resolved-dns-stream.c      | 27 ++++++++++++++++++++------
7eab74
 src/resolve/resolved-dns-stream.h      |  6 +++++-
7eab74
 src/resolve/resolved-dns-transaction.c |  8 ++++----
7eab74
 src/resolve/resolved-manager.c         |  2 +-
7eab74
 4 files changed, 31 insertions(+), 12 deletions(-)
7eab74
7eab74
diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c
626085
index 7f47e7223a..8d898b4819 100644
7eab74
--- a/src/resolve/resolved-dns-stream.c
7eab74
+++ b/src/resolve/resolved-dns-stream.c
626085
@@ -55,8 +55,8 @@ static int dns_stream_complete(DnsStream *s, int error) {
7eab74
 
7eab74
         if (s->complete)
7eab74
                 s->complete(s, error);
7eab74
-        else
7eab74
-                dns_stream_free(s);
7eab74
+        else /* the default action if no completion function is set is to close the stream */
7eab74
+                dns_stream_unref(s);
7eab74
 
7eab74
         return 0;
7eab74
 }
626085
@@ -322,10 +322,16 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
7eab74
         return 0;
7eab74
 }
7eab74
 
7eab74
-DnsStream *dns_stream_free(DnsStream *s) {
7eab74
+DnsStream *dns_stream_unref(DnsStream *s) {
7eab74
         if (!s)
7eab74
                 return NULL;
7eab74
 
7eab74
+        assert(s->n_ref > 0);
7eab74
+        s->n_ref--;
7eab74
+
7eab74
+        if (s->n_ref > 0)
7eab74
+                return NULL;
7eab74
+
7eab74
         dns_stream_stop(s);
7eab74
 
7eab74
         if (s->manager) {
626085
@@ -338,14 +344,22 @@ DnsStream *dns_stream_free(DnsStream *s) {
7eab74
 
7eab74
         free(s);
7eab74
 
7eab74
-        return 0;
7eab74
+        return NULL;
7eab74
 }
7eab74
 
7eab74
-DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_free);
7eab74
+DnsStream *dns_stream_ref(DnsStream *s) {
7eab74
+        if (!s)
7eab74
+                return NULL;
7eab74
+
7eab74
+        assert(s->n_ref > 0);
7eab74
+        s->n_ref++;
7eab74
+
7eab74
+        return s;
7eab74
+}
7eab74
 
7eab74
 int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) {
7eab74
         static const int one = 1;
7eab74
-        _cleanup_(dns_stream_freep) DnsStream *s = NULL;
7eab74
+        _cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
7eab74
         int r;
7eab74
 
7eab74
         assert(m);
626085
@@ -358,6 +372,7 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) {
7eab74
         if (!s)
7eab74
                 return -ENOMEM;
7eab74
 
7eab74
+        s->n_ref = 1;
7eab74
         s->fd = -1;
7eab74
         s->protocol = protocol;
7eab74
 
7eab74
diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h
7eab74
index 46eae31c60..28aee48205 100644
7eab74
--- a/src/resolve/resolved-dns-stream.h
7eab74
+++ b/src/resolve/resolved-dns-stream.h
7eab74
@@ -31,6 +31,7 @@ typedef struct DnsStream DnsStream;
7eab74
 
7eab74
 struct DnsStream {
7eab74
         Manager *manager;
7eab74
+        int n_ref;
7eab74
 
7eab74
         DnsProtocol protocol;
7eab74
 
7eab74
@@ -59,6 +60,9 @@ struct DnsStream {
7eab74
 };
7eab74
 
7eab74
 int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd);
7eab74
-DnsStream *dns_stream_free(DnsStream *s);
7eab74
+DnsStream *dns_stream_unref(DnsStream *s);
7eab74
+DnsStream *dns_stream_ref(DnsStream *s);
7eab74
+
7eab74
+DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_unref);
7eab74
 
7eab74
 int dns_stream_write_packet(DnsStream *s, DnsPacket *p);
7eab74
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
7eab74
index bc1a90db1b..6fa581b6a9 100644
7eab74
--- a/src/resolve/resolved-dns-transaction.c
7eab74
+++ b/src/resolve/resolved-dns-transaction.c
7eab74
@@ -37,7 +37,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
7eab74
         dns_packet_unref(t->received);
7eab74
         dns_answer_unref(t->cached);
7eab74
 
7eab74
-        dns_stream_free(t->stream);
7eab74
+        dns_stream_unref(t->stream);
7eab74
 
7eab74
         if (t->scope) {
7eab74
                 LIST_REMOVE(transactions_by_scope, t->scope->transactions, t);
7eab74
@@ -114,7 +114,7 @@ static void dns_transaction_stop(DnsTransaction *t) {
7eab74
         assert(t);
7eab74
 
7eab74
         t->timeout_event_source = sd_event_source_unref(t->timeout_event_source);
7eab74
-        t->stream = dns_stream_free(t->stream);
7eab74
+        t->stream = dns_stream_unref(t->stream);
7eab74
 }
7eab74
 
7eab74
 static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
7eab74
@@ -208,7 +208,7 @@ static int on_stream_complete(DnsStream *s, int error) {
7eab74
         t = s->transaction;
7eab74
         p = dns_packet_ref(s->read_packet);
7eab74
 
7eab74
-        t->stream = dns_stream_free(t->stream);
7eab74
+        t->stream = dns_stream_unref(t->stream);
7eab74
 
7eab74
         if (error != 0) {
7eab74
                 dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES);
7eab74
@@ -279,7 +279,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
7eab74
 
7eab74
         r = dns_stream_write_packet(t->stream, t->sent);
7eab74
         if (r < 0) {
7eab74
-                t->stream = dns_stream_free(t->stream);
7eab74
+                t->stream = dns_stream_unref(t->stream);
7eab74
                 return r;
7eab74
         }
7eab74
 
7eab74
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
7eab74
index 173ab8a148..aa7aa68cab 100644
7eab74
--- a/src/resolve/resolved-manager.c
7eab74
+++ b/src/resolve/resolved-manager.c
7eab74
@@ -1531,7 +1531,7 @@ static int on_llmnr_stream_packet(DnsStream *s) {
7eab74
         } else
7eab74
                 log_debug("Invalid LLMNR TCP packet.");
7eab74
 
7eab74
-        dns_stream_free(s);
7eab74
+        dns_stream_unref(s);
7eab74
         return 0;
7eab74
 }
7eab74