Discussion:
macOS 10.13 vasnprintf crash
comex
2017-07-07 19:23:07 UTC
Permalink
Hi,

In macOS 10.13 High Sierra (currently in beta), and presumably other
Apple OSes moving forward, the printf-family functions intentionally
crash if the format string contains %n and is located in writable
memory. This is an exploit mitigation, similar to existing behavior
in glibc (with _FORTIFY_SOURCE=2) and Windows.

By default, gnulib's implementation of vasnprintf calls snprintf with
such format strings. lib/vasnprintf.c has an explicit test for glibc
and Windows to avoid crashing there (relevant code copied below for
reference). I suppose this test should either be extended to include
__APPLE__, or replaced with a configure-based test. (There's an
existing test in m4/printf.m4 that checks whether %n works, including
with writable memory, but it doesn't seem to prevent vasnprintf from
triggering the crash.)

Thanks.

--

#if USE_SNPRINTF
# if !(((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) &&
!defined __UCLIBC__) || ((defined _WIN32 || defined __WIN32__) &&
! defined __CYGWIN__))
fbp[1] = '%';
fbp[2] = 'n';
fbp[3] = '\0';
# else
/* On glibc2 systems from glibc >= 2.3 - probably also older
ones - we know that snprintf's return value conforms to
ISO C 99: the tests gl_SNPRINTF_RETVAL_C99 and
gl_SNPRINTF_TRUNCATION_C99 pass.
Therefore we can avoid using %n in this situation.
On glibc2 systems from 2004-10-18 or newer, the use of %n
in format strings in writable memory may crash the program
(if compiled with _FORTIFY_SOURCE=2), so we should avoid it
in this situation. */
/* On native Windows systems (such as mingw), we can avoid using
%n because:
- Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
snprintf does not write more than the specified number
of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
'4', '5', '6' into buf, not '4', '5', '\0'.)
- Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
allows us to recognize the case of an insufficient
buffer size: it returns -1 in this case.
On native Windows systems (such as mingw) where the OS is
Windows Vista, the use of %n in format strings by default
crashes the program. See
<http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and

<http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx>
So we should avoid %n in this situation. */
fbp[1] = '\0';
# endif
#else
fbp[1] = '\0';
#endif
Paul Eggert
2017-07-07 21:13:49 UTC
Permalink
Thanks for the heads-up. Although I don't use macOS I installed the attached;
please give it a try.
Bruno Haible
2017-07-07 21:33:58 UTC
Permalink
Hi Paul,
Post by Paul Eggert
Thanks for the heads-up. Although I don't use macOS I installed the attached;
please give it a try.
You beat me by 10 minutes :) Meanwhile I had verified that one can drop the
word "presumably": According to the comments in m4/printf.m4, %n is not needed
on Mac OS X 10.3 or newer. Versions older than 10.3 are most likely not in use
any more.


diff --git a/ChangeLog b/ChangeLog
index 176abb9..304b373 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,5 @@
2017-07-07 Paul Eggert <***@cs.ucla.edu>
+ Bruno Haible <***@clisp.org>

vasnprintf: port to macOS 10.13
Problem reported by comex in:
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index fecaf27..2e4eb19 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -4869,10 +4869,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#endif
*fbp = dp->conversion;
#if USE_SNPRINTF
-# if ! (((__GLIBC__ > 2 \
- || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
- && !defined __UCLIBC__) \
- || (defined __APPLE__ && defined __MACH__) \
+# if ! (((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
+ && !defined __UCLIBC__) \
+ || (defined __APPLE__ && defined __MACH__) \
|| ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
fbp[1] = '%';
fbp[2] = 'n';
@@ -4887,9 +4886,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
in format strings in writable memory may crash the program
(if compiled with _FORTIFY_SOURCE=2), so we should avoid it
in this situation. */
- /* macOS 10.13 High Sierra behaves like glibc with
- _FORTIFY_SOURCE=2, and older macOS releases
- presumably do not need %n. */
+ /* On Mac OS X 10.3 or newer, we know that snprintf's return
+ value conforms to ISO C 99: the tests gl_SNPRINTF_RETVAL_C99
+ and gl_SNPRINTF_TRUNCATION_C99 pass.
+ Therefore we can avoid using %n in this situation.
+ On Mac OS X 10.13 or newer, the use of %n in format strings
+ in writable memory by default crashes the program, so we
+ should avoid it in this situation. */
/* On native Windows systems (such as mingw), we can avoid using
%n because:
- Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
comex
2017-07-07 23:06:22 UTC
Permalink
Post by Paul Eggert
Thanks for the heads-up. Although I don't use macOS I installed the
attached; please give it a try.
Hi,

I can confirm that the latest two commits fixed the problem: GNU RCS
crashes after running `gnulib-tool --add-import` on the prior commit
and rebuilding, and works after doing the same with the latest commit.
Loading...