From f7ded3ce666ca8e27226dfa05b1e6b8636728441 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 29 Apr 2026 14:00:08 +0200 Subject: Fix possible stack overflow in es_printf for %.100f format. * configure.ac: Add test for snprintf. * src/gpgrt-int.h: Do not re-map snprintf if KEEP_SYSTEM_SNPRINTF is defined. * src/estream-printf.c (KEEP_SYSTEM_SNPRINTF): Define. (pr_float): Increase static buffer size. Use snprintf for long double. * tests/t-printf.c: Include float.h. (check_large_float): New. -- GnuPG-bug-id: 8240 Reported-by: Dirk Mueller (AI) --- src/estream-printf.c | 26 ++++++++++++++++++++++++-- src/gpgrt-int.h | 4 +++- 2 files changed, 27 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/estream-printf.c b/src/estream-printf.c index 8e71db7..058ca71 100644 --- a/src/estream-printf.c +++ b/src/estream-printf.c @@ -71,6 +71,7 @@ */ +#define KEEP_SYSTEM_SNPRINTF 1 /* Disable our snprintf re-mapping here. */ #ifdef HAVE_CONFIG_H # include #endif @@ -1073,7 +1074,7 @@ pr_float (estream_printf_out_t outfnc, void *outfncarg, int use_dbl = 0; #endif double afloat; - char numbuf[350]; + char numbuf[450]; /* See comment above the sprintf. */ char formatstr[20]; char *p, *pend; size_t n; @@ -1129,9 +1130,30 @@ pr_float (estream_printf_out_t outfnc, void *outfncarg, if ((arg->flags & FLAG_ALT_CONV)) *--p = '#'; *--p = '%'; + + /* On the size of NUMBUF: A double value (e.g. DBL_MAX) can have up + * to 309 decimal digits before the decimal point. When formatted + * with a precision of 100 (`%.100f`), the resulting string can have + * up to 411 characters (309 integer digits + 1 decimal point + 100 + * fractional digits + 1 nul). With long double it is worse and in + * theory we should not use a static buffer but allocate a large + * one. However, platforms with support for long double will very + * likley also support snprintf which can then be used to throw an + * error on truncation. */ #ifdef HAVE_LONG_DOUBLE if (use_dbl) - sprintf (numbuf, p, adblfloat); + { +# ifdef HAVE_SNPRINTF + rc = snprintf (numbuf, sizeof numbuf, p, adblfloat); +# else + rc = -1; /* Not supported - should not happen. */ +# endif + if (rc < 0 || rc >= sizeof numbuf) + { + _set_errno (EINVAL); + return -1; + } + } else #endif /*HAVE_LONG_DOUBLE*/ sprintf (numbuf, p, afloat); diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h index f67eec7..d373435 100644 --- a/src/gpgrt-int.h +++ b/src/gpgrt-int.h @@ -480,9 +480,11 @@ const char *_gpgrt_fname_get (gpgrt_stream_t stream); #include "estream-printf.h" -/* Make sure we always use our snprintf */ +/* Make sure we always use our snprintf (except for estream-printf.c) */ +#ifndef KEEP_SYSTEM_SNPRINTF #undef snprintf #define snprintf _gpgrt_estream_snprintf +#endif #if HAVE_W32_SYSTEM -- cgit