Commit 452990d13e for frr

commit 452990d13e99bfc310faefd596840ac9249cc99e
Author: Akhilesh Akhade <aakhade@nvidia.com>
Date:   Mon Nov 2 18:51:41 2026 +0200

    zebra: fix crash on explicit Wide LIB start below Wide LIB start

    The Explicit Wide LIB is the tail of the Wide LIB and has no end of its
    own, but nothing kept its start inside the Wide LIB:

        format usid-f3216
         wide-local-id-block start 1000 end 1010
         wide-local-id-block explicit start 0

    The Wide LIB is an array of (wlib_end - wlib_start + 1) entries, indexed
    by the offset of the SID function from wlib_start. The explicit
    allocation path, however, decides that a function belongs to the Wide
    LIB by comparing it against ewlib_start. A function below wlib_start
    passes that check, and the unsigned offset wraps, so zebra indexes far
    past the end of the array and faults.

    Requesting a uA SID with function 500 against the ranges above indexes
    the array at 500 - 1000, which wraps to 4294966796. At 32 bytes per
    entry that is roughly 137 GB past the allocation.

    Reject any configuration that would leave the Explicit Wide LIB start
    below the Wide LIB start. The two ranges are configured independently
    and either can be reset to its default, so all four commands that move
    them are checked. Only the lower bound is enforced: an Explicit Wide LIB
    start above wlib_end just leaves the range empty, which is harmless, and
    rejecting it would make the Wide LIB impossible to move.

    Clamp ewlib_start to wlib_start in the alloc and release paths as well.
    That is unreachable once the ranges are validated, but the Wide LIB
    index is otherwise unchecked, so it keeps a future caller from faulting.

    Signed-off-by: Akhilesh Akhade <aakhade@nvidia.com>

diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index 891f1d4071..6b89c13721 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -1546,7 +1546,11 @@ static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block,
 			uint32_t elib_end = format->config.usid.elib_end;
 			uint32_t wlib_start = format->config.usid.wlib_start;
 			uint32_t wlib_end = format->config.usid.wlib_end;
-			uint32_t ewlib_start = format->config.usid.ewlib_start;
+			/*
+			 * The Wide LIB is indexed relative to wlib_start, so the EWLIB
+			 * range must not start below it
+			 */
+			uint32_t ewlib_start = MAX(format->config.usid.ewlib_start, wlib_start);
 			uint32_t ewlib_end = wlib_end;
 			uint32_t *sid_wide_func_ptr = NULL;

@@ -2203,7 +2207,11 @@ static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block,
 			uint32_t elib_start = format->config.usid.elib_start;
 			uint32_t elib_end = format->config.usid.elib_end;
 			uint32_t wlib_start = format->config.usid.wlib_start;
-			uint32_t ewlib_start = format->config.usid.ewlib_start;
+			/*
+			 * The Wide LIB is indexed relative to wlib_start, so the EWLIB
+			 * range must not start below it
+			 */
+			uint32_t ewlib_start = MAX(format->config.usid.ewlib_start, wlib_start);
 			uint32_t ewlib_end = format->config.usid.wlib_end;
 			uint32_t *sid_wide_func_ptr = NULL;

diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 4fdf184b41..79e495b250 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -1473,6 +1473,14 @@ DEFPY(srv6_sid_format_usid_wlib,
 		return CMD_WARNING_CONFIG_FAILED;
 	}

+	if (start > format->config.usid.ewlib_start) {
+		vty_out(vty,
+			"%% Wide LIB start (%" PRId64
+			") cannot be greater than the Explicit Wide LIB start (%u)\n",
+			start, format->config.usid.ewlib_start);
+		return CMD_WARNING_CONFIG_FAILED;
+	}
+
 	format->config.usid.wlib_start = start;
 	format->config.usid.wlib_end = end;

@@ -1493,19 +1501,28 @@ DEFPY(no_srv6_sid_format_usid_wlib,
       "Specify the end value for the Wide LIB\n")
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+	uint32_t wlib_start = 0, wlib_end = 0;

 	if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) {
-		format->config.usid.wlib_start =
-			SRV6_SID_FORMAT_USID_F3216_WLIB_START;
-		format->config.usid.wlib_end =
-			SRV6_SID_FORMAT_USID_F3216_WLIB_END;
+		wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START;
+		wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END;
 	} else if (strmatch(format->name, SRV6_SID_FORMAT_USID_F4816_NAME)) {
-		format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F4816_WLIB_START;
-		format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F4816_WLIB_END;
+		wlib_start = SRV6_SID_FORMAT_USID_F4816_WLIB_START;
+		wlib_end = SRV6_SID_FORMAT_USID_F4816_WLIB_END;
 	} else {
 		assert(0);
 	}

+	if (wlib_start > format->config.usid.ewlib_start) {
+		vty_out(vty,
+			"%% Default Wide LIB start (%u) would be greater than the Explicit Wide LIB start (%u), remove the Explicit Wide LIB first\n",
+			wlib_start, format->config.usid.ewlib_start);
+		return CMD_WARNING_CONFIG_FAILED;
+	}
+
+	format->config.usid.wlib_start = wlib_start;
+	format->config.usid.wlib_end = wlib_end;
+
 	/* Notify zclients that the format has changed */
 	zebra_srv6_sid_format_changed_cb(format);

@@ -1522,6 +1539,14 @@ DEFPY(srv6_sid_format_usid_wide_lib_explicit,
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);

+	if (start < format->config.usid.wlib_start) {
+		vty_out(vty,
+			"%% Explicit Wide LIB start (%" PRId64
+			") cannot be less than Wide LIB start (%u)\n",
+			start, format->config.usid.wlib_start);
+		return CMD_WARNING_CONFIG_FAILED;
+	}
+
 	format->config.usid.ewlib_start = start;

 	/* Notify zclients that the format has changed */
@@ -1540,15 +1565,24 @@ DEFPY(no_srv6_sid_format_usid_wide_lib_explicit,
       "Specify the start value for the Explicit Wide LIB\n")
 {
 	VTY_DECLVAR_CONTEXT(srv6_sid_format, format);
+	uint32_t ewlib_start = 0;

 	if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME))
-		format->config.usid.ewlib_start =
-			SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
+		ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START;
 	else if (strmatch(format->name, SRV6_SID_FORMAT_USID_F4816_NAME))
-		format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F4816_EWLIB_START;
+		ewlib_start = SRV6_SID_FORMAT_USID_F4816_EWLIB_START;
 	else
 		assert(0);

+	if (ewlib_start < format->config.usid.wlib_start) {
+		vty_out(vty,
+			"%% Default Explicit Wide LIB start (%u) would be less than the Wide LIB start (%u), remove the Wide LIB first\n",
+			ewlib_start, format->config.usid.wlib_start);
+		return CMD_WARNING_CONFIG_FAILED;
+	}
+
+	format->config.usid.ewlib_start = ewlib_start;
+
 	/* Notify zclients that the format has changed */
 	zebra_srv6_sid_format_changed_cb(format);