summaryrefslogtreecommitdiffstats
path: root/sys/netinet/libalias/alias_nbt.c
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1998-12-14 02:25:32 +0000
committerdillon <dillon@FreeBSD.org>1998-12-14 02:25:32 +0000
commit14901c04b79cb17c3c64e0f387e5bf232548c4f1 (patch)
tree944aea4f0c97efa78bd8751707f0852d6ebb930b /sys/netinet/libalias/alias_nbt.c
parent95f78d45621446ffbafb1a53dc3294659c10152a (diff)
downloadFreeBSD-src-14901c04b79cb17c3c64e0f387e5bf232548c4f1.zip
FreeBSD-src-14901c04b79cb17c3c64e0f387e5bf232548c4f1.tar.gz
Reviewed by: freebsd-current
Add bounds checking to netbios NS packet resolving code. This should prevent natd from crashing on badly formed netbios packets (as might be heard when the machine is sitting on a cable modem or certain DSL networks), and also closes potential security holes that might have exploited the lack of bounds checking in the previous version of the code.
Diffstat (limited to 'sys/netinet/libalias/alias_nbt.c')
-rw-r--r--sys/netinet/libalias/alias_nbt.c215
1 files changed, 176 insertions, 39 deletions
diff --git a/sys/netinet/libalias/alias_nbt.c b/sys/netinet/libalias/alias_nbt.c
index f3581a7..cd07431 100644
--- a/sys/netinet/libalias/alias_nbt.c
+++ b/sys/netinet/libalias/alias_nbt.c
@@ -15,7 +15,7 @@
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * $Id:$
+ * $Id: alias_nbt.c,v 1.1 1998/05/24 03:03:10 amurai Exp $
*
* TODO:
* oClean up.
@@ -132,15 +132,21 @@ void PrintRcode( u_char rcode ) {
/* Handling Name field */
-u_char *AliasHandleName ( u_char *p ) {
+u_char *AliasHandleName ( u_char *p, char *pmax ) {
u_char *s;
u_char c;
int compress;
/* Following length field */
+
+ if (p == NULL || (char *)p >= pmax)
+ return(NULL);
+
if (*p & 0xc0 ) {
p = p + 2;
+ if ((char *)p > pmax)
+ return(NULL);
return ((u_char *)p);
}
while ( ( *p & 0x3f) != 0x00 ) {
@@ -152,6 +158,10 @@ u_char *AliasHandleName ( u_char *p ) {
/* Get next length field */
p = (u_char *)(p + (*p & 0x3f) + 1);
+ if ((char *)p > pmax) {
+ p = NULL;
+ break;
+ }
#ifdef DEBUG
printf(":");
#endif
@@ -179,7 +189,10 @@ u_char *AliasHandleName ( u_char *p ) {
}
/* Set up to out of Name field */
- p++;
+ if (p == NULL || (char *)p >= pmax)
+ p = NULL;
+ else
+ p++;
return ((u_char *)p);
}
@@ -194,19 +207,24 @@ u_char *AliasHandleName ( u_char *p ) {
#define DGM_POSITIVE_RES 0x15
#define DGM_NEGATIVE_RES 0x16
-void AliasHandleUdpNbt(
+int AliasHandleUdpNbt(
struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
- u_short alias_port )
-{
+ u_short alias_port
+) {
struct udphdr * uh;
NbtDataHeader *ndh;
- u_char *p;
+ u_char *p = NULL;
+ char *pmax;
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
+ pmax = (char *)uh + ntohs( uh->uh_ulen );
+
ndh = (NbtDataHeader *)((char *)uh + (sizeof (struct udphdr)));
+ if ((char *)(ndh + 1) > pmax)
+ return(-1);
#ifdef DEBUG
printf("\nType=%02x,", ndh->type );
#endif
@@ -215,8 +233,8 @@ void AliasHandleUdpNbt(
case DGM_DIRECT_GROUP:
case DGM_BROADCAST:
p = (u_char *)ndh + 14;
- p = AliasHandleName ( p ); /* Source Name */
- p = AliasHandleName ( p ); /* Destination Name */
+ p = AliasHandleName ( p, pmax ); /* Source Name */
+ p = AliasHandleName ( p, pmax ); /* Destination Name */
break;
case DGM_ERROR:
p = (u_char *)ndh + 11;
@@ -225,9 +243,11 @@ void AliasHandleUdpNbt(
case DGM_POSITIVE_RES:
case DGM_NEGATIVE_RES:
p = (u_char *)ndh + 10;
- p = AliasHandleName ( p ); /* Destination Name */
+ p = AliasHandleName ( p, pmax ); /* Destination Name */
break;
}
+ if (p == NULL || (char *)p > pmax)
+ p = NULL;
#ifdef DEBUG
printf("%s:%d-->", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
#endif
@@ -251,6 +271,7 @@ void AliasHandleUdpNbt(
printf("%s:%d\n", inet_ntoa(ndh->source_ip), ntohs(ndh->source_port) );
fflush(stdout);
#endif
+ return((p == NULL) ? -1 : 0);
}
/* Question Section */
#define QS_TYPE_NB 0x0020
@@ -261,14 +282,22 @@ typedef struct {
u_short class; /* The class of Request */
} NBTNsQuestion;
-u_char *AliasHandleQuestion(u_short count,
+u_char *
+AliasHandleQuestion(
+ u_short count,
NBTNsQuestion *q,
+ char *pmax,
NBTArguments *nbtarg)
{
while ( count != 0 ) {
/* Name Filed */
- q = (NBTNsQuestion *)AliasHandleName((u_char *)q );
+ q = (NBTNsQuestion *)AliasHandleName((u_char *)q, pmax);
+
+ if (q == NULL || (char *)(q + 1) > pmax) {
+ q = NULL;
+ break;
+ }
/* Type and Class filed */
switch ( ntohs(q->type) ) {
@@ -308,12 +337,17 @@ typedef struct {
struct in_addr addr;
} NBTNsRNB;
-u_char *AliasHandleResourceNB( NBTNsResource *q,
+u_char *
+AliasHandleResourceNB(
+ NBTNsResource *q,
+ char *pmax,
NBTArguments *nbtarg)
{
NBTNsRNB *nb;
u_short bcount;
+ if (q == NULL || (char *)(q + 1) > pmax)
+ return(NULL);
/* Check out a length */
bcount = ntohs(q->rdlen);
@@ -325,7 +359,11 @@ u_char *AliasHandleResourceNB( NBTNsResource *q,
printf("NB rec[%s", inet_ntoa(nbtarg->oldaddr));
printf("->%s, %dbytes] ",inet_ntoa(nbtarg->newaddr ), bcount);
#endif
- while ( bcount != 0 ) {
+ while ( nb != NULL && bcount != 0 ) {
+ if ((char *)(nb + 1) > pmax) {
+ nb = NULL;
+ break;
+ }
#ifdef DEBUG
printf("<%s>", inet_ntoa(nb->addr) );
#endif
@@ -356,6 +394,9 @@ u_char *AliasHandleResourceNB( NBTNsResource *q,
nb=(NBTNsRNB *)((u_char *)nb + SizeOfNsRNB);
bcount -= SizeOfNsRNB;
}
+ if (nb == NULL || (char *)(nb + 1) > pmax) {
+ nb = NULL;
+ }
return ((u_char *)nb);
}
@@ -365,12 +406,18 @@ typedef struct {
struct in_addr addr;
} NBTNsResourceA;
-u_char *AliasHandleResourceA( NBTNsResource *q,
+u_char *
+AliasHandleResourceA(
+ NBTNsResource *q,
+ char *pmax,
NBTArguments *nbtarg)
{
NBTNsResourceA *a;
u_short bcount;
+ if (q == NULL || (char *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource A position */
a = (NBTNsResourceA *)( (u_char *)q + sizeof(NBTNsResource) );
@@ -383,6 +430,8 @@ u_char *AliasHandleResourceA( NBTNsResource *q,
printf("->%s]",inet_ntoa(nbtarg->newaddr ));
#endif
while ( bcount != 0 ) {
+ if (a == NULL || (char *)(a + 1) > pmax)
+ return(NULL);
#ifdef DEBUG
printf("..%s", inet_ntoa(a->addr) );
#endif
@@ -405,6 +454,8 @@ u_char *AliasHandleResourceA( NBTNsResource *q,
a++; /*XXXX*/
bcount -= SizeOfResourceA;
}
+ if (a == NULL || (char *)(a + 1) > pmax)
+ a = NULL;
return ((u_char *)a);
}
@@ -412,12 +463,18 @@ typedef struct {
u_short opcode:4, flags:8, resv:4;
} NBTNsResourceNULL;
-u_char *AliasHandleResourceNULL( NBTNsResource *q,
+u_char *
+AliasHandleResourceNULL(
+ NBTNsResource *q,
+ char *pmax,
NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
+ if (q == NULL || (char *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
@@ -426,19 +483,31 @@ u_char *AliasHandleResourceNULL( NBTNsResource *q,
/* Processing all in_addr array */
while ( bcount != 0 ) {
+ if ((char *)(n + 1) > pmax) {
+ n = NULL;
+ break;
+ }
n++;
bcount -= sizeof(NBTNsResourceNULL);
}
+ if ((char *)(n + 1) > pmax)
+ n = NULL;
return ((u_char *)n);
}
-u_char *AliasHandleResourceNS( NBTNsResource *q,
+u_char *
+AliasHandleResourceNS(
+ NBTNsResource *q,
+ char *pmax,
NBTArguments *nbtarg)
{
NBTNsResourceNULL *n;
u_short bcount;
+ if (q == NULL || (char *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource NULL position */
n = (NBTNsResourceNULL *)( (u_char *)q + sizeof(NBTNsResource) );
@@ -446,8 +515,11 @@ u_char *AliasHandleResourceNS( NBTNsResource *q,
bcount = ntohs(q->rdlen);
/* Resource Record Name Filed */
- q = (NBTNsResource *)AliasHandleName( (u_char *)n ); /* XXX */
+ q = (NBTNsResource *)AliasHandleName( (u_char *)n, pmax ); /* XXX */
+ if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
+ return(NULL);
+ else
return ((u_char *)n + bcount);
}
@@ -455,28 +527,44 @@ typedef struct {
u_short numnames;
} NBTNsResourceNBSTAT;
-u_char *AliasHandleResourceNBSTAT( NBTNsResource *q,
+u_char *
+AliasHandleResourceNBSTAT(
+ NBTNsResource *q,
+ char *pmax,
NBTArguments *nbtarg)
{
NBTNsResourceNBSTAT *n;
u_short bcount;
+ if (q == NULL || (char *)(q + 1) > pmax)
+ return(NULL);
+
/* Forward to Resource NBSTAT position */
n = (NBTNsResourceNBSTAT *)( (u_char *)q + sizeof(NBTNsResource) );
/* Check out of length */
bcount = ntohs(q->rdlen);
+ if (q == NULL || (char *)((u_char *)n + bcount) > pmax)
+ return(NULL);
+ else
return ((u_char *)n + bcount);
}
-u_char *AliasHandleResource(u_short count,
+u_char *
+AliasHandleResource(
+ u_short count,
NBTNsResource *q,
- NBTArguments *nbtarg)
+ char *pmax,
+ NBTArguments
+ *nbtarg)
{
while ( count != 0 ) {
/* Resource Record Name Filed */
- q = (NBTNsResource *)AliasHandleName( (u_char *)q );
+ q = (NBTNsResource *)AliasHandleName( (u_char *)q, pmax );
+
+ if (q == NULL || (char *)(q + 1) > pmax)
+ break;
#ifdef DEBUG
printf("type=%02x, count=%d\n", ntohs(q->type), count );
#endif
@@ -484,22 +572,45 @@ u_char *AliasHandleResource(u_short count,
/* Type and Class filed */
switch ( ntohs(q->type) ) {
case RR_TYPE_NB:
- q = (NBTNsResource *)AliasHandleResourceNB( q, nbtarg );
+ q = (NBTNsResource *)AliasHandleResourceNB(
+ q,
+ pmax,
+ nbtarg
+ );
break;
case RR_TYPE_A:
- q = (NBTNsResource *)AliasHandleResourceA( q, nbtarg );
+ q = (NBTNsResource *)AliasHandleResourceA(
+ q,
+ pmax,
+ nbtarg
+ );
break;
case RR_TYPE_NS:
- q = (NBTNsResource *)AliasHandleResourceNS( q, nbtarg );
+ q = (NBTNsResource *)AliasHandleResourceNS(
+ q,
+ pmax,
+ nbtarg
+ );
break;
case RR_TYPE_NULL:
- q = (NBTNsResource *)AliasHandleResourceNULL( q, nbtarg );
+ q = (NBTNsResource *)AliasHandleResourceNULL(
+ q,
+ pmax,
+ nbtarg
+ );
break;
case RR_TYPE_NBSTAT:
- q = (NBTNsResource *)AliasHandleResourceNBSTAT( q, nbtarg );
+ q = (NBTNsResource *)AliasHandleResourceNBSTAT(
+ q,
+ pmax,
+ nbtarg
+ );
break;
- default: printf("\nUnknown Type of Resource %0x\n",
- ntohs(q->type) );
+ default:
+ printf(
+ "\nUnknown Type of Resource %0x\n",
+ ntohs(q->type)
+ );
break;
}
count--;
@@ -508,7 +619,7 @@ u_char *AliasHandleResource(u_short count,
return ((u_char *)q);
}
-void AliasHandleUdpNbtNS(
+int AliasHandleUdpNbtNS(
struct ip *pip, /* IP packet to examine/patch */
struct alias_link *link,
struct in_addr *alias_address,
@@ -518,8 +629,8 @@ void AliasHandleUdpNbtNS(
{
struct udphdr * uh;
NbtNSHeader * nsh;
- u_short dlen;
u_char * p;
+ char *pmax;
NBTArguments nbtarg;
/* Set up Common Parameter */
@@ -531,12 +642,16 @@ void AliasHandleUdpNbtNS(
/* Calculate data length of UDP packet */
uh = (struct udphdr *) ((char *) pip + (pip->ip_hl << 2));
nbtarg.uh_sum = &(uh->uh_sum);
- dlen = ntohs( uh->uh_ulen );
nsh = (NbtNSHeader *)((char *)uh + (sizeof(struct udphdr)));
p = (u_char *)(nsh + 1);
+ pmax = (char *)uh + ntohs( uh->uh_ulen );
+
+ if ((char *)(nsh + 1) > pmax)
+ return(-1);
#ifdef DEBUG
- printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x, an=%04x, ns=%04x, ar=%04x, [%d]-->",
+ printf(" [%s] ID=%02x, op=%01x, flag=%02x, rcode=%01x, qd=%04x"
+ ", an=%04x, ns=%04x, ar=%04x, [%d]-->",
nsh->dir ? "Response": "Request",
nsh->nametrid,
nsh->opcode,
@@ -546,31 +661,53 @@ void AliasHandleUdpNbtNS(
ntohs(nsh->ancount),
ntohs(nsh->nscount),
ntohs(nsh->arcount),
- (u_char *)p -(u_char *)nsh);
+ (u_char *)p -(u_char *)nsh
+ );
#endif
/* Question Entries */
if (ntohs(nsh->qdcount) !=0 ) {
- p = AliasHandleQuestion(ntohs(nsh->qdcount), (NBTNsQuestion *)p, &nbtarg );
+ p = AliasHandleQuestion(
+ ntohs(nsh->qdcount),
+ (NBTNsQuestion *)p,
+ pmax,
+ &nbtarg
+ );
}
/* Answer Resource Records */
if (ntohs(nsh->ancount) !=0 ) {
- p = AliasHandleResource(ntohs(nsh->ancount), (NBTNsResource *)p, &nbtarg );
+ p = AliasHandleResource(
+ ntohs(nsh->ancount),
+ (NBTNsResource *)p,
+ pmax,
+ &nbtarg
+ );
}
/* Authority Resource Recodrs */
if (ntohs(nsh->nscount) !=0 ) {
- p = AliasHandleResource(ntohs(nsh->nscount), (NBTNsResource *)p, &nbtarg );
+ p = AliasHandleResource(
+ ntohs(nsh->nscount),
+ (NBTNsResource *)p,
+ pmax,
+ &nbtarg
+ );
}
/* Additional Resource Recodrs */
if (ntohs(nsh->arcount) !=0 ) {
- p = AliasHandleResource(ntohs(nsh->arcount), (NBTNsResource *)p, &nbtarg );
+ p = AliasHandleResource(
+ ntohs(nsh->arcount),
+ (NBTNsResource *)p,
+ pmax,
+ &nbtarg
+ );
}
#ifdef DEBUG
PrintRcode(nsh->rcode);
#endif
- return;
+ return ((p == NULL) ? -1 : 0);
}
+
OpenPOWER on IntegriCloud