r2224: Make nmbd more robust against bad netbios packets.
authorJeremy Allison <jra@samba.org>
Sat, 4 Sep 2004 01:57:16 +0000 (01:57 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 15:52:36 +0000 (10:52 -0500)
Jeremy.

source/libsmb/nmblib.c
source/nmbd/nmbd_packets.c
source/nmbd/nmbd_processlogon.c

index d883c5308d39086292e34876f7d6b28939eff80e..7f22ce0096afc6ff86186b87eb62d9a67a49b643 100644 (file)
@@ -475,6 +475,11 @@ static BOOL parse_dgram(char *inbuf,int length,struct dgram_packet *dgram)
        dgram->datasize = length-offset;
        memcpy(dgram->data,inbuf+offset,dgram->datasize);
 
+       /* Paranioa. Ensure the last 2 bytes in the dgram buffer are
+          zero. This should be true anyway, just enforce it for paranioa sake. JRA. */
+       SMB_ASSERT(dgram->datasize <= (sizeof(dgram->data)-2));
+       memset(&dgram->data[sizeof(dgram->data)-2], '\0', 2);
+
        return(True);
 }
 
index d8b50a1b2e9a83a223acfcb233c8071f756b77ad..96de4911dc587057f5d4087e856b9b802ca62579 100644 (file)
@@ -1203,6 +1203,16 @@ an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip),
                return;
        }
 
