]> git.puffer.fish Git - matthieu/frr.git/commitdiff
lib: Check prefix length from zebra is sensible
authorPaul Jakma <paul.jakma@hpe.com>
Tue, 9 Feb 2016 15:23:03 +0000 (15:23 +0000)
committerDonald Sharp <sharpd@cumulusnetworks.com>
Fri, 23 Sep 2016 16:12:17 +0000 (12:12 -0400)
* 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>

bgpd/bgp_zebra.c
isisd/isis_zebra.c
lib/zclient.c
ospf6d/ospf6_zebra.c
ospfd/ospf_zebra.c
ripd/rip_zebra.c
ripngd/ripng_zebra.c

index 15db3215578abecce47c13a7eb3e4ab6301ac1b9..0f5c3ce7aae4d866df8d4641eccd1df79f5f1cb4 100644 (file)
@@ -607,7 +607,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
   /* 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. */
@@ -722,7 +722,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length,
   /* 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. */
index 45728ad2c10c2346e2b12345427dee65bb6a8e54..a75e293f9635974d23f9bcfa162fc9a56bb7c4a9 100644 (file)
@@ -570,7 +570,7 @@ isis_zebra_read_ipv4 (int command, struct zclient *zclient,
   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))
index 5193a282a633e1700f79c9c456ed91a62446d808..6ccc6e371b4ae2cf6ba52573e7c364384b63e6c7 100644 (file)
@@ -942,18 +942,30 @@ zebra_redistribute_send (int command, struct zclient *zclient, afi_t afi, int ty
   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. */
@@ -1263,8 +1275,7 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   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;
 
@@ -1288,24 +1299,24 @@ zebra_interface_address_read (int type, struct stream *s, vrf_id_t vrf_id)
   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) 
     {
       ifc = connected_lookup_prefix_exact (ifp, &p);
       if (!ifc)
         {
           /* 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)
         {
index 6dee1424a66500b1a2e49410ef0f9e3c625ea2ef..5969ef7b695935ce3a6414587b5b90fc1721d7af 100644 (file)
@@ -235,7 +235,7 @@ ospf6_zebra_read_ipv6 (int command, struct zclient *zclient,
   /* 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. */
index 8752e83ed50fd9b46d73e160e0a38309fe8812d7..0938ce8d1ec97b490585e715dc4193d0ecd310c8 100644 (file)
@@ -1070,7 +1070,7 @@ ospf_zebra_read_ipv4 (int command, struct zclient *zclient,
   /* 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)))
index c312641d44fb5045cd1d5ba2efd59f25d8bfdded..06e840464dcaa3a962333c5e73b86ced85b4ae58 100644 (file)
@@ -153,7 +153,7 @@ rip_zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length,
   /* 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. */
index 1184cd0db62a20c07816e74d644285d7ea9138ce..e1ede095ecad6cac7d739ac45cd2bc899353f573 100644 (file)
@@ -149,7 +149,7 @@ ripng_zebra_read_ipv6 (int command, struct zclient *zclient,
   /* 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. */