Add a bunch of bounds checks.

Don't bother copying the route header - we're using the EXTRACT_ macros,
so we don't have to worry about alignment.

Use the length field from the packet, not just the length of the
containing packet, and check to make sure the containing packet is long
enough to contain it.

Add a bunch of checks against the packet length.

In "default_print()" calls, cut the length off at the captured data
length.  In other calls, don't - let the bounds checks handle caplen <
length.
This commit is contained in:
guy 2005-05-06 02:16:26 +00:00
parent 1324704138
commit f616391792

View File

@ -21,7 +21,7 @@
#ifndef lint
static const char rcsid[] _U_ =
"@(#) $Header: /tcpdump/master/tcpdump/print-decnet.c,v 1.38 2003-11-16 09:36:17 guy Exp $ (LBL)";
"@(#) $Header: /tcpdump/master/tcpdump/print-decnet.c,v 1.39 2005-05-06 02:16:26 guy Exp $ (LBL)";
#endif
#ifdef HAVE_CONFIG_H
@ -47,13 +47,13 @@ struct rtentry;
#include "addrtoname.h"
/* Forwards */
static void print_decnet_ctlmsg(const union routehdr *, u_int);
static int print_decnet_ctlmsg(const union routehdr *, u_int, u_int);
static void print_t_info(int);
static void print_l1_routes(const char *, u_int);
static void print_l2_routes(const char *, u_int);
static int print_l1_routes(const char *, u_int);
static int print_l2_routes(const char *, u_int);
static void print_i_info(int);
static void print_elist(const char *, u_int);
static void print_nsp(const u_char *, u_int);
static int print_elist(const char *, u_int);
static int print_nsp(const u_char *, u_int);
static void print_reason(int);
#ifdef PRINT_NSPDATA
static void pdata(u_char *, int);
@ -67,11 +67,10 @@ void
decnet_print(register const u_char *ap, register u_int length,
register u_int caplen)
{
static union routehdr rhcopy;
register union routehdr *rhp = &rhcopy;
register const union routehdr *rhp;
register int mflags;
int dst, src, hops;
u_int rhlen, nsplen, pktlen;
u_int nsplen, pktlen;
const u_char *nspp;
if (length < sizeof(struct shorthdr)) {
@ -79,12 +78,20 @@ decnet_print(register const u_char *ap, register u_int length,
return;
}
TCHECK2(*ap, sizeof(short));
pktlen = EXTRACT_LE_16BITS(ap);
if (pktlen < sizeof(struct shorthdr)) {
(void)printf("[|decnet]");
return;
}
if (pktlen > length) {
(void)printf("[|decnet]");
return;
}
length = pktlen;
rhlen = min(length, caplen);
rhlen = min(rhlen, sizeof(*rhp));
memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen);
rhp = (const union routehdr *)&(ap[sizeof(short)]);
TCHECK(rhp->rh_short.sh_flags);
mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
if (mflags & RMF_PAD) {
@ -92,49 +99,57 @@ decnet_print(register const u_char *ap, register u_int length,
u_int padlen = mflags & RMF_PADMASK;
if (vflag)
(void) printf("[pad:%d] ", padlen);
if (length < padlen + 2) {
(void)printf("[|decnet]");
return;
}
TCHECK2(ap[sizeof(short)], padlen);
ap += padlen;
length -= padlen;
caplen -= padlen;
rhlen = min(length, caplen);
rhlen = min(rhlen, sizeof(*rhp));
memcpy((char *)rhp, (char *)&(ap[sizeof(short)]), rhlen);
rhp = (const union routehdr *)&(ap[sizeof(short)]);
mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
}
if (mflags & RMF_FVER) {
(void) printf("future-version-decnet");
default_print(ap, length);
default_print(ap, min(length, caplen));
return;
}
/* is it a control message? */
if (mflags & RMF_CTLMSG) {
print_decnet_ctlmsg(rhp, min(length, caplen));
if (!print_decnet_ctlmsg(rhp, length, caplen))
goto trunc;
return;
}
switch (mflags & RMF_MASK) {
case RMF_LONG:
if (length < sizeof(struct longhdr)) {
(void)printf("[|decnet]");
return;
}
TCHECK(rhp->rh_long);
dst =
EXTRACT_LE_16BITS(rhp->rh_long.lg_dst.dne_remote.dne_nodeaddr);
src =
EXTRACT_LE_16BITS(rhp->rh_long.lg_src.dne_remote.dne_nodeaddr);
hops = EXTRACT_LE_8BITS(rhp->rh_long.lg_visits);
nspp = &(ap[sizeof(short) + sizeof(struct longhdr)]);
nsplen = min((length - sizeof(struct longhdr)),
(caplen - sizeof(struct longhdr)));
nsplen = length - sizeof(struct longhdr);
break;
case RMF_SHORT:
TCHECK(rhp->rh_short);
dst = EXTRACT_LE_16BITS(rhp->rh_short.sh_dst);
src = EXTRACT_LE_16BITS(rhp->rh_short.sh_src);
hops = (EXTRACT_LE_8BITS(rhp->rh_short.sh_visits) & VIS_MASK)+1;
nspp = &(ap[sizeof(short) + sizeof(struct shorthdr)]);
nsplen = min((length - sizeof(struct shorthdr)),
(caplen - sizeof(struct shorthdr)));
nsplen = length - sizeof(struct shorthdr);
break;
default:
(void) printf("unknown message flags under mask");
default_print((u_char *)ap, length);
default_print((u_char *)ap, min(length, caplen));
return;
}
@ -150,11 +165,18 @@ decnet_print(register const u_char *ap, register u_int length,
(void)printf("%d hops ", hops);
}
print_nsp(nspp, nsplen);
if (!print_nsp(nspp, nsplen))
goto trunc;
return;
trunc:
(void)printf("[|decnet]");
return;
}
static void
print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
static int
print_decnet_ctlmsg(register const union routehdr *rhp, u_int length,
u_int caplen)
{
int mflags = EXTRACT_LE_8BITS(rhp->rh_short.sh_flags);
register union controlmsg *cmp = (union controlmsg *)rhp;
@ -162,10 +184,14 @@ print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
etheraddr srcea, rtea;
int priority;
char *rhpx = (char *)rhp;
int ret;
switch (mflags & RMF_CTLMASK) {
case RMF_INIT:
(void)printf("init ");
if (length < sizeof(struct initmsg))
goto trunc;
TCHECK(cmp->cm_init);
src = EXTRACT_LE_16BITS(cmp->cm_init.in_src);
info = EXTRACT_LE_8BITS(cmp->cm_init.in_info);
blksize = EXTRACT_LE_16BITS(cmp->cm_init.in_blksize);
@ -178,35 +204,53 @@ print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
"src %sblksize %d vers %d eco %d ueco %d hello %d",
dnaddr_string(src), blksize, vers, eco, ueco,
hello);
ret = 1;
break;
case RMF_VER:
(void)printf("verification ");
if (length < sizeof(struct verifmsg))
goto trunc;
TCHECK(cmp->cm_ver);
src = EXTRACT_LE_16BITS(cmp->cm_ver.ve_src);
other = EXTRACT_LE_8BITS(cmp->cm_ver.ve_fcnval);
(void)printf("src %s fcnval %o", dnaddr_string(src), other);
ret = 1;
break;
case RMF_TEST:
(void)printf("test ");
if (length < sizeof(struct testmsg))
goto trunc;
TCHECK(cmp->cm_test);
src = EXTRACT_LE_16BITS(cmp->cm_test.te_src);
other = EXTRACT_LE_8BITS(cmp->cm_test.te_data);
(void)printf("src %s data %o", dnaddr_string(src), other);
ret = 1;
break;
case RMF_L1ROUT:
(void)printf("lev-1-routing ");
if (length < sizeof(struct l1rout))
goto trunc;
TCHECK(cmp->cm_l1rou);
src = EXTRACT_LE_16BITS(cmp->cm_l1rou.r1_src);
(void)printf("src %s ", dnaddr_string(src));
print_l1_routes(&(rhpx[sizeof(struct l1rout)]),
ret = print_l1_routes(&(rhpx[sizeof(struct l1rout)]),
length - sizeof(struct l1rout));
break;
case RMF_L2ROUT:
(void)printf("lev-2-routing ");
if (length < sizeof(struct l2rout))
goto trunc;
TCHECK(cmp->cm_l2rout);
src = EXTRACT_LE_16BITS(cmp->cm_l2rout.r2_src);
(void)printf("src %s ", dnaddr_string(src));
print_l2_routes(&(rhpx[sizeof(struct l2rout)]),
ret = print_l2_routes(&(rhpx[sizeof(struct l2rout)]),
length - sizeof(struct l2rout));
break;
case RMF_RHELLO:
(void)printf("router-hello ");
if (length < sizeof(struct rhellomsg))
goto trunc;
TCHECK(cmp->cm_rhello);
vers = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_vers);
eco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_eco);
ueco = EXTRACT_LE_8BITS(cmp->cm_rhello.rh_ueco);
@ -222,11 +266,14 @@ print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
"vers %d eco %d ueco %d src %s blksize %d pri %d hello %d",
vers, eco, ueco, dnaddr_string(src),
blksize, priority, hello);
print_elist(&(rhpx[sizeof(struct rhellomsg)]),
ret = print_elist(&(rhpx[sizeof(struct rhellomsg)]),
length - sizeof(struct rhellomsg));
break;
case RMF_EHELLO:
(void)printf("endnode-hello ");
if (length < sizeof(struct ehellomsg))
goto trunc;
TCHECK(cmp->cm_ehello);
vers = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_vers);
eco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_eco);
ueco = EXTRACT_LE_8BITS(cmp->cm_ehello.eh_ueco);
@ -246,13 +293,19 @@ print_decnet_ctlmsg(register const union routehdr *rhp, u_int length)
"vers %d eco %d ueco %d src %s blksize %d rtr %s hello %d data %o",
vers, eco, ueco, dnaddr_string(src),
blksize, dnaddr_string(dst), hello, other);
ret = 1;
break;
default:
(void)printf("unknown control message");
default_print((u_char *)rhp, length);
default_print((u_char *)rhp, min(length, caplen));
ret = 1;
break;
}
return (ret);
trunc:
return (0);
}
static void
@ -271,7 +324,7 @@ print_t_info(int info)
(void)printf("blo ");
}
static void
static int
print_l1_routes(const char *rp, u_int len)
{
int count;
@ -280,9 +333,10 @@ print_l1_routes(const char *rp, u_int len)
/* The last short is a checksum */
while (len > (3 * sizeof(short))) {
TCHECK2(*rp, 3 * sizeof(short));
count = EXTRACT_LE_16BITS(rp);
if (count > 1024)
return; /* seems to be bogus from here on */
return (1); /* seems to be bogus from here on */
rp += sizeof(short);
len -= sizeof(short);
id = EXTRACT_LE_16BITS(rp);
@ -294,9 +348,13 @@ print_l1_routes(const char *rp, u_int len)
(void)printf("{ids %d-%d cost %d hops %d} ", id, id + count,
RI_COST(info), RI_HOPS(info));
}
return (1);
trunc:
return (0);
}
static void
static int
print_l2_routes(const char *rp, u_int len)
{
int count;
@ -305,9 +363,10 @@ print_l2_routes(const char *rp, u_int len)
/* The last short is a checksum */
while (len > (3 * sizeof(short))) {
TCHECK2(*rp, 3 * sizeof(short));
count = EXTRACT_LE_16BITS(rp);
if (count > 1024)
return; /* seems to be bogus from here on */
return (1); /* seems to be bogus from here on */
rp += sizeof(short);
len -= sizeof(short);
area = EXTRACT_LE_16BITS(rp);
@ -319,6 +378,10 @@ print_l2_routes(const char *rp, u_int len)
(void)printf("{areas %d-%d cost %d hops %d} ", area, area + count,
RI_COST(info), RI_HOPS(info));
}
return (1);
trunc:
return (0);
}
static void
@ -339,18 +402,22 @@ print_i_info(int info)
(void)printf("blo ");
}
static void
static int
print_elist(const char *elp _U_, u_int len _U_)
{
/* Not enough examples available for me to debug this */
return (1);
}
static void
print_nsp(const u_char *nspp, u_int nsplen _U_)
static int
print_nsp(const u_char *nspp, u_int nsplen)
{
const struct nsphdr *nsphp = (struct nsphdr *)nspp;
int dst, src, flags;
if (nsplen < sizeof(struct nsphdr))
goto trunc;
TCHECK(*nsphp);
flags = EXTRACT_LE_8BITS(nsphp->nh_flags);
dst = EXTRACT_LE_16BITS(nsphp->nh_dst);
src = EXTRACT_LE_16BITS(nsphp->nh_src);
@ -371,27 +438,39 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
#endif
u_int data_off = sizeof(struct minseghdr);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[0]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
if (ack & SGQ_ACK) { /* acknum field */
if ((ack & SGQ_NAK) == SGQ_NAK)
(void)printf("nak %d ", ack & SGQ_MASK);
else
(void)printf("ack %d ", ack & SGQ_MASK);
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
data_off += sizeof(short);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[1]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
if (ack & SGQ_OACK) { /* ackoth field */
if ((ack & SGQ_ONAK) == SGQ_ONAK)
(void)printf("onak %d ", ack & SGQ_MASK);
else
(void)printf("oack %d ", ack & SGQ_MASK);
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
data_off += sizeof(short);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[2]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
}
}
(void)printf("seg %d ", ack & SGQ_MASK);
#ifdef PRINT_NSPDATA
dp = &(nspp[data_off]);
pdata(dp, 10);
if (nsplen > data_off) {
dp = &(nspp[data_off]);
TCHECK2(*dp, nsplen - data_off);
pdata(dp, nsplen - data_off);
}
#endif
}
break;
@ -405,27 +484,39 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
#endif
u_int data_off = sizeof(struct minseghdr);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[0]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
if (ack & SGQ_ACK) { /* acknum field */
if ((ack & SGQ_NAK) == SGQ_NAK)
(void)printf("nak %d ", ack & SGQ_MASK);
else
(void)printf("ack %d ", ack & SGQ_MASK);
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
data_off += sizeof(short);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[1]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
if (ack & SGQ_OACK) { /* ackdat field */
if ((ack & SGQ_ONAK) == SGQ_ONAK)
(void)printf("nakdat %d ", ack & SGQ_MASK);
else
(void)printf("ackdat %d ", ack & SGQ_MASK);
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
data_off += sizeof(short);
if (nsplen < data_off)
goto trunc;
TCHECK(shp->sh_seq[2]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
}
}
(void)printf("seg %d ", ack & SGQ_MASK);
#ifdef PRINT_NSPDATA
dp = &(nspp[data_off]);
pdata(dp, 10);
if (nsplen > data_off) {
dp = &(nspp[data_off]);
TCHECK2(*dp, nsplen - data_off);
pdata(dp, nsplen - data_off);
}
#endif
}
break;
@ -438,22 +529,28 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
int ack;
int lsflags, fcval;
if (nsplen < sizeof(struct seghdr) + sizeof(struct lsmsg))
goto trunc;
TCHECK(shp->sh_seq[0]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[0]);
if (ack & SGQ_ACK) { /* acknum field */
if ((ack & SGQ_NAK) == SGQ_NAK)
(void)printf("nak %d ", ack & SGQ_MASK);
else
(void)printf("ack %d ", ack & SGQ_MASK);
TCHECK(shp->sh_seq[1]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[1]);
if (ack & SGQ_OACK) { /* ackdat field */
if ((ack & SGQ_ONAK) == SGQ_ONAK)
(void)printf("nakdat %d ", ack & SGQ_MASK);
else
(void)printf("ackdat %d ", ack & SGQ_MASK);
TCHECK(shp->sh_seq[2]);
ack = EXTRACT_LE_16BITS(shp->sh_seq[2]);
}
}
(void)printf("seg %d ", ack & SGQ_MASK);
TCHECK(*lsmp);
lsflags = EXTRACT_LE_8BITS(lsmp->ls_lsflags);
fcval = EXTRACT_LE_8BITS(lsmp->ls_fcval);
switch (lsflags & LSI_MASK) {
@ -495,6 +592,9 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
struct ackmsg *amp = (struct ackmsg *)nspp;
int ack;
if (nsplen < sizeof(struct ackmsg))
goto trunc;
TCHECK(*amp);
ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
if (ack & SGQ_ACK) { /* acknum field */
if ((ack & SGQ_NAK) == SGQ_NAK)
@ -517,12 +617,16 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
struct ackmsg *amp = (struct ackmsg *)nspp;
int ack;
if (nsplen < sizeof(struct ackmsg))
goto trunc;
TCHECK(*amp);
ack = EXTRACT_LE_16BITS(amp->ak_acknum[0]);
if (ack & SGQ_ACK) { /* acknum field */
if ((ack & SGQ_NAK) == SGQ_NAK)
(void)printf("nak %d ", ack & SGQ_MASK);
else
(void)printf("ack %d ", ack & SGQ_MASK);
TCHECK(amp->ak_acknum[1]);
ack = EXTRACT_LE_16BITS(amp->ak_acknum[1]);
if (ack & SGQ_OACK) { /* ackdat field */
if ((ack & SGQ_ONAK) == SGQ_ONAK)
@ -557,6 +661,9 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
u_char *dp;
#endif
if (nsplen < sizeof(struct cimsg))
goto trunc;
TCHECK(*cimp);
services = EXTRACT_LE_8BITS(cimp->ci_services);
info = EXTRACT_LE_8BITS(cimp->ci_info);
segsize = EXTRACT_LE_16BITS(cimp->ci_segsize);
@ -590,8 +697,11 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
}
(void)printf("segsize %d ", segsize);
#ifdef PRINT_NSPDATA
dp = &(nspp[sizeof(struct cimsg)]);
pdata(dp, nsplen - sizeof(struct cimsg));
if (nsplen > sizeof(struct cimsg)) {
dp = &(nspp[sizeof(struct cimsg)]);
TCHECK2(*dp, nsplen - sizeof(struct cimsg));
pdata(dp, nsplen - sizeof(struct cimsg));
}
#endif
}
break;
@ -605,6 +715,9 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
u_char *dp;
#endif
if (nsplen < sizeof(struct ccmsg))
goto trunc;
TCHECK(*ccmp);
services = EXTRACT_LE_8BITS(ccmp->cc_services);
info = EXTRACT_LE_8BITS(ccmp->cc_info);
segsize = EXTRACT_LE_16BITS(ccmp->cc_segsize);
@ -641,8 +754,10 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
if (optlen) {
(void)printf("optlen %d ", optlen);
#ifdef PRINT_NSPDATA
optlen = min(optlen, nsplen - sizeof(struct ccmsg));
if (optlen > nsplen - sizeof(struct ccmsg))
goto trunc;
dp = &(nspp[sizeof(struct ccmsg)]);
TCHECK2(*dp, optlen);
pdata(dp, optlen);
#endif
}
@ -658,6 +773,9 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
u_char *dp;
#endif
if (nsplen < sizeof(struct dimsg))
goto trunc;
TCHECK(*dimp);
reason = EXTRACT_LE_16BITS(dimp->di_reason);
optlen = EXTRACT_LE_8BITS(dimp->di_optlen);
@ -665,8 +783,10 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
if (optlen) {
(void)printf("optlen %d ", optlen);
#ifdef PRINT_NSPDATA
optlen = min(optlen, nsplen - sizeof(struct dimsg));
if (optlen > nsplen - sizeof(struct dimsg))
goto trunc;
dp = &(nspp[sizeof(struct dimsg)]);
TCHECK2(*dp, optlen);
pdata(dp, optlen);
#endif
}
@ -678,6 +798,7 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
struct dcmsg *dcmp = (struct dcmsg *)nspp;
int reason;
TCHECK(*dcmp);
reason = EXTRACT_LE_16BITS(dcmp->dc_reason);
print_reason(reason);
@ -692,6 +813,10 @@ print_nsp(const u_char *nspp, u_int nsplen _U_)
(void)printf("reserved-type? %x %d > %d", flags, src, dst);
break;
}
return (1);
trunc:
return (0);
}
static struct tok reason2str[] = {