From 0fda9d704d3bbf54a5e64ce02a6fecb11fe7f047 Mon Sep 17 00:00:00 2001 From: Damien Miller Date: Fri, 10 Mar 2023 15:59:46 +1100 Subject: [PATCH] bounds checking for getrrsetbyname() replacement; Spotted by Coverity in CID 405033; ok millert@ --- openbsd-compat/getrrsetbyname.c | 47 +++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/openbsd-compat/getrrsetbyname.c b/openbsd-compat/getrrsetbyname.c index 73de5e948..8f5939840 100644 --- a/openbsd-compat/getrrsetbyname.c +++ b/openbsd-compat/getrrsetbyname.c @@ -390,6 +390,9 @@ parse_dns_response(const u_char *answer, int size) struct dns_response *resp; const u_char *cp; + if (size < HFIXEDSZ) + return (NULL); + /* allocate memory for the response */ resp = calloc(1, sizeof(*resp)); if (resp == NULL) @@ -456,14 +459,22 @@ parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) int i, length; char name[MAXDNAME]; - for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { +#define NEED(need) \ + do { \ + if (*cp + need > answer + size) \ + goto fail; \ + } while (0) - /* allocate and initialize struct */ - curr = calloc(1, sizeof(struct dns_query)); - if (curr == NULL) { + for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { + if (*cp >= answer + size) { + fail: free_dns_query(head); return (NULL); } + /* allocate and initialize struct */ + curr = calloc(1, sizeof(struct dns_query)); + if (curr == NULL) + goto fail; if (head == NULL) head = curr; if (prev != NULL) @@ -481,16 +492,20 @@ parse_dns_qsection(const u_char *answer, int size, const u_char **cp, int count) free_dns_query(head); return (NULL); } + NEED(length); *cp += length; /* type */ + NEED(INT16SZ); curr->type = _getshort(*cp); *cp += INT16SZ; /* class */ + NEED(INT16SZ); curr->class = _getshort(*cp); *cp += INT16SZ; } +#undef NEED return (head); } @@ -503,14 +518,23 @@ parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, int i, length; char name[MAXDNAME]; - for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { +#define NEED(need) \ + do { \ + if (*cp + need > answer + size) \ + goto fail; \ + } while (0) - /* allocate and initialize struct */ - curr = calloc(1, sizeof(struct dns_rr)); - if (curr == NULL) { + for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) { + if (*cp >= answer + size) { + fail: free_dns_rr(head); return (NULL); } + + /* allocate and initialize struct */ + curr = calloc(1, sizeof(struct dns_rr)); + if (curr == NULL) + goto fail; if (head == NULL) head = curr; if (prev != NULL) @@ -528,25 +552,31 @@ parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, free_dns_rr(head); return (NULL); } + NEED(length); *cp += length; /* type */ + NEED(INT16SZ); curr->type = _getshort(*cp); *cp += INT16SZ; /* class */ + NEED(INT16SZ); curr->class = _getshort(*cp); *cp += INT16SZ; /* ttl */ + NEED(INT32SZ); curr->ttl = _getlong(*cp); *cp += INT32SZ; /* rdata size */ + NEED(INT16SZ); curr->size = _getshort(*cp); *cp += INT16SZ; /* rdata itself */ + NEED(curr->size); curr->rdata = malloc(curr->size); if (curr->rdata == NULL) { free_dns_rr(head); @@ -555,6 +585,7 @@ parse_dns_rrsection(const u_char *answer, int size, const u_char **cp, memcpy(curr->rdata, *cp, curr->size); *cp += curr->size; } +#undef NEED return (head); }