Avoid release of store if there have been later allocations. Bug 2199
authorJeremy Harris <jgh146exb@wizmail.org>
Fri, 24 Nov 2017 20:22:33 +0000 (20:22 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 25 Nov 2017 16:47:03 +0000 (16:47 +0000)
doc/doc-txt/ChangeLog
src/src/receive.c

index e937ba2c7ba0952b17e7f3f54b6bfb45d6e80094..a2d9339c13daeeb41a5f25162e4da03cea9958bc 100644 (file)
@@ -59,6 +59,10 @@ JH/30 Fix a logging bug on aarch64: an unsafe routine was previously used for
       connection in response to HELO" was logged instead of the actual 4xx
       error for the HELO.
 
       connection in response to HELO" was logged instead of the actual 4xx
       error for the HELO.
 
+JH/34 Bug 2199: fix a use-after-free while reading smtp input for header lines.
+      A crafted sequence of BDAT commands could result in in-use memory beeing
+      freed.
+
 
 Exim version 4.89
 -----------------
 
 Exim version 4.89
 -----------------
index 95cf13e12a4449709781e93bf1489c4cde58b820..20672dbe91eea44d974ba39049ff383f118369d6 100644 (file)
@@ -1772,8 +1772,8 @@ for (;;)
   (and sometimes lunatic messages can have ones that are 100s of K long) we
   call store_release() for strings that have been copied - if the string is at
   the start of a block (and therefore the only thing in it, because we aren't
   (and sometimes lunatic messages can have ones that are 100s of K long) we
   call store_release() for strings that have been copied - if the string is at
   the start of a block (and therefore the only thing in it, because we aren't
-  doing any other gets), the block gets freed. We can only do this because we
-  know there are no other calls to store_get() going on. */
+  doing any other gets), the block gets freed. We can only do this release if
+  there were no allocations since the once that we want to free. */
 
   if (ptr >= header_size - 4)
     {
 
   if (ptr >= header_size - 4)
     {
@@ -1782,9 +1782,10 @@ for (;;)
     header_size *= 2;
     if (!store_extend(next->text, oldsize, header_size))
       {
     header_size *= 2;
     if (!store_extend(next->text, oldsize, header_size))
       {
+      BOOL release_ok = store_last_get[store_pool] == next->text;
       uschar *newtext = store_get(header_size);
       memcpy(newtext, next->text, ptr);
       uschar *newtext = store_get(header_size);
       memcpy(newtext, next->text, ptr);
-      store_release(next->text);
+      if (release_ok) store_release(next->text);
       next->text = newtext;
       }
     }
       next->text = newtext;
       }
     }