Re: Fwd: fix format security
Bruno Haible via Gnulib discussion list <[email protected]>
| Newsgroups | gmane.comp.lib.gnulib.bugs |
|---|---|
| Message-ID | <2786387.cd8oTp23Qr@cagnes> |
Simon Josefsson wrote:
> The format directive must also match the types, do msgfmt -c check that?
>
> I'm thinking if someone changed the translation file for
>
> int foo = 42;
> printf (_("foo %d"), foo);
>
> so that _("foo %d") returned "foo %s", then this would become an
> out-of-bounds memory de-reference.
Sure it does. Let's walk through an example:
$ cat foo.c
int foo = 42;
printf (_("You got %d"), foo);
$ xgettext -k_ -o foo.pot foo.c
$ cat foo.pot
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-26 15:44+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: foo.c:2
#, c-format
msgid "You got %d"
msgstr ""
Case 1: The translator uses %s instead of %d.
---------------------------------------------
$ msginit -l fr -i foo.pot; vi fr.po; cat fr.po
# French translations for PACKAGE package.
# Copyright (C) 2026 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Bruno Haible <[email protected]>, 2026.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-26 15:44+0200\n"
"PO-Revision-Date: 2026-08-26 15:47+0200\n"
"Last-Translator: Bruno Haible <[email protected]>\n"
"Language-Team: French <[email protected]>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: foo.c:2
#, c-format
msgid "You got %d"
msgstr "Vous obtenez %s"
$ : "Like po/Makefile does it"
msgmerge --for-msgfmt -o fr.gpo fr.po foo.pot && msgfmt -c --statistics --verbose -o t-fr.gmo fr.gpo && mv t-fr.gmo fr.gmo
fr.gpo:2: warning: header field 'Project-Id-Version' still has the initial default value
fr.gpo:17: format specifications in 'msgid' and 'msgstr' for argument 1 are not the same
msgfmt: found 1 fatal error
fr.gpo: 1 translated message.
$ echo $?
1
$ ls -l fr.gmo
ls: cannot access 'fr.gmo': No such file or directory
Case 2: The translator has maliciously removed the '#, c-format' line.
----------------------------------------------------------------------
$ : "Like po/Makefile does it"
msgmerge --for-msgfmt -o fr.gpo fr.po foo.pot && msgfmt -c --statistics --verbose -o t-fr.gmo fr.gpo && mv t-fr.gmo fr.gmo
fr.gpo:2: warning: header field 'Project-Id-Version' still has the initial default value
fr.gpo: 0 translated messages.
$ echo $?
0
$ ls -l fr.gmo
-rw-rw-r-- 1 bruno bruno 392 26. Aug 15:54 fr.gmo
$ msgunfmt --force-po fr.gmo
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2026-08-26 15:47+0200\n"
"Last-Translator: Bruno Haible <[email protected]>\n"
"Language-Team: French <[email protected]>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
In this case, the file is there, but the potentially dangerous message was
eliminated.
Bruno