Merge pull request #624 from ecsv/batadv-for-18.06
[feed/routing.git] / quagga / patches / 003-Quagga-2018-1114.patch
1 From e69b535f92eafb599329bf725d9b4c6fd5d7fded Mon Sep 17 00:00:00 2001
2 From: Paul Jakma <paul@jakma.org>
3 Date: Sat, 6 Jan 2018 19:52:10 +0000
4 Subject: bgpd/security: Fix double free of unknown attribute
5
6 Security issue: Quagga-2018-1114
7 See: https://www.quagga.net/security/Quagga-2018-1114.txt
8
9 It is possible for bgpd to double-free an unknown attribute. This can happen
10 via bgp_update_receive receiving an UPDATE with an invalid unknown attribute.
11 bgp_update_receive then will call bgp_attr_unintern_sub and bgp_attr_flush,
12 and the latter may try free an already freed unknown attr.
13
14 * bgpd/bgp_attr.c: (transit_unintern) Take a pointer to the caller's storage
15 for the (struct transit *), so that transit_unintern can NULL out the
16 caller's reference if the (struct transit) is freed.
17 (cluster_unintern) By inspection, appears to have a similar issue.
18 (bgp_attr_unintern_sub) adjust for above.
19
20 --- a/bgpd/bgp_attr.c
21 +++ b/bgpd/bgp_attr.c
22 @@ -186,15 +186,17 @@ cluster_intern (struct cluster_list *clu
23 }
24
25 void
26 -cluster_unintern (struct cluster_list *cluster)
27 +cluster_unintern (struct cluster_list **cluster)
28 {
29 - if (cluster->refcnt)
30 - cluster->refcnt--;
31 + struct cluster_list *c = *cluster;
32 + if (c->refcnt)
33 + c->refcnt--;
34
35 - if (cluster->refcnt == 0)
36 + if (c->refcnt == 0)
37 {
38 - hash_release (cluster_hash, cluster);
39 - cluster_free (cluster);
40 + hash_release (cluster_hash, c);
41 + cluster_free (c);
42 + *cluster = NULL;
43 }
44 }
45
46 @@ -344,15 +346,18 @@ transit_intern (struct transit *transit)
47 }
48
49 void
50 -transit_unintern (struct transit *transit)
51 +transit_unintern (struct transit **transit)
52 {
53 - if (transit->refcnt)
54 - transit->refcnt--;
55 + struct transit *t = *transit;
56 +
57 + if (t->refcnt)
58 + t->refcnt--;
59
60 - if (transit->refcnt == 0)
61 + if (t->refcnt == 0)
62 {
63 - hash_release (transit_hash, transit);
64 - transit_free (transit);
65 + hash_release (transit_hash, t);
66 + transit_free (t);
67 + *transit = NULL;
68 }
69 }
70
71 @@ -793,11 +798,11 @@ bgp_attr_unintern_sub (struct attr *attr
72 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
73
74 if (attr->extra->cluster)
75 - cluster_unintern (attr->extra->cluster);
76 + cluster_unintern (&attr->extra->cluster);
77 UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
78
79 if (attr->extra->transit)
80 - transit_unintern (attr->extra->transit);
81 + transit_unintern (&attr->extra->transit);
82 }
83 }
84
85 --- a/bgpd/bgp_attr.h
86 +++ b/bgpd/bgp_attr.h
87 @@ -184,10 +184,10 @@ extern unsigned long int attr_unknown_co
88
89 /* Cluster list prototypes. */
90 extern int cluster_loop_check (struct cluster_list *, struct in_addr);
91 -extern void cluster_unintern (struct cluster_list *);
92 +extern void cluster_unintern (struct cluster_list **);
93
94 /* Transit attribute prototypes. */
95 -void transit_unintern (struct transit *);
96 +void transit_unintern (struct transit **);
97
98 /* Below exported for unit-test purposes only */
99 struct bgp_attr_parser_args {