summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Steuck <greg@nest.cx>2021-11-22 21:38:47 -0800
committerMarge Bot <ben+marge-bot@smart-cactus.org>2021-11-25 08:36:09 -0500
commite2c48b98c6a201eae09b4c84e73bb77608d03ec8 (patch)
treef45e4cfc42b3c473b21ecd6f8088ac8f48bcb419
parent20101d9ca016fca17605dd4f641640a60bdadca4 (diff)
downloadhaskell-e2c48b98c6a201eae09b4c84e73bb77608d03ec8.tar.gz
Kill a use of %n format specifier
This format has been used as a security exploit vector for decades now. Some operating systems (OpenBSD, Android, MSVC). It is targeted for removal in C2X standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2834.htm This requires extending the debug message function to return the number of bytes written (like printf(3)), to permit %n format specifier in one in one invocation of statsPrintf() in report_summary(). Implemented by Matthias Kilian (kili<AT>outback.escape.de)
-rw-r--r--rts/RtsMessages.c13
-rw-r--r--rts/Stats.c16
-rw-r--r--rts/include/rts/Messages.h7
3 files changed, 21 insertions, 15 deletions
diff --git a/rts/RtsMessages.c b/rts/RtsMessages.c
index 9b165faea7..33be410001 100644
--- a/rts/RtsMessages.c
+++ b/rts/RtsMessages.c
@@ -36,7 +36,7 @@
// Default to the stdio implementation of these hooks.
RtsMsgFunction *fatalInternalErrorFn = rtsFatalInternalErrorFn;
-RtsMsgFunction *debugMsgFn = rtsDebugMsgFn;
+RtsMsgFunctionRetLen *debugMsgFn = rtsDebugMsgFn;
RtsMsgFunction *errorMsgFn = rtsErrorMsgFn;
RtsMsgFunction *sysErrorMsgFn = rtsSysErrorMsgFn;
@@ -102,10 +102,10 @@ debugBelch(const char*s, ...)
va_end(ap);
}
-void
+int
vdebugBelch(const char*s, va_list ap)
{
- (*debugMsgFn)(s,ap);
+ return (*debugMsgFn)(s,ap);
}
/* -----------------------------------------------------------------------------
@@ -285,16 +285,16 @@ rtsSysErrorMsgFn(const char *s, va_list ap)
#endif
}
-void
+int
rtsDebugMsgFn(const char *s, va_list ap)
{
+ int r;
#if defined(mingw32_HOST_OS)
/* Ensure we're in text mode so newlines get encoded properly. */
int mode = _setmode (_fileno(stderr), _O_TEXT);
if (isGUIApp())
{
char buf[BUFSIZE];
- int r;
r = vsnprintf(buf, BUFSIZE, s, ap);
if (r > 0 && r < BUFSIZE) {
@@ -305,12 +305,13 @@ rtsDebugMsgFn(const char *s, va_list ap)
#endif
{
/* don't fflush(stdout); WORKAROUND bug in Linux glibc */
- vfprintf(stderr, s, ap);
+ r = vfprintf(stderr, s, ap);
fflush(stderr);
}
#if defined(mingw32_HOST_OS)
_setmode (_fileno(stderr), mode);
#endif
+ return r;
}
diff --git a/rts/Stats.c b/rts/Stats.c
index 90e3e7b396..0c22f7e42b 100644
--- a/rts/Stats.c
+++ b/rts/Stats.c
@@ -69,7 +69,7 @@ static Time *GC_coll_cpu = NULL;
static Time *GC_coll_elapsed = NULL;
static Time *GC_coll_max_pause = NULL;
-static void statsPrintf( char *s, ... ) GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
+static int statsPrintf( char *s, ... ) GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
static void statsFlush( void );
static void statsClose( void );
@@ -995,8 +995,10 @@ static void report_summary(const RTSSummaryStats* sum)
for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
int prefix_length = 0;
- statsPrintf("%*s" "gen[%" FMT_Word32 "%n",
- col_width[0], "", g, &prefix_length);
+ prefix_length = statsPrintf("%*s" "gen[%" FMT_Word32,
+ col_width[0], "", g);
+ if (prefix_length < 0)
+ prefix_length = 0;
prefix_length -= col_width[0];
int suffix_length = col_width[1] + prefix_length;
suffix_length =
@@ -1716,19 +1718,21 @@ void getRTSStats( RTSStats *s )
Dumping stuff in the stats file, or via the debug message interface
-------------------------------------------------------------------------- */
-void
+int
statsPrintf( char *s, ... )
{
+ int ret = 0;
FILE *sf = RtsFlags.GcFlags.statsFile;
va_list ap;
va_start(ap,s);
if (sf == NULL) {
- vdebugBelch(s,ap);
+ ret = vdebugBelch(s,ap);
} else {
- vfprintf(sf, s, ap);
+ ret = vfprintf(sf, s, ap);
}
va_end(ap);
+ return ret;
}
static void
diff --git a/rts/include/rts/Messages.h b/rts/include/rts/Messages.h
index dbaf37bbc7..b19c02de3d 100644
--- a/rts/include/rts/Messages.h
+++ b/rts/include/rts/Messages.h
@@ -85,20 +85,21 @@ void vsysErrorBelch(const char *s, va_list ap);
void debugBelch(const char *s, ...)
GNUC3_ATTRIBUTE(format (PRINTF, 1, 2));
-void vdebugBelch(const char *s, va_list ap);
+int vdebugBelch(const char *s, va_list ap);
/* Hooks for redirecting message generation: */
typedef void RtsMsgFunction(const char *, va_list);
+typedef int RtsMsgFunctionRetLen(const char *, va_list);
extern RtsMsgFunction *fatalInternalErrorFn;
-extern RtsMsgFunction *debugMsgFn;
+extern RtsMsgFunctionRetLen *debugMsgFn;
extern RtsMsgFunction *errorMsgFn;
/* Default stdio implementation of the message hooks: */
extern RtsMsgFunction rtsFatalInternalErrorFn;
-extern RtsMsgFunction rtsDebugMsgFn;
+extern RtsMsgFunctionRetLen rtsDebugMsgFn;
extern RtsMsgFunction rtsErrorMsgFn;
extern RtsMsgFunction rtsSysErrorMsgFn;