Don't allow a translation entry if printf-style formatters differ.

This commit is contained in:
Dianne Skoll
2025-01-16 12:53:23 -05:00
parent 436526c27d
commit 8d0743dd3e
3 changed files with 53 additions and 37 deletions

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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" ""