ref: e29d8a3ecad734967cdcf2d4ce222ab27e9c524b
parent: dbbe9d37500219b61132266029c1d8f42378c01c
author: Ben Harris <[email protected]>
date: Sat Oct 15 16:46:28 EDT 2022
Add an assertion to check the format of encoded parameters Whenever the midend calls encode_params, it also checks that the result is a printable ASCII string that doesn't contain '#' or ':'. Parameter strings are embedded in save files, so they have to fit within ASCII. They can't contain '#' or ':' because those delimit the parameter section of a game ID. Nothing explicitly says they can't contain control characters, but those would be a particularly egregious violation of the recommendation that parameter strings be easy to type into a shell.
--- a/midend.c
+++ b/midend.c
@@ -383,6 +383,18 @@
return me->ourgame->dup_params(me->params);
}
+static char *encode_params(midend *me, const game_params *params, bool full)
+{
+ char *encoded = me->ourgame->encode_params(params, full);
+
+ /* Assert that the params consist of printable ASCII containing
+ * neither '#' nor ':'. */
+ for (int i = 0; encoded[i]; i++)
+ assert(encoded[i] >= 32 && encoded[i] < 127 &&
+ encoded[i] != '#' && encoded[i] != ':');
+ return encoded;
+}
+
static void midend_set_timer(midend *me)
{
me->timing = (me->ourgame->is_timed &&
@@ -618,8 +630,8 @@
* We check both params and cparams, to be as safe as possible.
*/
- old = me->ourgame->encode_params(me->params, true);
- new = me->ourgame->encode_params(data->params, true);
+ old = encode_params(me, me->params, true);
+ new = encode_params(me, data->params, true);
if (strcmp(old, new)) {
/* Set a flag to distinguish this deserialise failure
* from one due to faulty decoding */
@@ -627,8 +639,8 @@
return "Undoing this new-game operation would change params";
}
- old = me->ourgame->encode_params(me->curparams, true);
- new = me->ourgame->encode_params(data->cparams, true);
+ old = encode_params(me, me->curparams, true);
+ new = encode_params(me, data->cparams, true);
if (strcmp(old, new)) {
ctx->refused = true;
return "Undoing this new-game operation would change params";
@@ -1390,7 +1402,7 @@
for (i = 0; i < menu->n_entries; i++) {
if (menu->entries[i].params) {
me->encoded_presets[menu->entries[i].id] =
- me->ourgame->encode_params(menu->entries[i].params, true);
+ encode_params(me, menu->entries[i].params, true);
} else {
preset_menu_encode_params(me, menu->entries[i].submenu);
}
@@ -1469,7 +1481,7 @@
int midend_which_preset(midend *me)
{
- char *encoding = me->ourgame->encode_params(me->params, true);
+ char *encoding = encode_params(me, me->params, true);
int i, ret;
ret = -1;
@@ -1576,7 +1588,7 @@
* the former is likely to persist across many code
* changes).
*/
- parstr = me->ourgame->encode_params(me->curparams, which == CFG_SEED);
+ parstr = encode_params(me, me->curparams, which == CFG_SEED);
assert(parstr);
if (which == CFG_DESC) {
rest = me->desc ? me->desc : "";
@@ -1720,7 +1732,7 @@
newparams = me->ourgame->dup_params(me->params);
- tmpstr = me->ourgame->encode_params(newcurparams, false);
+ tmpstr = encode_params(me, newcurparams, false);
me->ourgame->decode_params(newparams, tmpstr);
sfree(tmpstr);
@@ -1792,7 +1804,7 @@
{
char *parstr, *ret;
- parstr = me->ourgame->encode_params(me->curparams, false);
+ parstr = encode_params(me, me->curparams, false);
assert(parstr);
assert(me->desc);
ret = snewn(strlen(parstr) + strlen(me->desc) + 2, char);
@@ -1808,7 +1820,7 @@
if (!me->seedstr)
return NULL;
- parstr = me->ourgame->encode_params(me->curparams, true);
+ parstr = encode_params(me, me->curparams, true);
assert(parstr);
ret = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char);
sprintf(ret, "%s#%s", parstr, me->seedstr);
@@ -2017,7 +2029,7 @@
* The current long-term parameters structure, in full.
*/
if (me->params) {
- char *s = me->ourgame->encode_params(me->params, true);
+ char *s = encode_params(me, me->params, true);
wr("PARAMS", s);
sfree(s);
}
@@ -2026,7 +2038,7 @@
* The current short-term parameters structure, in full.
*/
if (me->curparams) {
- char *s = me->ourgame->encode_params(me->curparams, true);
+ char *s = encode_params(me, me->curparams, true);
wr("CPARAMS", s);
sfree(s);
}