From 5279fd24b2f4a51e760bfde873fe1d29547220a6 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Sat, 7 Jan 2023 20:28:23 +0000 Subject: [PATCH] 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 --- guess.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/guess.c b/guess.c index f635fec..37195b4 100644 --- a/guess.c +++ b/guess.c @@ -380,6 +380,7 @@ static bool is_markable(const game_params *params, pegrow pegs) 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 @@ static void decode_ui(game_ui *ui, const char *encoding) 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 */