udhcp: we call DNS name encoder with NULL, this can SEGV. added a check
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 24 Mar 2010 15:11:32 +0000 (16:11 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 24 Mar 2010 15:11:32 +0000 (16:11 +0100)
function                                             old     new   delta
dname_enc                                            418     415      -3

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/udhcp/domain_codec.c

index 93dfd9a4e19c8c25f301e6c5df3ad26911b60ffe..c81372ad29274717b5cf69e97e75cd478c7e5eda 100644 (file)
@@ -7,8 +7,6 @@
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
-#if ENABLE_FEATURE_UDHCP_RFC3397
-
 #include "common.h"
 
 #define NS_MAXDNAME  1025      /* max domain name length */
@@ -63,7 +61,7 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
                                if (dst)
                                        dst[len - 1] = '.';
                        } else {
-                               /* null: end of current domain name */
+                               /* NUL: end of current domain name */
                                if (retpos == 0) {
                                        /* toplevel? keep going */
                                        crtpos++;
@@ -107,38 +105,39 @@ char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
  */
 static uint8_t *convert_dname(const char *src)
 {
-       uint8_t c, *res, *lp, *rp;
+       uint8_t c, *res, *lenptr, *dst;
        int len;
 
        res = xmalloc(strlen(src) + 2);
-       rp = lp = res;
-       rp++;
+       dst = lenptr = res;
+       dst++;
 
        for (;;) {
                c = (uint8_t)*src++;
-               if (c == '.' || c == '\0') {    /* end of label */
-                       len = rp - lp - 1;
+               if (c == '.' || c == '\0') {  /* end of label */
+                       len = dst - lenptr - 1;
                        /* label too long, too short, or two '.'s in a row? abort */
                        if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) {
                                free(res);
                                return NULL;
                        }
-                       *lp = len;
-                       lp = rp++;
-                       if (c == '\0' || *src == '\0')  /* end of dname */
+                       *lenptr = len;
+                       if (c == '\0' || *src == '\0')  /* "" or ".": end of src */
                                break;
-               } else {
-                       if (c >= 0x41 && c <= 0x5A)             /* uppercase? convert to lower */
-                               c += 0x20;
-                       *rp++ = c;
+                       lenptr = dst++;
+                       continue;
                }
+               if (c >= 'A' && c <= 'Z')  /* uppercase? convert to lower */
+                       c += ('a' - 'A');
+               *dst++ = c;
        }
 
-       *lp = 0;
-       if (rp - res > NS_MAXCDNAME) {  /* dname too long? abort */
+       if (dst - res >= NS_MAXCDNAME) {  /* dname too long? abort */
                free(res);
                return NULL;
        }
+
+       *dst = 0;
        return res;
 }
 
@@ -147,30 +146,35 @@ static uint8_t *convert_dname(const char *src)
 static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
 {
        const uint8_t *c, *d;
-       int off, inc;
+       int off;
 
        /* find all labels in cstr */
        off = 0;
        while (off < clen) {
                c = cstr + off;
 
-               if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {      /* pointer, skip */
+               if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {  /* pointer, skip */
                        off += 2;
-               } else if (*c) {        /* label, try matching dname */
-                       inc = *c + 1;
+                       continue;
+               }
+               if (*c) {  /* label, try matching dname */
                        d = dname;
-                       while (*c == *d && memcmp(c + 1, d + 1, *c) == 0) {
-                               if (*c == 0)    /* match, return offset */
+                       while (1) {
+                               unsigned len1 = *c + 1;
+                               if (memcmp(c, d, len1) != 0)
+                                       break;
+                               if (len1 == 1)  /* at terminating NUL - match, return offset */
                                        return off;
-                               d += *c + 1;
-                               c += *c + 1;
+                               d += len1;
+                               c += len1;
                                if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS)  /* pointer, jump */
                                        c = cstr + (((c[0] & 0x3f) << 8) | c[1]);
                        }
-                       off += inc;
-               } else {        /* null, skip */
-                       off++;
+                       off += cstr[off] + 1;
+                       continue;
                }
+               /* NUL, skip */
+               off++;
        }
 
        return -1;
@@ -178,7 +182,7 @@ static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
 
 /* computes string to be appended to cstr so that src would be added to
  * the compression (best case, it's a 2-byte pointer to some offset within
- * cstr; worst case, it's all of src, converted to rfc3011 format).
+ * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format).
  * The computed string is returned directly; its length is returned via retlen;
  * NULL and 0, respectively, are returned if an error occurs.
  */
@@ -193,17 +197,19 @@ uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int
                return NULL;
        }
 
-       for (d = dname; *d != 0; d += *d + 1) {
-               off = find_offset(cstr, clen, d);
-               if (off >= 0) { /* found a match, add pointer and terminate string */
-                       *d++ = NS_CMPRSFLGS + (off >> 8);
-                       *d = off;
-                       break;
+       d = dname;
+       while (*d) {
+               if (cstr) {
+                       off = find_offset(cstr, clen, d);
+                       if (off >= 0) { /* found a match, add pointer and return */
+                               *d++ = NS_CMPRSFLGS | (off >> 8);
+                               *d = off;
+                               break;
+                       }
                }
+               d += *d + 1;
        }
 
        *retlen = d - dname + 1;
        return dname;
 }
-
-#endif /* ENABLE_FEATURE_UDHCP_RFC3397 */