From 2cf37d594dd1b70958619c65cb71f2f79344d2c2 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 30 Dec 2020 23:02:03 +0200 Subject: [PATCH] bgpd: Validate community list if they are not malformed 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 --- bgpd/bgp_community.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index b6cc2b839f..f722a8dbc7 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -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; -- 2.39.5