]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Validate community list if they are not malformed 7803/head
authorDonatas Abraitis <donatas.abraitis@gmail.com>
Wed, 30 Dec 2020 21:02:03 +0000 (23:02 +0200)
committerDonatas Abraitis <donatas.abraitis@gmail.com>
Tue, 5 Jan 2021 08:59:11 +0000 (10:59 +0200)
Before fix:
```
root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535:429496723296'
root@exit1-debian-9:~/frr#

root@exit1-debian-9:~/frr# vtysh -c 'c' -c 'bgp community-list standard test permit 65535:4294967296'
root@exit1-debian-9:~/frr#

root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535'
root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535:'
% Malformed communities attribute
```

After fix:
```
root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535:4294967296'
% Malformed communities attribute

root@exit1-debian-9:~/frr# vtysh -c 'c' -c 'bgp community-list standard test permit 65535:4294967299'
% Malformed community-list value

root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535:'
% Malformed communities attribute
root@exit1-debian-9:~/frr# /usr/local/bin/vtysh  -c 'c' -c 'route-map test permit 10' -c 'set community 65535'
% Malformed communities attribute
```

Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
bgpd/bgp_community.c

index b6cc2b839f36afeb3bc69e36a8839c39652d24c0..f722a8dbc79d6e15a534c61a72a657be7ade49b3 100644 (file)
@@ -24,6 +24,7 @@
 #include "hash.h"
 #include "memory.h"
 #include "jhash.h"
+#include "frrstr.h"
 
 #include "bgpd/bgp_memory.h"
 #include "bgpd/bgp_community.h"
@@ -648,6 +649,31 @@ enum community_token {
        community_token_unknown
 };
 
+/* Helper to check if a given community is valid */
+static bool community_valid(const char *community)
+{
+       int octets = 0;
+       char **splits;
+       int num;
+       int invalid = 0;
+
+       frrstr_split(community, ":", &splits, &num);
+
+       for (int i = 0; i < num; i++) {
+               if (strtoul(splits[i], NULL, 10) > UINT16_MAX)
+                       invalid++;
+
+               if (strlen(splits[i]) == 0)
+                       invalid++;
+
+               octets++;
+               XFREE(MTYPE_TMP, splits[i]);
+       }
+       XFREE(MTYPE_TMP, splits);
+
+       return (octets < 2 || invalid) ? false : true;
+}
+
 /* Get next community token from string. */
 static const char *
 community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
@@ -780,6 +806,11 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
                uint32_t community_low = 0;
                uint32_t community_high = 0;
 
+               if (!community_valid(p)) {
+                       *token = community_token_unknown;
+                       return NULL;
+               }
+
                while (isdigit((unsigned char)*p) || *p == ':') {
                        if (*p == ':') {
                                if (separator) {
@@ -810,11 +841,6 @@ community_gettoken(const char *buf, enum community_token *token, uint32_t *val)
                        return NULL;
                }
 
-               if (community_low > UINT16_MAX) {
-                       *token = community_token_unknown;
-                       return NULL;
-               }
-
                *val = community_high + community_low;
                *token = community_token_val;
                return p;