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>
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 4ec15d0..bee1a94 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -250,7 +250,7 @@
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
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));
/* Nexthop, ifindex, distance, metric. */
@@ -326,7 +326,7 @@
/* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
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));
/* Nexthop, ifindex, distance, metric. */
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 6c398cf..a1a5bea 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -541,7 +541,7 @@
api.message = stream_getc (stream);
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));
if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP))
diff --git a/lib/zclient.c b/lib/zclient.c
index 610008b..d25c8d4 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -651,18 +651,30 @@
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. */
void
zebra_router_id_update_read (struct stream *s, struct prefix *rid)
{
- int plen;
-
/* Fetch interface address. */
rid->family = stream_getc (s);
-
- plen = prefix_blen (rid);
- stream_get (&rid->u.prefix, s, plen);
- rid->prefixlen = stream_getc (s);
+
+ zclient_stream_get_prefix (s, rid);
}
/* Interface addition from zebra daemon. */
@@ -814,8 +826,7 @@
ifindex_t ifindex;
struct interface *ifp;
struct connected *ifc;
- struct prefix p, d;
- int family;
+ struct prefix p, d, *dp;
int plen;
u_char ifc_flags;
@@ -840,21 +851,21 @@
ifc_flags = stream_getc (s);
/* Fetch interface address. */
- family = p.family = stream_getc (s);
-
- plen = prefix_blen (&p);
- stream_get (&p.u.prefix, s, plen);
- p.prefixlen = stream_getc (s);
+ d.family = p.family = stream_getc (s);
+ plen = prefix_blen (&d);
+
+ zclient_stream_get_prefix (s, &p);
/* Fetch destination address. */
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)
{
/* N.B. NULL destination pointers are encoded as all zeroes */
- ifc = connected_add_by_prefix(ifp, &p,(memconstant(&d.u.prefix,0,plen) ?
- NULL : &d));
+ ifc = connected_add_by_prefix(ifp, &p, dp);
if (ifc != NULL)
{
ifc->flags = ifc_flags;
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 30b6fc6..0caf001 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -227,7 +227,7 @@
/* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
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));
/* Nexthop, ifindex, distance, metric. */
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index cf2ea81..4531f13 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -845,7 +845,7 @@
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
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));
if (IPV4_NET127(ntohl(p.prefix.s_addr)))
diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c
index 0b6c22a..1411cd7 100644
--- a/ripd/rip_zebra.c
+++ b/ripd/rip_zebra.c
@@ -148,7 +148,7 @@
/* IPv4 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
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));
/* Nexthop, ifindex, distance, metric. */
diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c
index a48539e..e02b098 100644
--- a/ripngd/ripng_zebra.c
+++ b/ripngd/ripng_zebra.c
@@ -147,7 +147,7 @@
/* IPv6 prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
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));
/* Nexthop, ifindex, distance, metric. */