lib: Check prefix length from zebra is sensible

* zclient.c: prefix length on router-id and interface address add
  messages not sanity checked.  fix.

* */*_zebra.c: Prefix length on zebra route read was not checked, and
  clients use it to write to storage.  An evil zebra could overflow
  client structures by sending overly long prefixlen.

Prompted by discussions with:

Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
Paul Jakma 2016-02-09 15:23:03 +00:00 committed by Donald Sharp
parent 6b143a68d3
commit d91788284e
7 changed files with 35 additions and 24 deletions

View file

@ -607,7 +607,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
/* IPv4 prefix. */ /* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4)); memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET; p.family = AF_INET;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */ /* Nexthop, ifindex, distance, metric. */
@ -722,7 +722,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
/* IPv6 prefix. */ /* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6)); memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6; p.family = AF_INET6;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */ /* Nexthop, ifindex, distance, metric. */

View file

@ -570,7 +570,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
api.message = stream_getc (stream); api.message = stream_getc (stream);
p.family = AF_INET; p.family = AF_INET;
p.prefixlen = stream_getc (stream); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (stream));
stream_get (&p.prefix, stream, PSIZE (p.prefixlen)); stream_get (&p.prefix, stream, PSIZE (p.prefixlen));
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))

View file

@ -942,18 +942,30 @@ zebra_redistribute_send (int command, struct zclient *zclient, afi_t afi, int ty
return zclient_send_message(zclient); return zclient_send_message(zclient);
} }
/* Get prefix in ZServ format; family should be filled in on prefix */
static void
zclient_stream_get_prefix (struct stream *s, struct prefix *p)
{
size_t plen = prefix_blen (p);
u_char c;
p->prefixlen = 0;
if (plen == 0)
return;
stream_get (&p->u.prefix, s, plen);
c = stream_getc(s);
p->prefixlen = MIN(plen * 8, c);
}
/* Router-id update from zebra daemon. */ /* Router-id update from zebra daemon. */
void void
zebra_router_id_update_read (struct stream *s, struct prefix *rid) zebra_router_id_update_read (struct stream *s, struct prefix *rid)
{ {
int plen;
/* Fetch interface address. */ /* Fetch interface address. */
rid->family = stream_getc (s); rid->family = stream_getc (s);
plen = prefix_blen (rid); zclient_stream_get_prefix (s, rid);
stream_get (&rid->u.prefix, s, plen);
rid->prefixlen = stream_getc (s);
} }
/* Interface addition from zebra daemon. */ /* Interface addition from zebra daemon. */
@ -1263,8 +1275,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
ifindex_t ifindex; ifindex_t ifindex;
struct interface *ifp; struct interface *ifp;
struct connected *ifc; struct connected *ifc;
struct prefix p, d; struct prefix p, d, *dp;
int family;
int plen; int plen;
u_char ifc_flags; u_char ifc_flags;
@ -1288,24 +1299,24 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
ifc_flags = stream_getc (s); ifc_flags = stream_getc (s);
/* Fetch interface address. */ /* Fetch interface address. */
family = p.family = stream_getc (s); d.family = p.family = stream_getc (s);
plen = prefix_blen (&d);
plen = prefix_blen (&p);
stream_get (&p.u.prefix, s, plen); zclient_stream_get_prefix (s, &p);
p.prefixlen = stream_getc (s);
/* Fetch destination address. */ /* Fetch destination address. */
stream_get (&d.u.prefix, s, plen); stream_get (&d.u.prefix, s, plen);
d.family = family;
/* N.B. NULL destination pointers are encoded as all zeroes */
dp = memconstant(&d.u.prefix,0,plen) ? NULL : &d;
if (type == ZEBRA_INTERFACE_ADDRESS_ADD) if (type == ZEBRA_INTERFACE_ADDRESS_ADD)
{ {
ifc = connected_lookup_prefix_exact (ifp, &p); ifc = connected_lookup_prefix_exact (ifp, &p);
if (!ifc) if (!ifc)
{ {
/* N.B. NULL destination pointers are encoded as all zeroes */ /* N.B. NULL destination pointers are encoded as all zeroes */
ifc = connected_add_by_prefix(ifp, &p, (memconstant(&d.u.prefix,0,plen) ? ifc = connected_add_by_prefix(ifp, &p, dp);
NULL : &d));
} }
if (ifc) if (ifc)
{ {

View file

@ -235,7 +235,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
/* IPv6 prefix. */ /* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6)); memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6; p.family = AF_INET6;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */ /* Nexthop, ifindex, distance, metric. */

View file

@ -1070,7 +1070,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
/* IPv4 prefix. */ /* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4)); memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET; p.family = AF_INET;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
if (IPV4_NET127(ntohl(p.prefix.s_addr))) if (IPV4_NET127(ntohl(p.prefix.s_addr)))

View file

@ -153,7 +153,7 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
/* IPv4 prefix. */ /* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4)); memset (&p, 0, sizeof (struct prefix_ipv4));
p.family = AF_INET; p.family = AF_INET;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV4_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */ /* Nexthop, ifindex, distance, metric. */

View file

@ -149,7 +149,7 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient,
/* IPv6 prefix. */ /* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6)); memset (&p, 0, sizeof (struct prefix_ipv6));
p.family = AF_INET6; p.family = AF_INET6;
p.prefixlen = stream_getc (s); p.prefixlen = MIN(IPV6_MAX_PREFIXLEN, stream_getc (s));
stream_get (&p.prefix, s, PSIZE (p.prefixlen)); stream_get (&p.prefix, s, PSIZE (p.prefixlen));
/* Nexthop, ifindex, distance, metric. */ /* Nexthop, ifindex, distance, metric. */