From 314bc62c53d5f145aa8adac0eb7f2f3a7cb1028e Mon Sep 17 00:00:00 2001 From: claudio Date: Mon, 18 May 2026 18:36:25 +0000 Subject: [PATCH] Introduce a maximum size for a single flowspec NLRI of 4000 bytes. Enforce this in both in the parser 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. OK tb@ --- usr.sbin/bgpd/bgpd.h | 3 ++- usr.sbin/bgpd/flowspec.c | 6 +++++- usr.sbin/bgpd/parse.y | 15 +++++++++++---- usr.sbin/bgpd/rde_prefix.c | 12 ++++++++++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index cba646af2ca..67194554ff9 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.542 2026/05/12 09:12:49 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.543 2026/05/18 18:36:25 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -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; diff --git a/usr.sbin/bgpd/flowspec.c b/usr.sbin/bgpd/flowspec.c index 0b2650ca174..293e6beed82 100644 --- a/usr.sbin/bgpd/flowspec.c +++ b/usr.sbin/bgpd/flowspec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: flowspec.c,v 1.5 2023/10/23 13:07:44 claudio Exp $ */ +/* $OpenBSD: flowspec.c,v 1.6 2026/05/18 18:36:25 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker @@ -177,6 +177,10 @@ flowspec_valid(const uint8_t *buf, int len, int is_v6) 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) diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 6bb799d88a1..ebc77267c27 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.497 2026/05/18 15:49:22 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.498 2026/05/18 18:36:25 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -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; @@ -5692,6 +5691,7 @@ flow_to_flowspec(struct flowspec_context *ctx) aid = AID_FLOWSPECv6; break; default: + yyerror("unknown AID %d", ctx->aid); return NULL; } @@ -5699,9 +5699,16 @@ flow_to_flowspec(struct flowspec_context *ctx) if (ctx->components[i] != NULL) len += ctx->complen[i] + 1; - f = flowspec_alloc(aid, len); - if (f == NULL) + if (len > FLOWSPEC_SIZE_MAX) { + yyerror("flowspec too long %d > %d", len, FLOWSPEC_SIZE_MAX); return NULL; + } + + f = flowspec_alloc(aid, len); + if (f == NULL) { + yyerror("out of memory"); + return NULL; + } len = 0; for (i = FLOWSPEC_TYPE_MIN; i < FLOWSPEC_TYPE_MAX; i++) diff --git a/usr.sbin/bgpd/rde_prefix.c b/usr.sbin/bgpd/rde_prefix.c index 9b0a3449052..d1e4b944c4b 100644 --- a/usr.sbin/bgpd/rde_prefix.c +++ b/usr.sbin/bgpd/rde_prefix.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_prefix.c,v 1.61 2026/05/13 15:12:14 claudio Exp $ */ +/* $OpenBSD: rde_prefix.c,v 1.62 2026/05/18 18:36:25 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -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; @@ -424,6 +429,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) fatal(__func__);