]> The Tcpdump Group git mirrors - tcpdump/blobdiff - smbutil.c
Handle very large -f files by rejecting them.
[tcpdump] / smbutil.c
index e6114fa37330a0be518dc6ffc511cfc6de478636..525635cbc7f78ebf5f5038267ecf8e9ccc4d6a25 100644 (file)
--- a/smbutil.c
+++ b/smbutil.c
@@ -237,6 +237,7 @@ name_len(netdissect_options *ndo,
            return(-1); /* name goes past the end of the buffer */
        ND_TCHECK2(*s, 1);
        s += (*s) + 1;
+       ND_TCHECK2(*s, 1);
     }
     return(PTR_DIFF(s, s0) + 1);
 
@@ -271,8 +272,7 @@ name_type_str(int name_type)
 }
 
 void
-print_data(netdissect_options *ndo,
-           const unsigned char *buf, int len)
+smb_print_data(netdissect_options *ndo, const unsigned char *buf, int len)
 {
     int i = 0;
 
@@ -478,12 +478,13 @@ smb_fdata1(netdissect_options *ndo,
 
        case 'P':
          {
-           int l = atoi(fmt + 1);
+           int l = atoi(fmt + 1);          
+           if(l <= 0) goto trunc;  /* actually error in fmt string */
            ND_TCHECK2(buf[0], l);
            buf += l;
            fmt++;
            while (isdigit((unsigned char)*fmt))
-               fmt++;
+             fmt++;
            break;
          }
        case 'r':
@@ -797,17 +798,33 @@ smb_fdata(netdissect_options *ndo,
           int unicodestr)
 {
     static int depth = 0;
+    const u_char *buf_start = buf;
     char s[128];
     char *p;
 
     while (*fmt) {
        switch (*fmt) {
        case '*':
+           /*
+            * List of multiple instances of something described by the
+            * remainder of the string (which may itself include a list
+            * of multiple instances of something, so we recurse).
+            */
            fmt++;
            while (buf < maxbuf) {
                const u_char *buf2;
                depth++;
-               buf2 = smb_fdata(ndo, buf, fmt, maxbuf, unicodestr);
+               /*
+                * In order to avoid stack exhaustion recurse at most 10
+                * levels; that "should not happen", as no SMB structure
+                * should be nested *that* deeply, and we thus shouldn't
+                * have format strings with that level of nesting.
+                */
+               if (depth == 10) {
+                       ND_PRINT((ndo, "(too many nested levels, not recursing)"));
+                       buf2 = buf;
+               } else
+                       buf2 = smb_fdata(ndo, buf, fmt, maxbuf, unicodestr);
                depth--;
                if (buf2 == NULL)
                    return(NULL);
@@ -818,22 +835,35 @@ smb_fdata(netdissect_options *ndo,
            return(buf);
 
        case '|':
+           /*
+            * Just do a bounds check.
+            */
            fmt++;
            if (buf >= maxbuf)
                return(buf);
            break;
 
        case '%':
+           /*
+            * XXX - unused?
+            */
            fmt++;
            buf = maxbuf;
            break;
 
        case '#':
+           /*
+            * Done?
+            */
            fmt++;
            return(buf);
            break;
 
        case '[':
+           /*
+            * Format of an item, enclosed in square brackets; dissect
+            * the item with smb_fdata1().
+            */
            fmt++;
            if (buf >= maxbuf)
                return(buf);
@@ -847,11 +877,15 @@ smb_fdata(netdissect_options *ndo,
            s[p - fmt] = '\0';
            fmt = p + 1;
            buf = smb_fdata1(ndo, buf, s, maxbuf, unicodestr);
-           if (buf == NULL)
+           if(buf < buf_start || buf == NULL) {
                return(NULL);
+           }
            break;
 
        default:
+           /*
+            * Not a formatting character, so just print it.
+            */
            ND_PRINT((ndo, "%c", *fmt));
            fmt++;
            break;
@@ -860,7 +894,7 @@ smb_fdata(netdissect_options *ndo,
     if (!depth && buf < maxbuf) {
        size_t len = PTR_DIFF(maxbuf, buf);
        ND_PRINT((ndo, "Data: (%lu bytes)\n", (unsigned long)len));
-       print_data(ndo, buf, len);
+       smb_print_data(ndo, buf, len);
        return(buf + len);
     }
     return(buf);