CVE-2017-12992/RIPng: Clean up bounds checking.

Do bounds checking as we access items.

Scan the list of netinfo6 entries based on the supplied packet length,
without taking the captured length into account; let the aforementioned
bounds checking handle that.

This fixes a buffer over-read discovered by Kamil Frankowicz.

Add a test using the capture file supplied by the reporter(s).
This commit is contained in:
Guy Harris 2017-02-07 03:03:34 -08:00 committed by Denis Ovsienko
parent db24063b01
commit e942fb84fb
4 changed files with 42 additions and 31 deletions

View File

@ -110,65 +110,74 @@ ripng_print(netdissect_options *ndo, const u_char *dat, unsigned int length)
{
register const struct rip6 *rp = (const struct rip6 *)dat;
register const struct netinfo6 *ni;
register u_int amt;
register u_int i;
int j;
int trunc;
if (ndo->ndo_snapend < dat)
return;
amt = ndo->ndo_snapend - dat;
i = min(length, amt);
if (i < (sizeof(struct rip6) - sizeof(struct netinfo6)))
return;
i -= (sizeof(struct rip6) - sizeof(struct netinfo6));
unsigned int length_left;
u_int j;
ND_TCHECK(rp->rip6_cmd);
switch (rp->rip6_cmd) {
case RIP6_REQUEST:
j = length / sizeof(*ni);
if (j == 1
&& rp->rip6_nets->rip6_metric == HOPCNT_INFINITY6
&& IN6_IS_ADDR_UNSPECIFIED(&rp->rip6_nets->rip6_dest)) {
ND_PRINT((ndo, " ripng-req dump"));
break;
length_left = length;
if (length_left < (sizeof(struct rip6) - sizeof(struct netinfo6)))
goto trunc;
length_left -= (sizeof(struct rip6) - sizeof(struct netinfo6));
j = length_left / sizeof(*ni);
if (j == 1) {
ND_TCHECK(rp->rip6_nets);
if (rp->rip6_nets->rip6_metric == HOPCNT_INFINITY6
&& IN6_IS_ADDR_UNSPECIFIED(&rp->rip6_nets->rip6_dest)) {
ND_PRINT((ndo, " ripng-req dump"));
break;
}
}
if (j * sizeof(*ni) != length - 4)
ND_PRINT((ndo, " ripng-req %d[%u]:", j, length));
if (j * sizeof(*ni) != length_left)
ND_PRINT((ndo, " ripng-req %u[%u]:", j, length));
else
ND_PRINT((ndo, " ripng-req %d:", j));
trunc = ((i / sizeof(*ni)) * sizeof(*ni) != i);
for (ni = rp->rip6_nets; i >= sizeof(*ni);
i -= sizeof(*ni), ++ni) {
ND_PRINT((ndo, " ripng-req %u:", j));
for (ni = rp->rip6_nets; length_left >= sizeof(*ni);
length_left -= sizeof(*ni), ++ni) {
ND_TCHECK(*ni);
if (ndo->ndo_vflag > 1)
ND_PRINT((ndo, "\n\t"));
else
ND_PRINT((ndo, " "));
rip6_entry_print(ndo, ni, 0);
}
if (length_left != 0)
goto trunc;
break;
case RIP6_RESPONSE:
j = length / sizeof(*ni);
if (j * sizeof(*ni) != length - 4)
length_left = length;
if (length_left < (sizeof(struct rip6) - sizeof(struct netinfo6)))
goto trunc;
length_left -= (sizeof(struct rip6) - sizeof(struct netinfo6));
j = length_left / sizeof(*ni);
if (j * sizeof(*ni) != length_left)
ND_PRINT((ndo, " ripng-resp %d[%u]:", j, length));
else
ND_PRINT((ndo, " ripng-resp %d:", j));
trunc = ((i / sizeof(*ni)) * sizeof(*ni) != i);
for (ni = rp->rip6_nets; i >= sizeof(*ni);
i -= sizeof(*ni), ++ni) {
for (ni = rp->rip6_nets; length_left >= sizeof(*ni);
length_left -= sizeof(*ni), ++ni) {
ND_TCHECK(*ni);
if (ndo->ndo_vflag > 1)
ND_PRINT((ndo, "\n\t"));
else
ND_PRINT((ndo, " "));
rip6_entry_print(ndo, ni, ni->rip6_metric);
}
if (trunc)
ND_PRINT((ndo, "[|ripng]"));
if (length_left != 0)
goto trunc;
break;
default:
ND_PRINT((ndo, " ripng-%d ?? %u", rp->rip6_cmd, length));
break;
}
ND_TCHECK(rp->rip6_vers);
if (rp->rip6_vers != RIP6_VERSION)
ND_PRINT((ndo, " [vers %d]", rp->rip6_vers));
return;
trunc:
ND_PRINT((ndo, "[|ripng]"));
return;
}

View File

@ -450,6 +450,7 @@ isoclns-oobr isoclns-oobr.pcap isoclns-oobr.out
nfs-attr-oobr nfs-attr-oobr.pcap nfs-attr-oobr.out
decnet-oobr decnet-oobr.pcap decnet-oobr.out
oobr_parse_elements oobr_parse_elements.pcap oobr_parse_elements.out
hoobr_ripng_print hoobr_ripng_print.pcap hoobr_ripng_print.out
# bad packets from Wilfried Kirsch
slip-bad-direction slip-bad-direction.pcap slip-bad-direction.out -ve

View File

@ -0,0 +1 @@
IP 48.48.48.48.521 > 48.48.48.48.12336: [|ripng]

Binary file not shown.