[13690] in Athena Bugs
Hesiod core dumps on truncated packets
daemon@ATHENA.MIT.EDU (Greg Hudson)
Wed Jul 26 13:02:21 1995
Date: Wed, 26 Jul 1995 13:03:12 -0400
From: Greg Hudson <ghudson@MIT.EDU>
To: bugs@MIT.EDU, rel-eng@MIT.EDU
Hesiod's res_scan() does not deal properly with truncated responses.
The header will still say there are more fields in the response than
are actually present, and res_scan() will try to parse beyond the end
of the response. This will usually result in memory corruption,
depending on what happens to be in memory after the response buffer.
The test case I used to debug this is ghudson.grplist. Typically,
named will return a packet which claims to have one question, one
answer, three name server fields, and no additional fields, but the
actual response ends after the answer. (Occasionally named seems to
return a response with no name server fields advertised in the header;
I don't know why it's different sometimes.)
The patch I've included to fix this bug also does sanity-checking on
the lengths of returned fields in addition to checking for truncated
packets. This way, even if the name server packet is corrupted, we
won't copy more data into the data buffer than we have room for.
*** 1.2 1995/01/08 22:11:08
--- resolve.c 1995/07/26 16:55:07
***************
*** 1,8 ****
#ifndef lint
! static char *RCS_ID = "$Header: /afs/sipb/project/sipb-athena/hesiod/RCS/resolve.c,v 1.2 1995/01/08 22:11:08 yonah Exp $";
#endif
/*
! * $Author: yonah $
* $Source: /afs/sipb/project/sipb-athena/hesiod/RCS/resolve.c,v $
* $Athena: resolve.c,v 1.4 88/08/07 21:58:40 treese Locked $
*/
--- 1,8 ----
#ifndef lint
! static char *RCS_ID = "$Header: /afs/sipb/project/sipb-athena/hesiod/RCS/resolve.c,v 1.5 1995/07/26 16:55:06 ghudson Exp $";
#endif
/*
! * $Author: ghudson $
* $Source: /afs/sipb/project/sipb-athena/hesiod/RCS/resolve.c,v $
* $Athena: resolve.c,v 1.4 88/08/07 21:58:40 treese Locked $
*/
***************
*** 56,70 ****
nsmsg_p
! res_scan(msg)
char *msg;
{
static char bigmess[sizeof(nsmsg_t) + sizeof(rr_t)*((PACKETSZ-sizeof(HEADER))/RRFIXEDSZ)];
static char datmess[PACKETSZ-sizeof(HEADER)];
register char *cp;
register rr_t *rp;
register HEADER *hp;
! register char *data = datmess;
register int n, n_an, n_ns, n_ar, nrec;
register nsmsg_t *mess = (nsmsg_t *)bigmess;
--- 56,71 ----
nsmsg_p
! res_scan(msg, msg_len)
char *msg;
+ int msg_len;
{
static char bigmess[sizeof(nsmsg_t) + sizeof(rr_t)*((PACKETSZ-sizeof(HEADER))/RRFIXEDSZ)];
static char datmess[PACKETSZ-sizeof(HEADER)];
register char *cp;
register rr_t *rp;
register HEADER *hp;
! register char *data = datmess, *dend = data + sizeof(datmess);
register int n, n_an, n_ns, n_ar, nrec;
register nsmsg_t *mess = (nsmsg_t *)bigmess;
***************
*** 94,101 ****
/* scan answers */
if (n = n_an) {
! while (--n >= 0) {
! if ((cp = rr_scan(cp, rp)) == NULL)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
--- 95,102 ----
/* scan answers */
if (n = n_an) {
! while (--n >= 0 && cp < msg + msg_len) {
! if ((cp = rr_scan(cp, rp)) == NULL || rp->dlen + 1 > dend - data)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
***************
*** 107,114 ****
/* scan name servers */
if (n = n_ns) {
! while (--n >= 0) {
! if ((cp = rr_scan(cp, rp)) == NULL)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
--- 108,115 ----
/* scan name servers */
if (n = n_ns) {
! while (--n >= 0 && cp < msg + msg_len) {
! if ((cp = rr_scan(cp, rp)) == NULL || rp->dlen + 1 > dend - data)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
***************
*** 120,127 ****
/* scan additional records */
if (n = n_ar) {
! while (--n >= 0) {
! if ((cp = rr_scan(cp, rp)) == NULL)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
--- 121,128 ----
/* scan additional records */
if (n = n_ar) {
! while (--n >= 0 && cp < msg + msg_len) {
! if ((cp = rr_scan(cp, rp)) == NULL || rp->dlen + 1 > dend - data)
return((nsmsg_t *)NULL);
(void) strncpy(data, rp->data, rp->dlen);
rp->data = data;
***************
*** 192,198 ****
return((nsmsg_t *)NULL);
}
! return(res_scan(abuf));
}
--- 193,199 ----
return((nsmsg_t *)NULL);
}
! return(res_scan(abuf, n));
}