diff options
author | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-11-22 00:55:59 +0100 |
---|---|---|
committer | Quentin Young <qlyoung@cumulusnetworks.com> | 2019-11-22 09:26:31 +0100 |
commit | 73bfd76d65ec4ac0fb1b3f6a0566b702458dd48b (patch) | |
tree | 705d3edbbe33c3b5bddbcbff7b018a0d006efcdb /bgpd/bgp_lcommunity.c | |
parent | bgpd: use safe functions to work with ecom attrs (diff) | |
download | frr-73bfd76d65ec4ac0fb1b3f6a0566b702458dd48b.tar.xz frr-73bfd76d65ec4ac0fb1b3f6a0566b702458dd48b.zip |
bgpd: fix heap buffer overflow in lcom -> str enc
Spaces were not being accounted for in the heap buffer sizing, leading
to a heap buffer overflow when encoding large communities to their
string representations.
This patch also uses safer functions to do the encoding instead of
pointer math.
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
Diffstat (limited to '')
-rw-r--r-- | bgpd/bgp_lcommunity.c | 36 |
1 files changed, 17 insertions, 19 deletions
diff --git a/bgpd/bgp_lcommunity.c b/bgpd/bgp_lcommunity.c index 3243ce96b..674686b3c 100644 --- a/bgpd/bgp_lcommunity.c +++ b/bgpd/bgp_lcommunity.c @@ -177,15 +177,14 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) { int i; int len; - bool first = true; char *str_buf; - char *str_pnt; uint8_t *pnt; uint32_t global, local1, local2; json_object *json_lcommunity_list = NULL; json_object *json_string = NULL; -#define LCOMMUNITY_STR_DEFAULT_LEN 32 + /* 3 32-bit integers, 2 colons, and a space */ +#define LCOMMUNITY_STRLEN (10 * 3 + 2 + 1) if (!lcom) return; @@ -196,8 +195,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) } if (lcom->size == 0) { - str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1); - str_buf[0] = '\0'; + str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, 1); if (make_json) { json_object_string_add(lcom->json, "string", ""); @@ -209,15 +207,13 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) return; } - str_buf = str_pnt = - XMALLOC(MTYPE_LCOMMUNITY_STR, - (LCOMMUNITY_STR_DEFAULT_LEN * lcom->size) + 1); + /* 1 space + lcom->size lcom strings + null terminator */ + size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2; + str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz); for (i = 0; i < lcom->size; i++) { - if (first) - first = false; - else - *str_pnt++ = ' '; + if (i > 0) + strlcat(str_buf, " ", str_buf_sz); pnt = lcom->val + (i * LCOMMUNITY_SIZE); pnt = ptr_get_be32(pnt, &global); @@ -225,19 +221,21 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json) pnt = ptr_get_be32(pnt, &local2); (void)pnt; - len = sprintf(str_pnt, "%u:%u:%u", global, local1, local2); + char lcsb[LCOMMUNITY_STRLEN + 1]; + + snprintf(lcsb, sizeof(lcsb), "%u:%u:%u", global, local1, + local2); + + len = strlcat(str_buf, lcsb, str_buf_sz); + assert((unsigned int)len < str_buf_sz); + if (make_json) { - json_string = json_object_new_string(str_pnt); + json_string = json_object_new_string(lcsb); json_object_array_add(json_lcommunity_list, json_string); } - - str_pnt += len; } - str_buf = - XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, str_pnt - str_buf + 1); - if (make_json) { json_object_string_add(lcom->json, "string", str_buf); json_object_object_add(lcom->json, "list", |