From 1c71b1248ededfa446a7ef01bdf9b56f232553da Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Tue, 25 Aug 2026 03:12:34 +0300
Subject: [PATCH 5/6] savegame: Fix Heap Buffer Overflow in worklist_load()

Reported by Tristan

See RM #2161

Signed-off-by: Marko Lindqvist <cazfi74@gmail.com>
---
 server/savegame/savegame2.c | 11 +++++++++++
 server/savegame/savegame3.c | 11 +++++++++++
 2 files changed, 22 insertions(+)

diff --git a/server/savegame/savegame2.c b/server/savegame/savegame2.c
index 64baf0532e..f92f2991a6 100644
--- a/server/savegame/savegame2.c
+++ b/server/savegame/savegame2.c
@@ -764,6 +764,11 @@ static void worklist_load(struct section_file *file, int wlist_max_length,
   worklist_init(pwl);
   pwl->length = secfile_lookup_int_default(file, 0,
                                            "%s.wl_length", path_str);
+  if (pwl->length > wlist_max_length) {
+    log_sg("worklist length %d, while player's max worklist length %d.",
+           pwl->length, wlist_max_length);
+    pwl->length = wlist_max_length;
+  }
 
   for (i = 0; i < pwl->length; i++) {
     kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
@@ -3378,6 +3383,12 @@ static void sg_load_player_cities(struct loaddata *loading,
     wlist_max_length = MAX(wlist_max_length, wl_length);
   }
 
+  if (wlist_max_length > MAX_LEN_WORKLIST) {
+    log_sg("wlist_max_length %d over MAX_LEN_WORKLIST (%d)",
+           wlist_max_length, MAX_LEN_WORKLIST);
+    wlist_max_length = MAX_LEN_WORKLIST;
+  }
+
   /* Load all cities of the player. */
   for (i = 0; i < ncities; i++) {
     char buf[32];
diff --git a/server/savegame/savegame3.c b/server/savegame/savegame3.c
index c451ab6262..b4c1ba0b8e 100644
--- a/server/savegame/savegame3.c
+++ b/server/savegame/savegame3.c
@@ -954,6 +954,11 @@ static void worklist_load(struct section_file *file, int wlist_max_length,
   worklist_init(pwl);
   pwl->length = secfile_lookup_int_default(file, 0,
                                            "%s.wl_length", path_str);
+  if (pwl->length > wlist_max_length) {
+    log_sg("worklist length %d, while player's max worklist length %d.",
+           pwl->length, wlist_max_length);
+    pwl->length = wlist_max_length;
+  }
 
   for (i = 0; i < pwl->length; i++) {
     kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
@@ -4752,6 +4757,12 @@ static void sg_load_player_cities(struct loaddata *loading,
     wlist_max_length = MAX(wlist_max_length, wl_length);
   }
 
+  if (wlist_max_length > MAX_LEN_WORKLIST) {
+    log_sg("wlist_max_length %d over MAX_LEN_WORKLIST (%d)",
+           wlist_max_length, MAX_LEN_WORKLIST);
+    wlist_max_length = MAX_LEN_WORKLIST;
+  }
+
   /* Load all cities of the player. */
   for (i = 0; i < ncities; i++) {
     char buf[32];
-- 
2.53.0

