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>
This commit is contained in:
Quentin Young 2019-11-21 18:55:59 -05:00
parent 91085f974a
commit 73bfd76d65

View File

@ -177,15 +177,14 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
{ {
int i; int i;
int len; int len;
bool first = true;
char *str_buf; char *str_buf;
char *str_pnt;
uint8_t *pnt; uint8_t *pnt;
uint32_t global, local1, local2; uint32_t global, local1, local2;
json_object *json_lcommunity_list = NULL; json_object *json_lcommunity_list = NULL;
json_object *json_string = 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) if (!lcom)
return; return;
@ -196,8 +195,7 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
} }
if (lcom->size == 0) { if (lcom->size == 0) {
str_buf = XMALLOC(MTYPE_LCOMMUNITY_STR, 1); str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, 1);
str_buf[0] = '\0';
if (make_json) { if (make_json) {
json_object_string_add(lcom->json, "string", ""); json_object_string_add(lcom->json, "string", "");
@ -209,15 +207,13 @@ static void set_lcommunity_string(struct lcommunity *lcom, bool make_json)
return; return;
} }
str_buf = str_pnt = /* 1 space + lcom->size lcom strings + null terminator */
XMALLOC(MTYPE_LCOMMUNITY_STR, size_t str_buf_sz = (LCOMMUNITY_STRLEN * lcom->size) + 2;
(LCOMMUNITY_STR_DEFAULT_LEN * lcom->size) + 1); str_buf = XCALLOC(MTYPE_LCOMMUNITY_STR, str_buf_sz);
for (i = 0; i < lcom->size; i++) { for (i = 0; i < lcom->size; i++) {
if (first) if (i > 0)
first = false; strlcat(str_buf, " ", str_buf_sz);
else
*str_pnt++ = ' ';
pnt = lcom->val + (i * LCOMMUNITY_SIZE); pnt = lcom->val + (i * LCOMMUNITY_SIZE);
pnt = ptr_get_be32(pnt, &global); 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); pnt = ptr_get_be32(pnt, &local2);
(void)pnt; (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) { 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_object_array_add(json_lcommunity_list,
json_string); json_string);
} }
str_pnt += len;
} }
str_buf =
XREALLOC(MTYPE_LCOMMUNITY_STR, str_buf, str_pnt - str_buf + 1);
if (make_json) { if (make_json) {
json_object_string_add(lcom->json, "string", str_buf); json_object_string_add(lcom->json, "string", str_buf);
json_object_object_add(lcom->json, "list", json_object_object_add(lcom->json, "list",