X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fresolve%2Fresolved-dns-packet.c;h=5597ffd96909eb8fbd84a416e7a1a1576c539ce8;hb=a2ba62c719224a4b47751623ca5e8b0333f49721;hp=a503b0150659dfa5ed1db299a3468871c077fc3c;hpb=4e0296a943e85316ecce0324248f9543887b8a9a;p=elogind.git diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index a503b0150..5597ffd96 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -20,7 +20,7 @@ ***/ #include "utf8.h" - +#include "util.h" #include "resolved-dns-domain.h" #include "resolved-dns-packet.h" @@ -38,6 +38,13 @@ int dns_packet_new(DnsPacket **ret, size_t mtu) { if (a < DNS_PACKET_HEADER_SIZE) a = DNS_PACKET_HEADER_SIZE; + /* round up to next page size */ + a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket)); + + /* make sure we never allocate more than useful */ + if (a > DNS_PACKET_SIZE_MAX) + a = DNS_PACKET_SIZE_MAX; + p = malloc0(ALIGN(sizeof(DnsPacket)) + a); if (!p) return -ENOMEM; @@ -112,11 +119,13 @@ int dns_packet_validate(DnsPacket *p) { if (p->size < DNS_PACKET_HEADER_SIZE) return -EBADMSG; + if (p->size > DNS_PACKET_SIZE_MAX) + return -EBADMSG; + return 0; } int dns_packet_validate_reply(DnsPacket *p) { - DnsPacketHeader *h; int r; assert(p); @@ -125,14 +134,10 @@ int dns_packet_validate_reply(DnsPacket *p) { if (r < 0) return r; - h = DNS_PACKET_HEADER(p); - - /* Check QR field */ - if ((be16toh(h->flags) & 1) == 0) + if (DNS_PACKET_QR(p) == 0) return -EBADMSG; - /* Check opcode field */ - if (((be16toh(h->flags) >> 1) & 15) != 0) + if (DNS_PACKET_OPCODE(p) != 0) return -EBADMSG; return 0; @@ -141,8 +146,35 @@ int dns_packet_validate_reply(DnsPacket *p) { static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) { assert(p); - if (p->size + add > p->allocated) - return -ENOMEM; + if (p->size + add > p->allocated) { + size_t a; + + a = PAGE_ALIGN((p->size + add) * 2); + if (a > DNS_PACKET_SIZE_MAX) + a = DNS_PACKET_SIZE_MAX; + + if (p->size + add > a) + return -EMSGSIZE; + + if (p->data) { + void *d; + + d = realloc(p->data, a); + if (!d) + return -ENOMEM; + + p->data = d; + } else { + p->data = malloc(a); + if (!p->data) + return -ENOMEM; + + memcpy(p->data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size); + memzero((uint8_t*) p->data + p->size, a - p->size); + } + + p->allocated = a; + } if (start) *start = p->size; @@ -363,7 +395,7 @@ int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) { return 0; } -static void dns_packet_rewind(DnsPacket *p, size_t idx) { +void dns_packet_rewind(DnsPacket *p, size_t idx) { assert(p); assert(idx <= p->size); assert(idx >= DNS_PACKET_HEADER_SIZE); @@ -699,7 +731,7 @@ int dns_packet_skip_question(DnsPacket *p) { unsigned i, n; assert(p); - n = be16toh(DNS_PACKET_HEADER(p)->qdcount); + n = DNS_PACKET_QDCOUNT(p); for (i = 0; i < n; i++) { _cleanup_(dns_resource_key_free) DnsResourceKey key = {};