+       /* Ensure we have a large enough packet before looking inside. */
+       if (dgram->datasize < (smb_vwv12 - 2)) {
+               /* That's the offset minus the 4 byte length + 2 bytes of offset. */
+               DEBUG(0,("process_dgram: ignoring too short dgram packet (%u) sent to name %s from IP %s\n",
+                       (unsigned int)dgram->datasize,
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
+       }
+
        buf = &dgram->data[0];
        buf -= 4; /* XXXX for the pseudo tcp length - someday I need to get rid of this */
 
@@ -1212,14 +1222,36 @@ an error packet of type %x\n", nmb_namestr(&dgram->dest_name), inet_ntoa(p->ip),
        len = SVAL(buf,smb_vwv11);
        buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
 
-       if (len <= 0)
+       if (len <= 0 || len > dgram->datasize) {
+               DEBUG(0,("process_dgram: ignoring malformed1 (datasize = %d, len = %d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
+       }
+
+       if (buf2 < dgram->data || (buf2 >= dgram->data + dgram->datasize)) {
+               DEBUG(0,("process_dgram: ignoring malformed2 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       PTR_DIFF(buf2, dgram->data),
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
                return;
+       }
 
-       if (buf2 + len > buf + sizeof(dgram->data)) {
-               DEBUG(2,("process_dgram: datagram from %s to %s IP %s for %s len=%d too long.\n",
-                       nmb_namestr(&dgram->source_name),nmb_namestr(&dgram->dest_name),
-                       inet_ntoa(p->ip), smb_buf(buf),len));
-               len = (buf + sizeof(dgram->data)) - buf;
+       if ((buf2 + len < dgram->data) || (buf2 + len > dgram->data + dgram->datasize)) {
+               DEBUG(0,("process_dgram: ignoring malformed3 (datasize = %d, len=%d, off=%d) datagram \
+packet sent to name %s from IP %s\n",
+                       dgram->datasize,
+                       len,
+                       PTR_DIFF(buf2, dgram->data),
+                       nmb_namestr(&dgram->dest_name),
+                       inet_ntoa(p->ip) ));
+               return;
        }
 
        DEBUG(4,("process_dgram: datagram from %s to %s IP %s for %s of type %d len=%d\n",
index da93224043c0cd28f39be7dc5ace74782adf4bc0..fa2a8c1cefa060b09f5bc23ea86e47e5c55f75cd 100644 (file)
@@ -102,8 +102,22 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                char *machine = q;
                                char *user = skip_string(machine,1);
 
+                               if (PTR_DIFF(user, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
                                getdc = skip_string(user,1);
+
+                               if (PTR_DIFF(getdc, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
                                q = skip_string(getdc,1);
+
+                               if (PTR_DIFF(q + 5, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
                                token = SVAL(q,3);
 
                                fstrcpy(reply_name,my_name); 
@@ -151,7 +165,17 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                }
 
                                getdc = skip_string(machine,1);
+
+                               if (PTR_DIFF(getdc, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
                                q = skip_string(getdc,1);
+
+                               if (PTR_DIFF(q, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
                                q = ALIGN2(q, buf);
 
                                /* At this point we can work out if this is a W9X or NT style
@@ -165,9 +189,19 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                } else {
                                        unicomp = q;
 
+                                       if (PTR_DIFF(q, buf) >= len) {
+                                               DEBUG(0,("process_logon_packet: bad packet\n"));
+                                               return;
+                                       }
+
                                        /* A full length (NT style) request */
                                        q = skip_unibuf(unicomp, PTR_DIFF(buf + len, unicomp));
 
+                                       if (PTR_DIFF(q, buf) >= len) {
+                                               DEBUG(0,("process_logon_packet: bad packet\n"));
+                                               return;
+                                       }
+
                                        if (len - PTR_DIFF(q, buf) > 8) {
                                                /* with NT5 clients we can sometimes
                                                        get additional data - a length specificed string
@@ -180,6 +214,12 @@ logons are not enabled.\n", inet_ntoa(p->ip) ));
                                                }
                                                q += 16;
                                        }
+
+                                       if (PTR_DIFF(q + 8, buf) >= len) {
+                                               DEBUG(0,("process_logon_packet: bad packet\n"));
+                                               return;
+                                       }
+
                                        ntversion = IVAL(q, 0);
                                        lmnttoken = SVAL(q, 4);
                                        lm20token = SVAL(q, 6);
@@ -240,10 +280,34 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                fstring asccomp;
 
                                q += 2;
+
+                               if (PTR_DIFF(q, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                unicomp = q;
                                uniuser = skip_unibuf(unicomp, PTR_DIFF(buf+len, unicomp));
+
+                               if (PTR_DIFF(uniuser, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                getdc = skip_unibuf(uniuser,PTR_DIFF(buf+len, uniuser));
+
+                               if (PTR_DIFF(getdc, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                q = skip_string(getdc,1);
+
+                               if (PTR_DIFF(q + 8, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                q += 4; /* Account Control Bits - indicating username type */
                                domainsidsize = IVAL(q, 0);
                                q += 4;
@@ -270,6 +334,11 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                        q += 16;
                                }
 
+                               if (PTR_DIFF(q + 8, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                ntversion = IVAL(q, 0);
                                lmnttoken = SVAL(q, 4);
                                lm20token = SVAL(q, 6);
@@ -458,6 +527,11 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
           
                                /* Header */
           
+                               if (PTR_DIFF(q + 16, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                low_serial = IVAL(q, 0); q += 4;     /* Low serial number */
 
                                q += 4;                   /* Date/time */
@@ -467,14 +541,42 @@ reporting %s domain %s 0x%x ntversion=%x lm_nt token=%x lm_20 token=%x\n",
                                /* Domain info */
           
                                q = skip_string(q, 1);    /* PDC name */
+
+                               if (PTR_DIFF(q, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                q = skip_string(q, 1);    /* Domain name */
+
+                               if (PTR_DIFF(q, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode PDC name */
+
+                               if (PTR_DIFF(q, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                q = skip_unibuf(q, PTR_DIFF(buf + len, q)); /* Unicode domain name */
           
                                /* Database info */
           
+                               if (PTR_DIFF(q + 2, buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                db_count = SVAL(q, 0); q += 2;
-          
+
+                               if (PTR_DIFF(q + (db_count*20), buf) >= len) {
+                                       DEBUG(0,("process_logon_packet: bad packet\n"));
+                                       return;
+                               }
+
                                db_info = (struct sam_database_info *)
                                                malloc(sizeof(struct sam_database_info) * db_count);