summaryrefslogtreecommitdiff
path: root/print-decnet.c
diff options
context:
space:
mode:
authorguy <guy>2005-05-06 02:16:26 +0000
committerguy <guy>2005-05-06 02:16:26 +0000
commitf61639179282f8e796966b21e45f79db317d7bdb (patch)
tree585f8d3696420ea920a84fa2f315727800008358 /print-decnet.c
parent13247041388fef082829d0ca1d89fe1c0adc6db6 (diff)
downloadtcpdump-f61639179282f8e796966b21e45f79db317d7bdb.tar.gz
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.
Diffstat (limited to 'print-decnet.c')
-rw-r--r--print-decnet.c223
1 files changed, 174 insertions, 49 deletions
diff --git a/print-decnet.c b/print-decnet.c
index 92feb6ac..7fea582e 100644
--- a/print-decnet.c
+++ b/print-decnet.c
@@ -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[] = {