summaryrefslogtreecommitdiffstats
path: root/charset.c
diff options
context:
space:
mode:
authorKevin McCarthy <kevin@8t8.us>2022-04-08 20:19:27 -0700
committerKevin McCarthy <kevin@8t8.us>2022-04-12 11:07:15 -0700
commitf26d304b22e18942e4af6f98f826006cf27e8fde (patch)
tree61791e189db1c8406a73f16980213b79236affe7 /charset.c
parent4ae494ca621842c97f16da0bba61689ab458556c (diff)
Fix integer overflow in mutt_convert_string().
In the case of a *very* large message header (which is possible via a compressed encrypted message) it's possible to overflow the incorrect assignment of strlen() to an int local variable. Thanks to Tavis Ormandy for the bug report and patch, which this commit is based upon. Although Tavis wasn't able to find an exploit, it was almost possible to make ob small and obl big, which would have allowed attacker control of a heap corruption. Change the strlen() to assign directly to ibl (of type size_t). This prevents signed to unsigned conversion of len to ibl, which make the attack almost possible. Note that ibl should reflect the number of bytes to be converted by iconv(), so the change of ibl to strlen() instead of (strlen() + 1) is intentional, and correct. ob is allocated with an additional byte for a trailing nul, which is appended after the conversion.
Diffstat (limited to 'charset.c')
-rw-r--r--charset.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/charset.c b/charset.c
index 9d523259..d5e0102d 100644
--- a/charset.c
+++ b/charset.c
@@ -33,6 +33,7 @@
#include <dirent.h>
#include <unistd.h>
#include <errno.h>
+#include <stdint.h>
#include "mutt.h"
#include "charset.h"
@@ -489,7 +490,6 @@ int mutt_convert_string (char **ps, const char *from, const char *to, int flags)
if (to && from && (cd = mutt_iconv_open (to, from, flags)) != (iconv_t)-1)
{
- int len;
ICONV_CONST char *ib;
char *buf, *ob;
size_t ibl, obl;
@@ -503,8 +503,14 @@ int mutt_convert_string (char **ps, const char *from, const char *to, int flags)
else
outrepl = "?";
- len = strlen (s);
- ib = s, ibl = len + 1;
+ ib = s;
+ ibl = strlen (s);
+ if (ibl >= SIZE_MAX / MB_LEN_MAX)
+ {
+ iconv_close (cd);
+ return -1;
+ }
+
obl = MB_LEN_MAX * ibl;
ob = buf = safe_malloc (obl + 1);