On Sun, Dec 03, 2000 at 11:53:56AM +0100, Arkadiusz Miskiewicz wrote:
> Program received signal SIGSEGV, Segmentation fault.
> name_interpret (in=0x8142762 <Address 0x8142762 out of bounds>, out=0xbffff604 "")
> at ./smbutil.c:122
> 122 int len = (*in++) / 2;
Are you capturing traffic with the default snapshot length of 68?
I'm not sure that caused the RADIUS problem, as the RADIUS dissector
appears to be using all the right TCHECK macro calls, so it shouldn't
run off the end of the packet; however, the SMB dissector doesn't use
any of them, and the routine that constructed the bad pointer handed to
"name_interpret()" appears to blithely assume that the "ofs" argument
will be within the bounds of the packet (which "fdata1()" might arrange
to be the case), *but* that if there's a pointer (upper two bits of the
byte are set), the offset in the pointer is *also* within the bounds of
the message.
(It's also checking only the beginning of the name for a pointer, rather
than doing the same full-blown decompression that "ns_nprint()" in
"print-domain.c" does; when I did the NetBIOS Name Service dissector in
Ethereal, I had it call routines exported by the DNS dissector for this
purpose. However, given that NetBIOS names aren't multi-component,
there's *probably* only a pointer at the beginning, so fixing that
*might* not be extremely important.)
Here's a patch that should catch *some* of the places where the SMB
dissector doesn't check whether it's running past either the captured
length or the real length of the packet. Try that.
Index: print-smb.c
===================================================================
RCS file: /tcpdump/master/tcpdump/print-smb.c,v
retrieving revision 1.5
diff -c -r1.5 print-smb.c
*** print-smb.c 2000/01/19 05:17:13 1.5
--- print-smb.c 2000/12/03 22:17:06
***************
*** 719,724 ****
--- 719,726 ----
printf("flags=0x%x\n", flags);
case 0:
data = fdata(data,"NBT Session Packet\nFlags=[rw]\nLength=[rd]\n",data+4);
+ if (data == NULL)
+ break;
if (memcmp(data,"\377SMB",4)==0) {
if (nbt_len>PTR_DIFF(maxbuf,data))
printf("WARNING: Short packet. Try increasing the snap length (%ld)\n",
***************
*** 845,850 ****
--- 847,854 ----
printf("QuestionRecords:\n");
for (i=0;i<qdcount;i++)
p = fdata(p,"|Name=[n1]\nQuestionType=[rw]\nQuestionClass=[rw]\n#",maxbuf);
+ if (p == NULL)
+ goto out;
}
if (total) {
***************
*** 853,869 ****
--- 857,881 ----
int rdlen;
int restype;
p = fdata(p,"Name=[n1]\n#",maxbuf);
+ if (p == NULL)
+ goto out;
restype = RSVAL(p,0);
p = fdata(p,"ResType=[rw]\nResClass=[rw]\nTTL=[rD]\n",p+8);
+ if (p == NULL)
+ goto out;
rdlen = RSVAL(p,0);
printf("ResourceLength=%d\nResourceData=\n",rdlen);
p += 2;
if (rdlen == 6) {
p = fdata(p,"AddrType=[rw]\nAddress=[b.b.b.b]\n",p+rdlen);
+ if (p == NULL)
+ goto out;
} else {
if (restype == 0x21) {
int numnames = CVAL(p,0);
p = fdata(p,"NumNames=[B]\n",p+1);
+ if (p == NULL)
+ goto out;
while (numnames--) {
p = fdata(p,"Name=[n2]\t#",maxbuf);
if (p[0] & 0x80) printf("<GROUP> ");
***************
*** 893,898 ****
--- 905,911 ----
fdata(p,"AdditionalData:\n",maxbuf);
}
+ out:
printf("\n");
fflush(stdout);
}
***************
*** 910,916 ****
data = fdata(data,"\n>>> NBT UDP PACKET(138) Res=[rw] ID=[rw] IP=[b.b.b.b]
Port=[rd] Length=[rd] Res2=[rw]\nSourceName=[n1]\nDestName=[n1]\n#",maxbuf);
! print_smb(data,maxbuf);
printf("\n");
fflush(stdout);
--- 923,930 ----
data = fdata(data,"\n>>> NBT UDP PACKET(138) Res=[rw] ID=[rw] IP=[b.b.b.b]
Port=[rd] Length=[rd] Res2=[rw]\nSourceName=[n1]\nDestName=[n1]\n#",maxbuf);
! if (data != NULL)
! print_smb(data,maxbuf);
printf("\n");
fflush(stdout);
***************
*** 930,935 ****
--- 944,951 ----
startbuf = data;
data = fdata(data,"\n>>> NetBeui Packet\nType=[B] Length=[d] Signature=[w]
Command=[B]\n#",maxbuf);
+ if (data == NULL)
+ goto out;
switch (command) {
case 0xA:
***************
*** 968,973 ****
--- 984,991 ----
data = fdata(data,"Unknown Netbios Command ",data2);
break;
}
+ if (data == NULL)
+ goto out;
if (memcmp(data2,"\377SMB",4)==0) {
print_smb(data2,maxbuf);
***************
*** 982,987 ****
--- 1000,1006 ----
}
}
+ out:
printf("\n");
}
***************
*** 997,1003 ****
for (i=0;i<128;i++)
if (memcmp(&data[i],"\377SMB",4)==0) {
fdata(data,"\n>>> IPX transport ",&data[i]);
! print_smb(&data[i],maxbuf);
printf("\n");
fflush(stdout);
break;
--- 1016,1023 ----
for (i=0;i<128;i++)
if (memcmp(&data[i],"\377SMB",4)==0) {
fdata(data,"\n>>> IPX transport ",&data[i]);
! if (data != NULL)
! print_smb(&data[i],maxbuf);
printf("\n");
fflush(stdout);
break;
Index: smbutil.c
===================================================================
RCS file: /tcpdump/master/tcpdump/smbutil.c,v
retrieving revision 1.11
diff -c -r1.11 smbutil.c
*** smbutil.c 2000/09/28 06:43:09 1.11
--- smbutil.c 2000/12/03 22:17:07
***************
*** 31,37 ****
#include "interface.h"
#include "smb.h"
! extern uchar *startbuf;
/*******************************************************************
interpret a 32 bit dos packed date/time to some parameters
--- 31,37 ----
#include "interface.h"
#include "smb.h"
! extern const uchar *startbuf;
/*******************************************************************
interpret a 32 bit dos packed date/time to some parameters
***************
*** 114,125 ****
/****************************************************************************
! interpret the weird netbios "name". Return the name type
****************************************************************************/
! static int name_interpret(char *in,char *out)
{
int ret;
! int len = (*in++) / 2;
*out=0;
--- 114,131 ----
/****************************************************************************
! interpret the weird netbios "name". Return the name type, or -1 if
! we run past the end of the buffer
****************************************************************************/
! static int name_interpret(const uchar *in,const uchar *maxbuf,char *out)
{
int ret;
! int len;
!
! if (in >= maxbuf)
! return(-1); /* name goes past the end of the buffer */
! TCHECK2(*in, 1);
! len = (*in++) / 2;
*out=0;
***************
*** 127,132 ****
--- 133,141 ----
while (len--)
{
+ if (in + 1 >= maxbuf)
+ return(-1); /* name goes past the end of the buffer */
+ TCHECK2(*in, 2);
if (in[0] < 'A' || in[0] > 'P' || in[1] < 'A' || in[1] > 'P') {
*out = 0;
return(0);
***************
*** 139,184 ****
ret = out[-1];
return(ret);
}
/****************************************************************************
find a pointer to a netbios name
****************************************************************************/
! static char *name_ptr(char *buf,int ofs)
{
! unsigned char c = *(unsigned char *)(buf+ofs);
if ((c & 0xC0) == 0xC0)
{
uint16 l = RSVAL(buf, ofs) & 0x3FFF;
return(buf + l);
}
else
return(buf+ofs);
}
/****************************************************************************
extract a netbios name from a buf
****************************************************************************/
! static int name_extract(char *buf,int ofs,char *name)
{
! char *p = name_ptr(buf,ofs);
strcpy(name,"");
! return(name_interpret(p,name));
}
/****************************************************************************
return the total storage length of a mangled name
****************************************************************************/
! static int name_len(const unsigned char *s)
{
! const char *s0 = s;
! unsigned char c = *(unsigned char *)s;
if ((c & 0xC0) == 0xC0)
! return(2);
! while (*s) s += (*s)+1;
return(PTR_DIFF(s,s0)+1);
}
static void print_asc(const unsigned char *buf,int len)
--- 148,233 ----
ret = out[-1];
return(ret);
+
+ trunc:
+ return(-1);
}
/****************************************************************************
find a pointer to a netbios name
****************************************************************************/
! static const uchar *name_ptr(const uchar *buf,int ofs,const uchar *maxbuf)
{
! const uchar *p;
! uchar c;
!
! p = buf+ofs;
! if (p >= maxbuf)
! return(NULL); /* name goes past the end of the buffer */
! TCHECK2(*p, 1);
+ c = *p;
+
+ /* XXX - this should use the same code that the DNS dissector does */
if ((c & 0xC0) == 0xC0)
{
uint16 l = RSVAL(buf, ofs) & 0x3FFF;
+ if (l == 0)
+ {
+ /* We have a pointer that points to itself. */
+ return(NULL);
+ }
+ p = buf + l;
+ if (p >= maxbuf)
+ return(NULL); /* name goes past the end of the buffer */
+ TCHECK2(*p, 1);
return(buf + l);
}
else
return(buf+ofs);
+
+ trunc:
+ return(NULL); /* name goes past the end of the buffer */
}
/****************************************************************************
extract a netbios name from a buf
****************************************************************************/
! static int name_extract(const uchar *buf,int ofs,const uchar *maxbuf,char *name)
{
! const uchar *p = name_ptr(buf,ofs,maxbuf);
! if (p == NULL)
! return(-1); /* error (probably name going past end of buffer) */
strcpy(name,"");
! return(name_interpret(p,maxbuf,name));
}
/****************************************************************************
return the total storage length of a mangled name
****************************************************************************/
! static int name_len(const unsigned char *s, const unsigned char *maxbuf)
{
! const unsigned char *s0 = s;
! unsigned char c;
!
! if (s >= maxbuf)
! return(-1); /* name goes past the end of the buffer */
! TCHECK2(*s, 1);
! c = *s;
if ((c & 0xC0) == 0xC0)
! return(2);
! while (*s)
! {
! if (s >= maxbuf)
! return(-1); /* name goes past the end of the buffer */
! TCHECK2(*s, 1);
! s += (*s)+1;
! }
return(PTR_DIFF(s,s0)+1);
+
+ trunc:
+ return(-1); /* name goes past the end of the buffer */
}
static void print_asc(const unsigned char *buf,int len)
***************
*** 428,437 ****
int t = atoi(fmt+1);
char nbuf[255];
int name_type;
switch (t) {
case 1:
! name_type = name_extract(startbuf,PTR_DIFF(buf,startbuf),nbuf);
! buf += name_len(buf);
printf("%-15.15s NameType=0x%02X (%s)",
nbuf,name_type,name_type_str(name_type));
break;
--- 477,493 ----
int t = atoi(fmt+1);
char nbuf[255];
int name_type;
+ int len;
switch (t) {
case 1:
! name_type = name_extract(startbuf,PTR_DIFF(buf,startbuf),maxbuf,
! nbuf);
! if (name_type < 0)
! goto trunc;
! len = name_len(buf,maxbuf);
! if (len < 0)
! goto trunc;
! buf += len;
printf("%-15.15s NameType=0x%02X (%s)",
nbuf,name_type,name_type_str(name_type));
break;
***************
*** 484,489 ****
--- 540,550 ----
printf("END OF BUFFER\n");
return(buf);
+
+ trunc:
+ printf("\n");
+ printf("WARNING: Short packet. Try increasing the snap length\n");
+ return(NULL);
}
const uchar *fdata(const uchar *buf, const char *fmt, const uchar *maxbuf)
***************
*** 529,534 ****
--- 590,597 ----
strncpy(s,fmt,p-fmt);
fmt = p+1;
buf = fdata1(buf,s,maxbuf);
+ if (buf == NULL)
+ return(NULL);
break;
default:
***************
*** 692,697 ****
snprintf(ret,sizeof(ret),"ERROR: Unknown error (%d,%d)",class,num);
return(ret);
}
-
-
-
--- 755,757 ----