Post by Rich Felker Post by Rich Felker
- The Big Bikeshed: where to find locale files? These will be somewhat
musl-specific (to the extent that no other implementation uses the
design I have in mind, though it would be easy for others to use
it), so there's no existing practice to simply adopt. The files are
not machine-specific (we'll support either endianness .mo file) so
/usr/share (or other prefix variants) is the natural base location.
One idea for this: just don't accept anything except the built-in
locales (C, C.UTF-8, POSIX) and absolute pathnames. For suid programs,
the latter could be rejected completely (the safest and probably what
we should do) or restricted to a set of reasonable paths where each
path component is checked for permissions.
Another idea is pulling the search path from /etc/musl-locale.conf or
similar. Obviously this is not the most friendly to Rune's usage case,
but it would just be one more hard-coded path to override in the
custom build, or if absolute pathnames were also accepted for locales
the support for /etc/musl-locale.conf could just be stripped out.
From a usability standpoint, I think it's desirable to have some sort
of search path, even if absolute pathnames are also supported.
Consider mixed environments where the user has something like
LANG=fr_FR.UTF-8 for glibc programs; assuming the corresponding locale
is also installed for musl, the reasonable user expectation is that
musl-linked programs also use French messages, time formatting,
glibc honors the non-POSIX environment variable LOCPATH to control its
search for locales. While this is something of a consideration for
applications trying to avoid unwanted environment-influenced behavior
for security purposes or otherwise, it's not a big conformance problem
since setlocale already depends on the environment anyway (and thus
can't be called safely in parallel with modifications to the
environment, per POSIX). We could honor the same variable and just
append "/musl/" to the value (this would be nice from the standpoint
of not introducing another variable apps have to be aware of when they
want to filter it) but that's somewhat ugly since the glibc one is
intended to point to a "lib" (arch-specific) dir whereas musl's is
portable data. Using a separate variable might be preferable if we
even want to support an environment variable as a way to configure
this at runtime -- and I think doing so may be valuable since users
may want locales that are not installed by the system administrator.
In light of glibc CVE-2014-0475, which I'm not sure is even really a
proper "vulnerability" but rather just a complication of the standard
locale semantics that makes it hard to write secure programs without
filtering out locale vars from untrusted sources, a major goal I'd
like to pursue is minimizing the potential security impact of an
untrusted/malicious locale file. Obviously suid/AT_SECURE programs
should not even honor locale files except possibly from a hard-coded
trusted source, but ideally even programs without formally elevated
privilegs -- think gitolite type setups with ssh authorized_keys --
would not yield code execution or information leak when fed a
malicious locale file.
Here are the security aspects I have in mind:
- For libc itself (obviously we can't control application use of
gettext), only translate literal strings, never printf/scanf format
strings. For dlerror this requires some refactoring of the message
strings but otherwise I think this property is easy to satisfy. The
purpose of this property is to prevent format string injection via
locales and limit the scope of bad messages to literal copying of
those messages into the program output.
- Avoid loading as a locale any file which was not intended to be a
locale. This entails checking the magic number, sanity-checking the
headers, and also doing a single gettext-type string lookup for a
key string associated with our locale file format (a specialization
of general mo files). If the key is not found, the file can be
rejected; it's probably a mo file but not one that satisfies the
needs of libc for the requested locale category. The purpose of this
check is to prevent disclosure of contents of files that were not
intended to be locales.
- During gettext lookup (binary search), validate all offsets as lying
within the address range of the mapping. The purpose of this check
is to preclude information disclosure due to reading strings from
locations outside the mapping.
Obviously as long as mmap is used, there is a possibility of DoS via
file truncation and SIGBUS. I don't think it's worth trying to work
around this since the scope is limited to crashing your own programs
(or allowing someone else to crash them if you use a locale file
writable by someone else). As previoysly discussed for zoneinfo, one
option would be to malloc, read, and validate (rather than mmap), but
IMO this is cost-prohibitive.