diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-07-04 18:09:58 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-07-09 05:20:10 +0900 |
commit | 325513bc776c739a814996cc5c483235ca92be86 (patch) | |
tree | 197914963a0fd97d99ed99314fc615c0a482beeb /src/resolve/resolved-dns-cache.c | |
parent | 055acd4d8b385fd9ff29e49e0c46856a9e705433 (diff) | |
download | systemd-325513bc776c739a814996cc5c483235ca92be86.tar.gz |
resolve: mdns: calculate required packet size to store questions and authorities
Otherwise, if we have many cached entries or pending transactions with
TYPE_ANY, then dns_transaction_make_packet_mdns() fails with -EMSGSIZE.
This also fixes use-after-free.
Fixes #23894.
Diffstat (limited to 'src/resolve/resolved-dns-cache.c')
-rw-r--r-- | src/resolve/resolved-dns-cache.c | 32 |
1 files changed, 23 insertions, 9 deletions
diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 0856976d3e..f793a659ee 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -1242,16 +1242,14 @@ int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_ return 1; } -int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { +int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p, usec_t ts, unsigned max_rr) { unsigned ancount = 0; DnsCacheItem *i; - usec_t t; int r; assert(cache); assert(p); - - t = now(CLOCK_BOOTTIME); + assert(p->protocol == DNS_PROTOCOL_MDNS); HASHMAP_FOREACH(i, cache->by_key) LIST_FOREACH(by_key, j, i) { @@ -1263,14 +1261,17 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { /* RFC6762 7.1: Don't append records with less than half the TTL remaining * as known answers. */ - if (usec_sub_unsigned(j->until, t) < j->rr->ttl * USEC_PER_SEC / 2) + if (usec_sub_unsigned(j->until, ts) < j->rr->ttl * USEC_PER_SEC / 2) continue; r = dns_packet_append_rr(p, j->rr, 0, NULL, NULL); - if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) { - /* For mDNS, if we're unable to stuff all known answers into the given packet, - * allocate a new one, push the RR into that one and link it to the current one. - */ + if (r == -EMSGSIZE) { + if (max_rr == 0) + /* If max_rr == 0, do not allocate more packets. */ + goto finalize; + + /* If we're unable to stuff all known answers into the given packet, allocate + * a new one, push the RR into that one and link it to the current one. */ DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); ancount = 0; @@ -1288,8 +1289,21 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { return r; ancount++; + if (max_rr > 0 && ancount >= max_rr) { + DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); + ancount = 0; + + r = dns_packet_new_query(&p->more, p->protocol, 0, true); + if (r < 0) + return r; + + p = p->more; + + max_rr = UINT_MAX; + } } +finalize: DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); return 0; |