shithub: puzzles

Download patch

ref: 21193eaf9308ace41004a19180ff382ec6e8754b
parent: b3d4a4197954c21ac78b68c58dff8f84fe743ea2
author: Ben Harris <bjh21@bjh21.me.uk>
date: Thu Jan 12 15:55:56 EST 2023

Palisade: forbid moves that remove grid edges

Without this check, a corrupt save file can include a move that
removes an edge of the grid, and then is_solved() walks off the edge
of the grid causing a buffer over- or under-run.

To demonstrate the bug, load this save file in a build with
AddressSanitizer:

SAVEFILE:41:Simon Tatham's Portable Puzzle Collection
VERSION :1:1
GAME    :8:Palisade
PARAMS  :5:5x5n5
CPARAMS :5:5x5n5
DESC    :0:
NSTATES :1:2
STATEPOS:1:2
MOVE    :6:F0,0,1

--- a/palisade.c
+++ b/palisade.c
@@ -1010,10 +1010,9 @@
 {
     int w = state->shared->params.w, h = state->shared->params.h, wh = w * h;
     game_state *ret = dup_game(state);
-    int nchars, x, y, flag;
+    int nchars, x, y, flag, i;
 
     if (*move == 'S') {
-        int i;
         ++move;
         for (i = 0; i < wh && move[i]; ++i)
             ret->borders[i] =
@@ -1026,6 +1025,11 @@
     while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 &&
            !OUT_OF_BOUNDS(x, y, w, h)) {
         move += nchars;
+        for (i = 0; i < 4; i++)
+            if ((flag & BORDER(i)) &&
+                OUT_OF_BOUNDS(x+dx[i], y+dy[i], w, h))
+                /* No toggling the borders of the grid! */
+                goto badmove;
         ret->borders[y*w + x] ^= flag;
     }
 
@@ -1036,6 +1040,10 @@
                                    ret->borders);
 
     return ret;
+
+  badmove:
+    sfree(ret);
+    return NULL;
 }
 
 /* --- Drawing routines --------------------------------------------- */