Download raw body.
bgpd: limit flowspec size
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)
bgpd: limit flowspec size