From 44fc9bcbb71302946578c8f8d259f7635755e5d5 Mon Sep 17 00:00:00 2001
From: Marko Lindqvist <cazfi74@gmail.com>
Date: Mon, 24 Aug 2026 02:37:37 +0300
Subject: [PATCH 46/53] 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 | 12 ++++++++++++
 server/savegame/savegame3.c | 13 +++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/server/savegame/savegame2.c b/server/savegame/savegame2.c
index 92705d8517..73ee0b0f41 100644
--- a/server/savegame/savegame2.c
+++ b/server/savegame/savegame2.c
@@ -805,6 +805,14 @@ 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 > MAX_LEN_WORKLIST) {
+    log_sg("worklist length %d, while MAX_LEN_WORKLIST %d.",
+           pwl->length, MAX_LEN_WORKLIST);
+    pwl->length = MAX_LEN_WORKLIST;
+  } else if (pwl->length > wlist_max_length) {
+    log_sg("worklist length %d, while player's max worklist length %d.",
+           pwl->length, wlist_max_length);
+  }
 
   for (i = 0; i < pwl->length; i++) {
     kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
@@ -3680,6 +3688,10 @@ static void sg_load_player_cities(struct loaddata *loading,
   wlist_max_length = secfile_lookup_int_default(loading->file, 0,
                                                 "player%d.wl_max_length",
                                                 plrno);
+  if (wlist_max_length > MAX_LEN_WORKLIST) {
+    log_sg("wlist_max_length %d over MAX_LEN_WORKLIST (%d)",
+           wlist_max_length, MAX_LEN_WORKLIST);
+  }
 
   /* Load all cities of the player. */
   for (i = 0; i < ncities; i++) {
diff --git a/server/savegame/savegame3.c b/server/savegame/savegame3.c
index 06b768c862..3ca9532a07 100644
--- a/server/savegame/savegame3.c
+++ b/server/savegame/savegame3.c
@@ -981,6 +981,14 @@ 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 > MAX_LEN_WORKLIST) {
+    log_sg("worklist length %d, while MAX_LEN_WORKLIST %d.",
+           pwl->length, MAX_LEN_WORKLIST);
+    pwl->length = MAX_LEN_WORKLIST;
+  } else if (pwl->length > wlist_max_length) {
+    log_sg("worklist length %d, while player's max worklist length %d.",
+           pwl->length, wlist_max_length);
+  }
 
   for (i = 0; i < pwl->length; i++) {
     kind = secfile_lookup_str(file, "%s.wl_kind%d", path_str, i);
@@ -5063,6 +5071,11 @@ static void sg_load_player_cities(struct loaddata *loading,
   wlist_max_length = secfile_lookup_int_default(loading->file, 0,
                                                 "player%d.wl_max_length",
                                                 plrno);
+  if (wlist_max_length > MAX_LEN_WORKLIST) {
+    log_sg("wlist_max_length %d over MAX_LEN_WORKLIST (%d)",
+           wlist_max_length, MAX_LEN_WORKLIST);
+  }
+
   routes_max = secfile_lookup_int_default(loading->file, 0,
                                           "player%d.routes_max_length", plrno);
 
-- 
2.53.0

