From 067f361d9b6e2e1a0fa5d3bd62900e23b6ded4bb Mon Sep 17 00:00:00 2001
From: Evann DREUMONT <53308142+LeGmask@users.noreply.github.com>
Date: Tue, 2 Sep 2025 16:23:34 +0200
Subject: [PATCH] Nest: Function aspa_check() should return ASPA_INVALID for
 paths containing AS_SET

The aspa_check() uses as_path_getlen() to estimate the size of a buffer,
which does not work for AS_SET segments, because as_path_getlen() returns
length 1 for them regardless of their length. This may cause buffer
overflow and crash.

As AS_SET segments are not valid for ASPA verification, we can just
handle them explicitly. See https://datatracker.ietf.org/doc/html/draft-ietf-sidrops-aspa-verification#section-6

Co-Authored-By: Alarig <alarig@swordarmor.fr>

Minor changes by committer.
---
 nest/a-path.c   | 21 +++++++++++++++++++++
 nest/attrs.h    |  1 +
 nest/rt-table.c |  7 ++++++-
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/nest/a-path.c b/nest/a-path.c
index aba2c86df..6f52ccf6a 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -177,6 +177,27 @@ as_path_contains_confed(const struct adata *path)
   return 0;
 }
 
+int
+as_path_contains_set(const struct adata *path)
+{
+  const byte *pos = path->data;
+  const byte *end = pos + path->length;
+
+  while (pos < end)
+  {
+    uint type = pos[0];
+    uint slen = 2 + BS * pos[1];
+
+    if ((type == AS_PATH_SET) ||
+	(type == AS_PATH_CONFED_SET))
+      return 1;
+
+    pos += slen;
+  }
+
+  return 0;
+}
+
 struct adata *
 as_path_strip_confed(struct linpool *pool, const struct adata *path)
 {
diff --git a/nest/attrs.h b/nest/attrs.h
index 0475afa72..699b91df2 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -36,6 +36,7 @@ int as_path_16to32(byte *dst, const byte *src, uint len);
 int as_path_32to16(byte *dst, const byte *src, uint len);
 int as_path_contains_as4(const struct adata *path);
 int as_path_contains_confed(const struct adata *path);
+int as_path_contains_set(const struct adata *path);
 struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op);
 struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as);
 struct adata *as_path_to_old(struct linpool *pool, const struct adata *path);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index ee3f11882..ed364d351 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -362,7 +362,12 @@ enum aspa_result aspa_check(rtable *tab, const adata *path, bool force_upstream)
   if (as_path_contains_confed(path))
     return ASPA_INVALID;
 
-  /* Check path length */
+  /* No support for AS_SET */
+  /* See draft-ietf-sidrops-aspa-verification section 6 */
+  if (as_path_contains_set(path))
+    return ASPA_INVALID;
+
+  /* Check path length; we assume just AS_SEQUENCE segments */
   uint len = as_path_getlen(path);
   if (len == 0)
     return ASPA_INVALID;
-- 
GitLab

