about summary refs log tree commit diff
path: root/resolv/gethnamaddr.c
diff options
context:
space:
mode:
Diffstat (limited to 'resolv/gethnamaddr.c')
-rw-r--r--resolv/gethnamaddr.c44
1 files changed, 41 insertions, 3 deletions
diff --git a/resolv/gethnamaddr.c b/resolv/gethnamaddr.c
index 4c8180fca8..3272dbd591 100644
--- a/resolv/gethnamaddr.c
+++ b/resolv/gethnamaddr.c
@@ -160,6 +160,24 @@ dprintf(msg, num)
 # define dprintf(msg, num) /*nada*/
 #endif
 
+#define BOUNDED_INCR(x) \
+	do { \
+		cp += x; \
+		if (cp > eom) { \
+			__set_h_errno (NO_RECOVERY); \
+			return (NULL); \
+		} \
+	} while (0)
+
+#define BOUNDS_CHECK(ptr, count) \
+	do { \
+		if ((ptr) + (count) > eom) { \
+			__set_h_errno (NO_RECOVERY); \
+			return (NULL); \
+		} \
+	} while (0)
+
+
 static struct hostent *
 getanswer(answer, anslen, qname, qtype)
 	const querybuf *answer;
@@ -170,7 +188,7 @@ getanswer(answer, anslen, qname, qtype)
 	register const HEADER *hp;
 	register const u_char *cp;
 	register int n;
-	const u_char *eom;
+	const u_char *eom, *erdata;
 	char *bp, **ap, **hap;
 	int type, class, buflen, ancount, qdcount;
 	int haveanswer, had_error;
@@ -201,7 +219,8 @@ getanswer(answer, anslen, qname, qtype)
 	qdcount = ntohs(hp->qdcount);
 	bp = hostbuf;
 	buflen = sizeof hostbuf;
-	cp = answer->buf + HFIXEDSZ;
+	cp = answer->buf;
+	BOUNDED_INCR(HFIXEDSZ);
 	if (qdcount != 1) {
 		__set_h_errno (NO_RECOVERY);
 		return (NULL);
@@ -211,7 +230,7 @@ getanswer(answer, anslen, qname, qtype)
 		__set_h_errno (NO_RECOVERY);
 		return (NULL);
 	}
-	cp += n + QFIXEDSZ;
+	BOUNDED_INCR(n + QFIXEDSZ);
 	if (qtype == T_A || qtype == T_AAAA) {
 		/* res_send() has already verified that the query name is the
 		 * same as the one we sent; this just gets the expanded name
@@ -243,12 +262,15 @@ getanswer(answer, anslen, qname, qtype)
 			continue;
 		}
 		cp += n;			/* name */
+		BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
 		type = _getshort(cp);
  		cp += INT16SZ;			/* type */
 		class = _getshort(cp);
  		cp += INT16SZ + INT32SZ;	/* class, TTL */
 		n = _getshort(cp);
 		cp += INT16SZ;			/* len */
+		BOUNDS_CHECK(cp, n);
+		erdata = cp + n;
 		if (class != C_IN) {
 			/* XXX - debug? syslog? */
 			cp += n;
@@ -263,6 +285,10 @@ getanswer(answer, anslen, qname, qtype)
 				continue;
 			}
 			cp += n;
+			if (cp != erdata) {
+				__set_h_errno (NO_RECOVERY);
+				return (NULL);
+			}
 			/* Store alias. */
 			*ap++ = bp;
 			n = strlen(bp) + 1;	/* for the \0 */
@@ -291,6 +317,10 @@ getanswer(answer, anslen, qname, qtype)
 				continue;
 			}
 			cp += n;
+			if (cp != erdata) {
+				__set_h_errno (NO_RECOVERY);
+				return (NULL);
+			}
 			/* Get canonical name. */
 			n = strlen(tbuf) + 1;	/* for the \0 */
 			if (n > buflen || n >= MAXHOSTNAMELEN) {
@@ -326,6 +356,10 @@ getanswer(answer, anslen, qname, qtype)
 			}
 #if MULTI_PTRS_ARE_ALIASES
 			cp += n;
+			if (cp != erdata) {
+				__set_h_errno (NO_RECOVERY);
+				return (NULL);
+			}
 			if (!haveanswer)
 				host.h_name = bp;
 			else if (ap < &host_aliases[MAXALIASES-1])
@@ -397,6 +431,10 @@ getanswer(answer, anslen, qname, qtype)
 			bp += n;
 			buflen -= n;
 			cp += n;
+			if (cp != erdata) {
+				__set_h_errno (NO_RECOVERY);
+				return (NULL);
+			}
 			break;
 		default:
 			abort();