shithub: puzzles

Download patch

ref: 5279fd24b2f4a51e760bfde873fe1d29547220a6
parent: c84af670b52f09e9e47587584c0559c508d4a37d
author: Ben Harris <bjh21@bjh21.me.uk>
date: Sat Jan 7 15:28:23 EST 2023

Guess: validate peg colours in decode_ui()

Peg colours in the current guess must be within the range of colours
for the current game, just as they must be for completed moves.
Otherwise is_markable() can cause a buffer overrun.

Since there's no way for decode_ui() to report an error, it just ignores
the bad peg colours.  I've also added an assertion to catch this problem
in is_markable().

The following save file demonstrates the problem when loaded in a build
with AddressSanitizer:

SAVEFILE:41:Simon Tatham's Portable Puzzle Collection
VERSION :1:1
GAME    :5:Guess
PARAMS  :9:c6p4g10Bm
CPARAMS :9:c6p4g10Bm
DESC    :8:2de917c0
UI      :7:7,7,7,7
NSTATES :1:1
STATEPOS:1:1

--- a/guess.c
+++ b/guess.c
@@ -380,6 +380,7 @@
     for (i = 0; i < params->npegs; i++) {
         int c = pegs->pegs[i];
         if (c > 0) {
+            assert(c <= params->ncolours);
             colcount->pegs[c-1]++;
             nset++;
         }
@@ -462,6 +463,9 @@
     const char *p = encoding;
     for (i = 0; i < ui->curr_pegs->npegs; i++) {
         ui->curr_pegs->pegs[i] = atoi(p);
+        if (ui->curr_pegs->pegs[i] < 0 ||
+            ui->curr_pegs->pegs[i] > ui->params.ncolours)
+            ui->curr_pegs->pegs[i] = 0; /* Remove invalid pegs. */
         while (*p && isdigit((unsigned char)*p)) p++;
         if (*p == '_') {
             /* NB: old versions didn't store holds */