CVE-2017-1000369: Improper Resource Shutdown or Release (CWE-404)
value: Exim supports the use of multiple "-p" command line arguments which are malloc()'ed and never free()'ed, used in conjunction with other issues allows attackers to cause arbitrary code execution. This affects exim version 4.89 and earlier. Please note that at this time upstream has released a patch (commit 65e061b76867a9ea7aeeb535341b790b90ae6c21), but it is not known if a new point release is available that addresses this issue at this time.
CWE description: The product does not release or incorrectly releases a resource before it is made available for re-use.
CVSS v3 base score: 4
Published: 2017-06-19T16:29Z
Repository: https://github.com/Exim/exim
Language: C
Files changed: doc/doc-docbook/spec.xfpt, src/src/exim.c
Commit date: 2017-06-13 19:04:26 +0100
Commit message: Cleanup (prevent repeated use of -p/-oMr to avoid mem leak)

Diff: diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 06373ccd..7816bc26 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -4272,11 +4272,11 @@ option sets the received protocol value that is stored in
 &$received_protocol$&. However, it does not apply (and is ignored) when &%-bh%&
 or &%-bs%& is used. For &%-bh%&, the protocol is forced to one of the standard
 SMTP protocol names (see the description of &$received_protocol$& in section
 &<<SECTexpvar>>&). For &%-bs%&, the protocol is always &"local-"& followed by
 one of those same names. For &%-bS%& (batched SMTP) however, the protocol can
-be set by &%-oMr%&.
+be set by &%-oMr%&. Repeated use of this option is not supported.
 
 .vitem &%-oMs%&&~<&'host&~name'&>
 .oindex "&%-oMs%&"
 .cindex "sender" "host name, specifying for local message"
 See &%-oMa%& above for general remarks about the &%-oM%& options. The &%-oMs%&
@@ -4372,10 +4372,11 @@ For compatibility with Sendmail, this option is equivalent to
 It sets the incoming protocol and host name (for trusted callers). The
 host name and its colon can be omitted when only the protocol is to be set.
 Note the Exim already has two private options, &%-pd%& and &%-ps%&, that refer
 to embedded Perl. It is therefore impossible to set a protocol value of &`d`&
 or &`s`& using this option (but that does not seem a real limitation).
+Repeated use of this option is not supported.
 
 .vitem &%-q%&
 .oindex "&%-q%&"
 .cindex "queue runner" "starting manually"
 This option is normally restricted to admin users. However, there is a
diff --git a/src/src/exim.c b/src/src/exim.c
index 67583e58..88e11977 100644
--- a/src/src/exim.c
+++ b/src/src/exim.c
@@ -3104,11 +3104,18 @@ for (i = 1; i < argc; i++)
           message_reference = argv[++i];
         }
 
       /* -oMr: Received protocol */
 
-      else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i];
+      else if (Ustrcmp(argrest, "Mr") == 0)
+
+        if (received_protocol)
+          {
+          fprintf(stderr, "received_protocol is set already\n");
+          exit(EXIT_FAILURE);
+          }
+        else received_protocol = argv[++i];
 
       /* -oMs: Set sender host name */
 
       else if (Ustrcmp(argrest, "Ms") == 0) sender_host_name = argv[++i];
 
@@ -3200,11 +3207,19 @@ for (i = 1; i < argc; i++)
         { badarg = TRUE; break; }
       }
 
     if (*argrest != 0)
       {
-      uschar *hn = Ustrchr(argrest, ':');
+      uschar *hn;
+
+      if (received_protocol)
+        {
+        fprintf(stderr, "received_protocol is set already\n");
+        exit(EXIT_FAILURE);
+        }
+
+      hn = Ustrchr(argrest, ':');
       if (hn == NULL)
         {
         received_protocol = argrest;
         }
       else

Vulnerable code: be set by &%-oMr%&.
      else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i];
      uschar *hn = Ustrchr(argrest, ':');
Fixed code: be set by &%-oMr%&. Repeated use of this option is not supported.
Repeated use of this option is not supported.
      else if (Ustrcmp(argrest, "Mr") == 0)

        if (received_protocol)
          {
          fprintf(stderr, "received_protocol is set already\n");
          exit(EXIT_FAILURE);
          }
        else received_protocol = argv[++i];
      uschar *hn;

      if (received_protocol)
        {
        fprintf(stderr, "received_protocol is set already\n");
        exit(EXIT_FAILURE);
        }

      hn = Ustrchr(argrest, ':');