Git fork

gettext: avoid using gettext if the locale dir is not present

In cc5e1bf99247 (gettext: avoid initialization if the locale dir is not
present, 2018-04-21) Git was taught to avoid a costly gettext start-up
when there are not even any localized messages to work with.

But we still called `gettext()` and `ngettext()` functions.

Which caused a problem in Git for Windows when the libgettext that is
consumed from the MSYS2 project stopped using a runtime prefix in
https://github.com/msys2/MINGW-packages/pull/10461

Due to that change, we now use an unintialized gettext machinery that
might get auto-initialized _using an unintended locale directory_:
`C:\mingw64\share\locale`.

Let's record the fact when the gettext initialization was skipped, and
skip calling the gettext functions accordingly.

This addresses CVE-2023-25815.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

+10 -1
+4
gettext.c
··· 109 setlocale(LC_CTYPE, "C"); 110 } 111 112 void git_setup_gettext(void) 113 { 114 const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); ··· 129 setlocale(LC_TIME, ""); 130 init_gettext_charset("git"); 131 textdomain("git"); 132 133 free(p); 134 }
··· 109 setlocale(LC_CTYPE, "C"); 110 } 111 112 + int git_gettext_enabled = 0; 113 + 114 void git_setup_gettext(void) 115 { 116 const char *podir = getenv(GIT_TEXT_DOMAIN_DIR_ENVIRONMENT); ··· 131 setlocale(LC_TIME, ""); 132 init_gettext_charset("git"); 133 textdomain("git"); 134 + 135 + git_gettext_enabled = 1; 136 137 free(p); 138 }
+6 -1
gettext.h
··· 31 int use_gettext_poison(void); 32 33 #ifndef NO_GETTEXT 34 void git_setup_gettext(void); 35 int gettext_width(const char *s); 36 #else 37 static inline void git_setup_gettext(void) 38 { 39 use_gettext_poison(); /* getenv() reentrancy paranoia */ ··· 48 { 49 if (!*msgid) 50 return ""; 51 - return use_gettext_poison() ? "# GETTEXT POISON #" : gettext(msgid); 52 } 53 54 static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) ··· 56 { 57 if (use_gettext_poison()) 58 return "# GETTEXT POISON #"; 59 return ngettext(msgid, plu, n); 60 } 61
··· 31 int use_gettext_poison(void); 32 33 #ifndef NO_GETTEXT 34 + extern int git_gettext_enabled; 35 void git_setup_gettext(void); 36 int gettext_width(const char *s); 37 #else 38 + #define git_gettext_enabled (0) 39 static inline void git_setup_gettext(void) 40 { 41 use_gettext_poison(); /* getenv() reentrancy paranoia */ ··· 50 { 51 if (!*msgid) 52 return ""; 53 + return use_gettext_poison() ? "# GETTEXT POISON #" : 54 + !git_gettext_enabled ? msgid : gettext(msgid); 55 } 56 57 static inline FORMAT_PRESERVING(1) FORMAT_PRESERVING(2) ··· 59 { 60 if (use_gettext_poison()) 61 return "# GETTEXT POISON #"; 62 + if (!git_gettext_enabled) 63 + return n == 1 ? msgid : plu; 64 return ngettext(msgid, plu, n); 65 } 66