|
|
205431 |
From 79fae02a1c621ca7b476dda8194e3bf24f177c89 Mon Sep 17 00:00:00 2001
|
|
|
205431 |
From: Paul Jakma <paul@jakma.org>
|
|
|
205431 |
Date: Sat, 6 Jan 2018 19:52:10 +0000
|
|
|
205431 |
Subject: [PATCH] bgpd/security: Fix double free of unknown attribute
|
|
|
205431 |
|
|
|
205431 |
Security issue: Quagga-2018-1114
|
|
|
205431 |
See: https://www.quagga.net/security/Quagga-2018-1114.txt
|
|
|
205431 |
|
|
|
205431 |
It is possible for bgpd to double-free an unknown attribute. This can happen
|
|
|
205431 |
via bgp_update_receive receiving an UPDATE with an invalid unknown attribute.
|
|
|
205431 |
bgp_update_receive then will call bgp_attr_unintern_sub and bgp_attr_flush,
|
|
|
205431 |
and the latter may try free an already freed unknown attr.
|
|
|
205431 |
|
|
|
205431 |
* bgpd/bgp_attr.c: (transit_unintern) Take a pointer to the caller's storage
|
|
|
205431 |
for the (struct transit *), so that transit_unintern can NULL out the
|
|
|
205431 |
caller's reference if the (struct transit) is freed.
|
|
|
205431 |
(cluster_unintern) By inspection, appears to have a similar issue.
|
|
|
205431 |
(bgp_attr_unintern_sub) adjust for above.
|
|
|
205431 |
---
|
|
|
205431 |
bgpd/bgp_attr.c | 33 +++++++++++++++++++--------------
|
|
|
205431 |
bgpd/bgp_attr.h | 4 ++--
|
|
|
205431 |
2 files changed, 21 insertions(+), 16 deletions(-)
|
|
|
205431 |
|
|
|
205431 |
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
|
|
|
205431 |
index cbf2902d..8eea4ed0 100644
|
|
|
205431 |
--- a/bgpd/bgp_attr.c
|
|
|
205431 |
+++ b/bgpd/bgp_attr.c
|
|
|
205431 |
@@ -183,15 +183,17 @@ cluster_intern (struct cluster_list *cluster)
|
|
|
205431 |
}
|
|
|
205431 |
|
|
|
205431 |
void
|
|
|
205431 |
-cluster_unintern (struct cluster_list *cluster)
|
|
|
205431 |
+cluster_unintern (struct cluster_list **cluster)
|
|
|
205431 |
{
|
|
|
205431 |
- if (cluster->refcnt)
|
|
|
205431 |
- cluster->refcnt--;
|
|
|
205431 |
+ struct cluster_list *c = *cluster;
|
|
|
205431 |
+ if (c->refcnt)
|
|
|
205431 |
+ c->refcnt--;
|
|
|
205431 |
|
|
|
205431 |
- if (cluster->refcnt == 0)
|
|
|
205431 |
+ if (c->refcnt == 0)
|
|
|
205431 |
{
|
|
|
205431 |
- hash_release (cluster_hash, cluster);
|
|
|
205431 |
- cluster_free (cluster);
|
|
|
205431 |
+ hash_release (cluster_hash, c);
|
|
|
205431 |
+ cluster_free (c);
|
|
|
205431 |
+ *cluster = NULL;
|
|
|
205431 |
}
|
|
|
205431 |
}
|
|
|
205431 |
|
|
|
205431 |
@@ -241,15 +243,18 @@ transit_intern (struct transit *transit)
|
|
|
205431 |
}
|
|
|
205431 |
|
|
|
205431 |
void
|
|
|
205431 |
-transit_unintern (struct transit *transit)
|
|
|
205431 |
+transit_unintern (struct transit **transit)
|
|
|
205431 |
{
|
|
|
205431 |
- if (transit->refcnt)
|
|
|
205431 |
- transit->refcnt--;
|
|
|
205431 |
+ struct transit *t = *transit;
|
|
|
205431 |
+
|
|
|
205431 |
+ if (t->refcnt)
|
|
|
205431 |
+ t->refcnt--;
|
|
|
205431 |
|
|
|
205431 |
- if (transit->refcnt == 0)
|
|
|
205431 |
+ if (t->refcnt == 0)
|
|
|
205431 |
{
|
|
|
205431 |
- hash_release (transit_hash, transit);
|
|
|
205431 |
- transit_free (transit);
|
|
|
205431 |
+ hash_release (transit_hash, t);
|
|
|
205431 |
+ transit_free (t);
|
|
|
205431 |
+ *transit = NULL;
|
|
|
205431 |
}
|
|
|
205431 |
}
|
|
|
205431 |
|
|
|
205431 |
@@ -658,11 +663,11 @@ bgp_attr_unintern_sub (struct attr *attr)
|
|
|
205431 |
UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
|
|
|
205431 |
|
|
|
205431 |
if (attr->extra->cluster)
|
|
|
205431 |
- cluster_unintern (attr->extra->cluster);
|
|
|
205431 |
+ cluster_unintern (&attr->extra->cluster);
|
|
|
205431 |
UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
|
|
|
205431 |
|
|
|
205431 |
if (attr->extra->transit)
|
|
|
205431 |
- transit_unintern (attr->extra->transit);
|
|
|
205431 |
+ transit_unintern (&attr->extra->transit);
|
|
|
205431 |
}
|
|
|
205431 |
}
|
|
|
205431 |
|
|
|
205431 |
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
|
|
|
205431 |
index df87c863..7d3cc64b 100644
|
|
|
205431 |
--- a/bgpd/bgp_attr.h
|
|
|
205431 |
+++ b/bgpd/bgp_attr.h
|
|
|
205431 |
@@ -174,10 +174,10 @@ extern unsigned long int attr_unknown_count (void);
|
|
|
205431 |
|
|
|
205431 |
/* Cluster list prototypes. */
|
|
|
205431 |
extern int cluster_loop_check (struct cluster_list *, struct in_addr);
|
|
|
205431 |
-extern void cluster_unintern (struct cluster_list *);
|
|
|
205431 |
+extern void cluster_unintern (struct cluster_list **);
|
|
|
205431 |
|
|
|
205431 |
/* Transit attribute prototypes. */
|
|
|
205431 |
-void transit_unintern (struct transit *);
|
|
|
205431 |
+void transit_unintern (struct transit **);
|
|
|
205431 |
|
|
|
205431 |
/* Below exported for unit-test purposes only */
|
|
|
205431 |
struct bgp_attr_parser_args {
|
|
|
205431 |
--
|
|
|
205431 |
2.14.3
|
|
|
205431 |
|