From: Claudio Jeker Subject: bgpd: limit flowspec size To: tech@openbsd.org Date: Mon, 18 May 2026 14:47:10 +0200 Add a maximum size for a single flowspec rule. Currently 4000 bytes. Enforce this in both in the parsers but also in the RDE. In the RDE flowspec_valid() will error out if the lenght is too long but also pt_get_flow() and pt_add_flow() will error out. The fixed buffer in pt_get_flow() is now sized appropriately instead of using a arbitrary size. A size of 4000 is very luxurious and close to the max for regular BGP sessions. -- :wq Claudio Index: bgpctl/bgpctl.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v diff -u -p -r1.320 bgpctl.c --- bgpctl/bgpctl.c 4 Feb 2026 11:48:33 -0000 1.320 +++ bgpctl/bgpctl.c 18 May 2026 12:39:00 -0000 @@ -1971,6 +1971,8 @@ res_to_flowspec(struct parse_result *r) if (len == 0) errx(1, "no flowspec rule defined"); + if (len > FLOWSPEC_SIZE_MAX) + errx(1, "flowspec rule too long"); f = malloc(FLOWSPEC_SIZE + len); if (f == NULL) Index: bgpd/bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v diff -u -p -r1.542 bgpd.h --- bgpd/bgpd.h 12 May 2026 09:12:49 -0000 1.542 +++ bgpd/bgpd.h 18 May 2026 12:35:31 -0000 @@ -594,6 +594,7 @@ struct flowspec { uint8_t data[1]; }; #define FLOWSPEC_SIZE (offsetof(struct flowspec, data)) +#define FLOWSPEC_SIZE_MAX 4000 struct flowspec_config { RB_ENTRY(flowspec_config) entry; Index: bgpd/flowspec.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/flowspec.c,v diff -u -p -r1.5 flowspec.c --- bgpd/flowspec.c 23 Oct 2023 13:07:44 -0000 1.5 +++ bgpd/flowspec.c 18 May 2026 12:35:31 -0000 @@ -177,6 +177,10 @@ flowspec_valid(const uint8_t *buf, int l if (len == 0) return -1; + /* flowspec rule is too large */ + if (len > FLOWSPEC_SIZE_MAX) + return -1; + while (len > 0) { l = flowspec_next_component(buf, len, is_v6, &type); if (l == -1) Index: bgpd/parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v diff -u -p -r1.496 parse.y --- bgpd/parse.y 13 May 2026 09:25:11 -0000 1.496 +++ bgpd/parse.y 18 May 2026 12:37:40 -0000 @@ -1201,7 +1201,6 @@ flowspec : FLOWSPEC af { f = flow_to_flowspec(curflow); if (f == NULL) { - yyerror("out of memory"); free($5); flow_free(curflow); curflow = NULL; @@ -5688,6 +5687,7 @@ flow_to_flowspec(struct flowspec_context aid = AID_FLOWSPECv6; break; default: + yyerror("unknown AID %d", ctx->aid); return NULL; } @@ -5695,9 +5695,16 @@ flow_to_flowspec(struct flowspec_context if (ctx->components[i] != NULL) len += ctx->complen[i] + 1; + if (len > FLOWSPEC_SIZE_MAX) { + yyerror("flowspec to long %d > %d", len, FLOWSPEC_SIZE_MAX); + return NULL; + } + f = flowspec_alloc(aid, len); - if (f == NULL) + if (f == NULL) { + yyerror("out of memory"); return NULL; + } len = 0; for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++) Index: bgpd/rde_prefix.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde_prefix.c,v diff -u -p -r1.61 rde_prefix.c --- bgpd/rde_prefix.c 13 May 2026 15:12:14 -0000 1.61 +++ bgpd/rde_prefix.c 18 May 2026 12:35:31 -0000 @@ -405,11 +405,16 @@ pt_get_flow(struct flowspec *f) struct pt_entry *needle; union { struct pt_entry_flow flow; - uint8_t buf[4096]; + uint8_t buf[FLOWSPEC_SIZE_MAX + PT_FLOW_SIZE]; } x; needle = (struct pt_entry *)&x.flow; + if (f->len > FLOWSPEC_SIZE_MAX) { + log_warnx("%s: flowspec too long", __func__); + return NULL; + } + memset(needle, 0, PT_FLOW_SIZE); needle->aid = f->aid; needle->len = f->len + PT_FLOW_SIZE; @@ -423,6 +428,9 @@ pt_add_flow(struct flowspec *f) { struct pt_entry *p; int len = f->len + PT_FLOW_SIZE; + + if (f->len > FLOWSPEC_SIZE_MAX) + fatalx("%s: flowspec too long", __func__); p = malloc(len); if (p == NULL)