]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
bounds checking for getrrsetbyname() replacement;
authorDamien Miller <djm@mindrot.org>
Fri, 10 Mar 2023 04:59:46 +0000 (15:59 +1100)
committerDamien Miller <djm@mindrot.org>
Fri, 10 Mar 2023 04:59:46 +0000 (15:59 +1100)
Spotted by Coverity in CID 405033; ok millert@

openbsd-compat/getrrsetbyname.c

index 73de5e9482b864653927cb90365f707a2a872c26..8f593984066e976cf898cd7d05383623add2964f 100644 (file)
@@ -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);
 }