From: Claudio Jeker Subject: bgpd: handle 0-sized objects better To: tech@openbsd.org Date: Mon, 9 Sep 2024 16:39:12 +0200 memcpy(foo, NULL, 0) is sadly big no no. Also malloc(0) is not protable and with that also calloc(0, foo) or reallocarray(foo, 0, bar). This tries to fix some (most) of those. I know that some of the ASPA bits need further work. Some of that will be in the next diff. In aspath_prepend() I'm not sure if it is better to test for asp->data == NULL instead of the uglier asp->len > shift Now shift has to be 0 if asp->len == 0 so one could also check for asp->len != 0. In the pt_fill case the code in nlri_get_vpn4 ensures that labellen is non-zero so I decided to fatal there. -- :wq Claudio Index: rde_attr.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v diff -u -p -r1.134 rde_attr.c --- rde_attr.c 12 Jul 2023 14:45:43 -0000 1.134 +++ rde_attr.c 9 Sep 2024 13:00:28 -0000 @@ -357,7 +357,8 @@ aspath_get(void *data, uint16_t len) aspath->len = len; aspath->ascnt = aspath_count(data, len); aspath->source_as = aspath_extract_origin(data, len); - memcpy(aspath->data, data, len); + if (len != 0) + memcpy(aspath->data, data, len); return (aspath); } @@ -396,7 +397,7 @@ aspath_put(struct aspath *aspath) u_char * aspath_deflate(u_char *data, uint16_t *len, int *flagnew) { - uint8_t *seg, *nseg, *ndata; + uint8_t *seg, *nseg, *ndata = NULL; uint32_t as; int i; uint16_t seg_size, olen, nlen; @@ -415,6 +416,9 @@ aspath_deflate(u_char *data, uint16_t *l fatalx("%s: would overflow", __func__); } + if (nlen == 0) + goto done; + if ((ndata = malloc(nlen)) == NULL) fatal("%s", __func__); @@ -437,6 +441,7 @@ aspath_deflate(u_char *data, uint16_t *l } } + done: *len = nlen; return (ndata); } @@ -791,6 +796,10 @@ aspath_prepend(struct aspath *asp, uint3 fatalx("aspath_prepend: preposterous prepend"); if (quantum == 0) { /* no change needed but return a copy */ + if (asp->len == 0) { + *len = 0; + return (NULL); + } p = malloc(asp->len); if (p == NULL) fatal("%s", __func__); @@ -834,7 +843,8 @@ aspath_prepend(struct aspath *asp, uint3 wpos += sizeof(uint32_t); } } - memcpy(p + wpos, asp->data + shift, asp->len - shift); + if (asp->len > shift) + memcpy(p + wpos, asp->data + shift, asp->len - shift); *len = l; return (p); @@ -851,6 +861,11 @@ aspath_override(struct aspath *asp, uint uint32_t as; uint16_t l, seg_size; uint8_t i, seg_len, seg_type; + + if (asp->len == 0) { + *len = 0; + return (NULL); + } p = malloc(asp->len); if (p == NULL) Index: rde_community.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_community.c,v diff -u -p -r1.15 rde_community.c --- rde_community.c 24 Jan 2024 14:51:12 -0000 1.15 +++ rde_community.c 9 Sep 2024 13:45:00 -0000 @@ -715,18 +715,19 @@ communities_copy(struct rde_community *t memset(to, 0, sizeof(*to)); /* ignore from->size and allocate the perfect amount */ - to->size = from->size; + to->size = from->nentries; to->nentries = from->nentries; to->flags = from->flags; + if (to->nentries == 0) + return; + if ((to->communities = reallocarray(NULL, to->size, sizeof(struct community))) == NULL) fatal(__func__); memcpy(to->communities, from->communities, to->nentries * sizeof(struct community)); - memset(to->communities + to->nentries, 0, sizeof(struct community) * - (to->size - to->nentries)); } /* Index: rde_prefix.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_prefix.c,v diff -u -p -r1.51 rde_prefix.c --- rde_prefix.c 25 Jun 2024 13:21:18 -0000 1.51 +++ rde_prefix.c 9 Sep 2024 13:17:10 -0000 @@ -225,6 +225,8 @@ pt_fill(struct bgpd_addr *prefix, int pr pte_vpn4.prefixlen = prefixlen; pte_vpn4.rd = prefix->rd; pte_vpn4.labellen = prefix->labellen; + if (prefix->labellen == 0) + fatalx("pt_fill: no MPLS label in VPN addr"); memcpy(pte_vpn4.labelstack, prefix->labelstack, prefix->labellen); return ((struct pt_entry *)&pte_vpn4); @@ -239,6 +241,8 @@ pt_fill(struct bgpd_addr *prefix, int pr pte_vpn6.prefixlen = prefixlen; pte_vpn6.rd = prefix->rd; pte_vpn6.labellen = prefix->labellen; + if (prefix->labellen == 0) + fatalx("pt_fill: no MPLS label in VPN addr"); memcpy(pte_vpn6.labelstack, prefix->labelstack, prefix->labellen); return ((struct pt_entry *)&pte_vpn6); Index: rde_sets.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_sets.c,v diff -u -p -r1.12 rde_sets.c --- rde_sets.c 28 Jul 2022 13:11:51 -0000 1.12 +++ rde_sets.c 9 Sep 2024 13:18:49 -0000 @@ -149,6 +149,9 @@ set_free(struct set_table *set) int set_add(struct set_table *set, void *elms, size_t nelms) { + if (nelms == 0) /* nothing todo */ + return 0; + if (set->max < nelms || set->max - nelms < set->nmemb) { uint32_t *s; size_t new_size;