From: Yu Watanabe Date: Tue, 5 Jan 2021 06:27:11 +0000 (+0900) Subject: resolve: fix use after free in DnsAnswer X-Git-Tag: v248-rc1~399 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0c2c0fd256d2be652910d65e5a4aacc08c240714;p=thirdparty%2Fsystemd.git resolve: fix use after free in DnsAnswer This fixes a bug introduced by ae45e1a3832fbb6c96707687e42f0b4aaab52c9b. The set DnsAnswer::set_items contains the reference to the array in DnsAnswer. So, the set must be reconstructed when we realloc() the object. Fixes #18132. --- diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index f5e50fcd844..a2878ec2bb8 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -664,6 +664,7 @@ int dns_answer_reserve(DnsAnswer **a, size_t n_free) { if (*a) { size_t ns; + int r; if ((*a)->n_ref > 1) return -EBUSY; @@ -680,11 +681,23 @@ int dns_answer_reserve(DnsAnswer **a, size_t n_free) { if (ns > UINT16_MAX) ns = UINT16_MAX; + /* This must be done before realloc() below. Otherwise, the original DnsAnswer object + * may be broken. */ + r = set_reserve((*a)->set_items, ns); + if (r < 0) + return r; + n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns); if (!n) return -ENOMEM; n->n_allocated = ns; + + /* Previously all items are stored in the set, and the enough memory area is allocated + * in the above. So set_put() in the below cannot fail. */ + set_clear(n->set_items); + for (size_t i = 0; i < n->n_rrs; i++) + assert_se(set_put(n->set_items, &n->items[i]) > 0); } else { n = dns_answer_new(n_free); if (!n)