From: Claudio Jeker Subject: bgpd: better limit the maximum number of SPAS in a ASPA record To: tech@openbsd.org Date: Mon, 11 May 2026 14:29:06 +0200 The MAX_ASPA_SPAS_COUNT handling in bgpd has 2 minor issues. The merged ASPA table in the rtr process could in theory become bigger than MAX_ASPA_SPAS_COUNT. This is in itself not an issue, the RDE can handle that but we want to ensure the message can not overflow the imsg maximum buffer size. Using the same MAX_ASPA_SPAS_COUNT limit there makes sense. Also log if this happens, which may be annoying since the merged table is not persisted and so the warning will pop up over and over again until the issue is fixed. Since MAX_ASPA_SPAS_COUNT is magnitues bigger than what is around I do not bother to make this better right now. merge_aspa_set() in parse.y does the MAX_ASPA_SPAS_COUNT wrong and is off by 1 afaik. Write this like all other MAX_ASPA_SPAS_COUNT checks and put MAX_ASPA_SPAS_COUNT on the right hand side of the comparison. Btw: the biggest record right now is: customer-as 14789 provider-as { 557, 1680, 2107, 3737, 3741, 4007, 4651, 4775, 4780, 4787, 7459, 8047, 8697, 8866, 8966, 9038, 9329, 9534, 9930, 10075, 10089, 10094, 10118, 10396, 11232, 11260, 12297, 12400, 12735 , 13335, 13576, 14259, 14840, 14988, 15399, 15739, 16010, 16637, 16735, 17072, 1 7451, 17494, 17557, 17639, 17754, 17882, 18001, 18200, 18229, 18678, 20764, 2157 4, 23201, 23674, 23752, 23889, 23951, 24088, 24432, 24499, 24550, 27665, 27775, 27884, 27924, 28118, 28126, 28198, 28283, 29049, 29357, 29555, 30689, 30844, 309 99, 33765, 33779, 33874, 35900, 36947, 36992, 37054, 37105, 37133, 37468, 37645, 37662, 37678, 37705, 37904, 38040, 38082, 38442, 38565, 45430, 45498, 45582, 45 916, 46650, 47589, 48728, 48832, 49800, 52263, 52468, 55805, 55915, 55943, 55944 , 57324, 58470, 58495, 58682, 58715, 58717, 59318, 59588, 61399, 61580, 63526, 6 4116, 64126, 131267, 132602, 137187, 137491, 138754, 138886, 139009, 139901, 139 922, 141177, 141731, 150748, 199995, 201532, 203214, 203217, 204170, 205140, 206 206, 208407, 210021, 212522, 262186, 262589, 262907, 263073, 263779, 266445, 268 696, 268976, 271253, 271885, 272037, 272806, 327875, 327899, 328578, 328949 } -- :wq Claudio Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v diff -u -p -r1.492 parse.y --- parse.y 8 May 2026 12:03:50 -0000 1.492 +++ parse.y 9 May 2026 20:46:57 -0000 @@ -5537,7 +5537,7 @@ merge_aspa_set(uint32_t as, struct aspa_ RB_INSERT(aspa_tree, &conf->aspa, aspa); } - if (MAX_ASPA_SPAS_COUNT - aspa->num <= tas->num) { + if (tas->num > MAX_ASPA_SPAS_COUNT - aspa->num) { yyerror("too many providers for customer-as %u", as); return -1; } Index: rtr.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rtr.c,v diff -u -p -r1.34 rtr.c --- rtr.c 19 Mar 2026 13:36:50 -0000 1.34 +++ rtr.c 7 May 2026 14:26:22 -0000 @@ -489,10 +489,13 @@ rtr_imsg_compose(int type, uint32_t id, * At the same time tas_aid is overwritten with the bitmasks or cleared * if no extra aid masks are needed. */ -static size_t -rtr_aspa_set_size(struct aspa_set *aspa) +static void +rtr_aspa_set_size(const struct aspa_set *aspa, struct aspa_prep *ap) { - return aspa->num * sizeof(uint32_t); + if (aspa->num > MAX_ASPA_SPAS_COUNT) + return; + ap->datasize += aspa->num * sizeof(uint32_t); + ap->entries++; } /* @@ -531,8 +534,7 @@ rtr_recalc(void) rtr_aspa_merge(&at); RB_FOREACH(aspa, aspa_tree, &at) { - ap.datasize += rtr_aspa_set_size(aspa); - ap.entries++; + rtr_aspa_set_size(aspa, &ap); } imsg_compose(ibuf_rde, IMSG_RECONF_ASPA_PREP, 0, 0, -1, @@ -541,6 +543,13 @@ rtr_recalc(void) /* walk tree in reverse because aspa_add_set requires that */ RB_FOREACH_REVERSE(aspa, aspa_tree, &at) { struct aspa_set as = { .as = aspa->as, .num = aspa->num }; + + if (aspa->num > MAX_ASPA_SPAS_COUNT) { + log_warnx("oversized ASPA record after merge: " + "implicit withdraw of customerAS %s", + log_as(aspa->as)); + continue; + } imsg_compose(ibuf_rde, IMSG_RECONF_ASPA, 0, 0, -1, &as, offsetof(struct aspa_set, tas));