diff --git a/src/main.c b/src/main.c index fe28bf50..5b2c9e56 100644 --- a/src/main.c +++ b/src/main.c @@ -2056,25 +2056,9 @@ int GetOnceDate(void) return OnceDate; } -static void -get_printf_escapes(char const *str, DynamicBuffer *out) -{ - char const *s = str; - while(*s) { - if (*s == '%' && *(s+1) != 0) { - s++; - DBufPutc(out, *s); - } - s++; - } -} - char const *GetErr(int r) { char const *msg; - DynamicBuffer origEscapes; - DynamicBuffer translatedEscapes; - int dangerous; if (r < 0 || r >= NumErrs) { r = E_SWERR; @@ -2085,23 +2069,5 @@ char const *GetErr(int r) return ErrMsg[r]; } - /* We need to make sure both the original and translated version - have the *SAME* printf-style escapes to avoid a malicious - translation file doing a format-string attack */ - DBufInit(&origEscapes); - DBufInit(&translatedEscapes); - - get_printf_escapes(ErrMsg[r], &origEscapes); - get_printf_escapes(msg, &translatedEscapes); - - dangerous = strcmp(DBufValue(&origEscapes), DBufValue(&translatedEscapes)); - - DBufFree(&origEscapes); - DBufFree(&translatedEscapes); - - if (dangerous) { - return ErrMsg[r]; - } else { - return msg; - } + return msg; } diff --git a/src/trans.c b/src/trans.c index 7da2bb5a..ec49e49c 100644 --- a/src/trans.c +++ b/src/trans.c @@ -35,6 +35,7 @@ typedef struct xlat { hash_table TranslationTable; static XlateItem *FindTranslation(char const *orig); +static int printf_formatters_are_safe(char const *orig, char const *translated); void TranslationTemplate(char const *in) @@ -294,7 +295,13 @@ FindTranslation(char const *orig) int InsertTranslation(char const *orig, char const *translated) { - XlateItem *item = FindTranslation(orig); + XlateItem *item; + + if (!printf_formatters_are_safe(orig, translated)) { + Eprint(tr("Invalid translation: Both original and translated must have the same printf-style formatting sequences in the same order.")); + return E_PARSE_ERR; + } + item = FindTranslation(orig); if (item) { if (!strcmp(item->translated, translated)) { /* Translation is the same; do nothing */ @@ -303,7 +310,6 @@ InsertTranslation(char const *orig, char const *translated) RemoveTranslation(item); } - /* TRANSLATE "foo" "foo" means to remove the translation */ if (strcmp(orig, "LANGID") && (!strcmp(orig, translated))) { return OK; } @@ -470,3 +476,46 @@ dump_translation_hash_stats(void) hash_table_dump_stats(&TranslationTable, ErrFp); } +static void +get_printf_escapes(char const *str, DynamicBuffer *out) +{ + char const *s = str; + while(*s) { + if (*s == '%' && *(s+1) != 0) { + + /* %% is safe and does not need to be replicated in translation */ + if (*(s+1) == '%') { + s += 2; + continue; + } + s++; + DBufPutc(out, *s); + while (*s && *(s+1) && strchr("#0- +'I%123456789.hlqLjzZt", *s)) { + s++; + DBufPutc(out, *s); + } + } + s++; + } +} + +static int +printf_formatters_are_safe(char const *orig, char const *translated) +{ + DynamicBuffer origEscapes; + DynamicBuffer translatedEscapes; + int dangerous; + + DBufInit(&origEscapes); + DBufInit(&translatedEscapes); + + get_printf_escapes(orig, &origEscapes); + get_printf_escapes(translated, &translatedEscapes); + + dangerous = strcmp(DBufValue(&origEscapes), DBufValue(&translatedEscapes)); + + if (dangerous) { + return 0; + } + return 1; +} diff --git a/tests/test.cmp b/tests/test.cmp index 6bffbe2e..584d1282 100644 --- a/tests/test.cmp +++ b/tests/test.cmp @@ -24503,6 +24503,7 @@ TRANSLATE "Function `%s' defined at %s:%d should take %d argument%s, but actuall TRANSLATE "Function `%s' redefined (previously defined at %s:%d)" "" TRANSLATE "GetValidHebDate: Bad adarbehave value %d" "" TRANSLATE "In" "" +TRANSLATE "Invalid translation: Both original and translated must have the same printf-style formatting sequences in the same order." "" TRANSLATE "Missing REM type; assuming MSG" "" TRANSLATE "No Adar A in %d" "" TRANSLATE "No substition function `%s' defined" ""