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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.