[exim-cvs] Taint: check on supplied buffer vs. list when ext…

Top Page
Delete this message
Reply to this message
Author: Exim Git Commits Mailing List
Date:  
To: exim-cvs
Subject: [exim-cvs] Taint: check on supplied buffer vs. list when extracting elements
Gitweb: https://git.exim.org/exim.git/commitdiff/ba74fb8d95d2e9af2122e0a95c4d5334b4f0466c
Commit:     ba74fb8d95d2e9af2122e0a95c4d5334b4f0466c
Parent:     ab1604ea9202d3dbc0fd7fd230dc693d83d3092c
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Sun Apr 5 23:21:40 2020 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sun Apr 5 23:27:18 2020 +0100


    Taint: check on supplied buffer vs. list when extracting elements
---
 src/src/acl.c             |  2 +-
 src/src/daemon.c          |  6 +++---
 src/src/functions.h       |  6 +++++-
 src/src/host.c            |  3 ++-
 src/src/match.c           |  5 ++---
 src/src/string.c          |  7 +++++--
 src/src/transports/pipe.c |  2 +-
 src/src/transports/smtp.c |  8 +++-----
 src/src/verify.c          | 24 ++++++++++++------------
 test/confs/0027           |  2 +-
 test/confs/0029           |  4 ++--
 test/confs/0251           |  2 +-
 test/confs/0306           |  2 +-
 test/confs/0307           |  2 +-
 test/stderr/0023          |  2 +-
 15 files changed, 41 insertions(+), 36 deletions(-)


diff --git a/src/src/acl.c b/src/src/acl.c
index 9ed0057..02251b1 100644
--- a/src/src/acl.c
+++ b/src/src/acl.c
@@ -1600,7 +1600,7 @@ an error if options are given for items that don't expect them.

uschar *slash = Ustrchr(arg, '/');
const uschar *list = arg;
-uschar *ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size);
+uschar *ss = string_nextinlist(&list, &sep, NULL, 0);
verify_type_t * vp;

if (!ss) goto BAD_VERIFY;
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 3b21d27..6560da1 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -1353,7 +1353,7 @@ if (f.daemon_listen && !f.inetd_wait_mode)

     list = override_local_interfaces;
     sep = 0;
-    while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+    while ((s = string_nextinlist(&list, &sep, NULL, 0)))
       {
       uschar joinstr[4];
       gstring ** gp = Ustrpbrk(s, ".:") ? &new_local_interfaces : &new_smtp_port;
@@ -1391,13 +1391,13 @@ if (f.daemon_listen && !f.inetd_wait_mode)


   list = daemon_smtp_port;
   sep = 0;
-  while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
+  while ((s = string_nextinlist(&list, &sep, NULL, 0)))
     pct++;
   default_smtp_port = store_get((pct+1) * sizeof(int), FALSE);
   list = daemon_smtp_port;
   sep = 0;
   for (pct = 0;
-       (s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size));
+       (s = string_nextinlist(&list, &sep, NULL, 0));
        pct++)
     {
     if (isdigit(*s))
diff --git a/src/src/functions.h b/src/src/functions.h
index efd039b..8206c48 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -521,7 +521,6 @@ extern int     string_is_ip_address(const uschar *, int *);
 #ifdef SUPPORT_I18N
 extern BOOL    string_is_utf8(const uschar *);
 #endif
-extern uschar *string_nextinlist(const uschar **, int *, uschar *, int);
 extern const uschar *string_printing2(const uschar *, BOOL);
 extern uschar *string_split_message(uschar *);
 extern uschar *string_unprinting(uschar *);
@@ -549,6 +548,11 @@ extern gstring *string_vformat_trc(gstring *, const uschar *, unsigned,
 extern uschar *string_open_failed_trc(int, const uschar *, unsigned,
             const char *, ...) PRINTF_FUNCTION(4,5);


+#define string_nextinlist(lp, sp, b, l) \
+    string_nextinlist_trc((lp), (sp), (b), (l), US __FUNCTION__, __LINE__)
+extern uschar *string_nextinlist_trc(const uschar **listptr, int *separator, uschar *buffer, int buflen,
+            const uschar * func, int line);
+
 extern int     strcmpic(const uschar *, const uschar *);
 extern int     strncmpic(const uschar *, const uschar *, int);
 extern uschar *strstric(uschar *, uschar *, BOOL);
diff --git a/src/src/host.c b/src/src/host.c
index 3361d59..1426bff 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -729,6 +729,7 @@ host_build_ifacelist(const uschar *list, uschar *name)
 int sep = 0;
 uschar *s;
 ip_address_item * yield = NULL, * last = NULL, * next;
+BOOL taint = is_tainted(list);


while ((s = string_nextinlist(&list, &sep, NULL, 0)))
{
@@ -747,7 +748,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0)))
address above. The field in the ip_address_item is large enough to hold an
IPv6 address. */

- next = store_get(sizeof(ip_address_item), FALSE);
+ next = store_get(sizeof(ip_address_item), taint);
next->next = NULL;
Ustrcpy(next->address, s);
next->port = port;
diff --git a/src/src/match.c b/src/src/match.c
index a0899bf..6da1d27 100644
--- a/src/src/match.c
+++ b/src/src/match.c
@@ -446,7 +446,6 @@ BOOL ignore_defer = FALSE;
const uschar *list;
uschar *sss;
uschar *ot = NULL;
-uschar buffer[1024];

/* Save time by not scanning for the option name when we don't need it. */

@@ -506,12 +505,12 @@ else

/* For an unnamed list, use the expanded version in comments */

-HDEBUG(D_any) if (ot == NULL) ot = string_sprintf("%s in \"%s\"?", name, list);
+HDEBUG(D_any) if (!ot) ot = string_sprintf("%s in \"%s\"?", name, list);

/* Now scan the list and process each item in turn, until one of them matches,
or we hit an error. */

-while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
+while ((sss = string_nextinlist(&list, &sep, NULL, 0)))
{
uschar * ss = sss;

diff --git a/src/src/string.c b/src/src/string.c
index 4ef2fee..80cf49f 100644
--- a/src/src/string.c
+++ b/src/src/string.c
@@ -863,7 +863,8 @@ Returns:     pointer to buffer, containing the next substring,
 */


 uschar *
-string_nextinlist(const uschar **listptr, int *separator, uschar *buffer, int buflen)
+string_nextinlist_trc(const uschar **listptr, int *separator, uschar *buffer, int buflen,
+ const uschar * func, int line)
 {
 int sep = *separator;
 const uschar *s = *listptr;
@@ -906,6 +907,8 @@ sep_is_special = iscntrl(sep);
 if (buffer)
   {
   int p = 0;
+  if (is_tainted(s) && !is_tainted(buffer))
+    die_tainted(US"string_nextinlist", func, line);
   for (; *s; s++)
     {
     if (*s == sep && (*(++s) != sep || sep_is_special)) break;
@@ -1638,7 +1641,7 @@ doesn't seem much we can do about that. */


 va_start(ap, format);
 (void) string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE,
-    0, format, ap);
+    SVFMT_REBUFFER, format, ap);
 string_from_gstring(g);
 gstring_release_unused(g);
 va_end(ap);
diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c
index 6a7f150..27422bd 100644
--- a/src/src/transports/pipe.c
+++ b/src/src/transports/pipe.c
@@ -678,7 +678,7 @@ if (envlist)
     return FALSE;
     }


-while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)))
+while ((ss = string_nextinlist(&envlist, &envsep, NULL, 0)))
    {
    if (envcount > nelem(envp) - 2)
      {
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index fc5bb78..5fb22bc 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -911,11 +911,9 @@ names = string_copyn(expand_nstring[1], expand_nlength[1]);
 for (au = auths, authnum = 0; au; au = au->next, authnum++) if (au->client)
   {
   const uschar * list = names;
-  int sep = ' ';
-  uschar name[32];
-
-  while (string_nextinlist(&list, &sep, name, sizeof(name)))
-    if (strcmpic(au->public_name, name) == 0)
+  uschar * s;
+  for (int sep = ' '; s = string_nextinlist(&list, &sep, NULL, 0); )
+    if (strcmpic(au->public_name, s) == 0)
       { authbits |= BIT(authnum); break; }
   }


diff --git a/src/src/verify.c b/src/src/verify.c
index 4b584c0..cd9df1f 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -2260,7 +2260,7 @@ for (header_line * h = header_list; h && yield == OK; h = h->next)

colon = Ustrchr(h->text, ':');
s = colon + 1;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);

   /* Loop for multiple addresses in the header, enabling group syntax. Note
   that we have to reset this after the header has been scanned. */
@@ -2339,7 +2339,7 @@ for (header_line * h = header_list; h && yield == OK; h = h->next)
     /* Advance to the next address */


     s = ss + (terminator ? 1 : 0);
-    while (isspace(*s)) s++;
+    Uskip_whitespace(&s);
     }   /* Next address */


   f.parse_allow_group = FALSE;
@@ -3383,11 +3383,13 @@ dns_scan dnss;
 tree_node *t;
 dnsbl_cache_block *cb;
 int old_pool = store_pool;
-uschar query[256];         /* DNS domain max length */
+uschar * query;
+int qlen;


/* Construct the specific query domainname */

-if (!string_format(query, sizeof(query), "%s.%s", prepend, domain))
+query = string_sprintf("%s.%s", prepend, domain);
+if ((qlen = Ustrlen(query)) >= 256)
   {
   log_write(0, LOG_MAIN|LOG_PANIC, "dnslist query is too long "
     "(ignored): %s...", query);
@@ -3422,7 +3424,7 @@ else


   else
     {    /* Set up a tree entry to cache the lookup */
-    t = store_get(sizeof(tree_node) + Ustrlen(query), is_tainted(query));
+    t = store_get(sizeof(tree_node) + qlen + 1 + 1, is_tainted(query));
     Ustrcpy(t->name, query);
     t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block), FALSE);
     (void)tree_insertnode(&dnsbl_cache, t);
@@ -3529,7 +3531,6 @@ if (cb->rc == DNS_SUCCEED)
     for (da = cb->rhs; da; da = da->next)
       {
       int ipsep = ',';
-      uschar ip[46];
       const uschar *ptr = iplist;
       uschar *res;


@@ -3537,8 +3538,8 @@ if (cb->rc == DNS_SUCCEED)

       if (!bitmask)
     {
-        while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))))
-          if (Ustrcmp(CS da->address, ip) == 0)
+        while ((res = string_nextinlist(&ptr, &ipsep, NULL, 0)))
+          if (Ustrcmp(CS da->address, res) == 0)
         break;
     }


@@ -3560,9 +3561,9 @@ if (cb->rc == DNS_SUCCEED)

         /* Scan the returned addresses, skipping any that are IPv6 */


-        while ((res = string_nextinlist(&ptr, &ipsep, ip, sizeof(ip))))
+        while ((res = string_nextinlist(&ptr, &ipsep, NULL, 0)))
           {
-          if (host_aton(ip, address) != 1) continue;
+          if (host_aton(res, address) != 1) continue;
           if ((address[0] & mask) == address[0]) break;
           }
         }
@@ -3732,7 +3733,6 @@ int sep = 0;
 int defer_return = FAIL;
 const uschar *list = *listptr;
 uschar *domain;
-uschar buffer[1024];
 uschar revadd[128];        /* Long enough for IPv6 address */


 /* Indicate that the inverted IP address is not yet set up */
@@ -3745,7 +3745,7 @@ dns_init(FALSE, FALSE, FALSE);    /*XXX dnssec? */


/* Loop through all the domains supplied, until something matches */

-while ((domain = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
+while ((domain = string_nextinlist(&list, &sep, NULL, 0)))
   {
   int rc;
   BOOL bitmask = FALSE;
diff --git a/test/confs/0027 b/test/confs/0027
index 19bdaa0..c2d0f01 100644
--- a/test/confs/0027
+++ b/test/confs/0027
@@ -39,7 +39,7 @@ data3:
 acl_rcpt:
   warn     set acl_m_1 = ${acl {data}}
   accept endpass
-         acl = ${tr{$local_part}{:}{\n}}
+         acl = ${bless:${tr{$local_part}{:}{\n}}}
   deny   message = this message should not occur



diff --git a/test/confs/0029 b/test/confs/0029
index 09e7796..342e6a5 100644
--- a/test/confs/0029
+++ b/test/confs/0029
@@ -16,8 +16,8 @@ begin acl
 check_rcpt:
   require  verify = sender
            verify = sender=\
-                    ${if eq {${domain:$sender_address}}{test.ex}\
-                    {${local_part:$sender_address}@???}\
+                    ${if eq {$sender_address_domain}{test.ex}\
+                    {$sender_address_local_part@???}\
                     {$sender_address}}
   accept


diff --git a/test/confs/0251 b/test/confs/0251
index ea6b78f..9c95152 100644
--- a/test/confs/0251
+++ b/test/confs/0251
@@ -39,7 +39,7 @@ exeter_listr:
   require_files = DIR/aux-fixed/TESTNUM.restrict.${local_part}
   retry_use_local_part
   senders = ${if exists{DIR/aux-fixed/TESTNUM.restrict.${local_part}} \
-    {DIR/aux-fixed/TESTNUM.restrict.${local_part}}{zzzz}}
+    {${bless:DIR/aux-fixed/TESTNUM.restrict.${local_part}}}{zzzz}}
   syntax_errors_to = ${local_part}-request@???


 exeter_listf:
diff --git a/test/confs/0306 b/test/confs/0306
index 779e155..b3c18f4 100644
--- a/test/confs/0306
+++ b/test/confs/0306
@@ -33,7 +33,7 @@ r2:
   driver = redirect
   domains = lists.test.ex
   senders = ${if exists {DIR/aux-fixed/TESTNUM/$local_part}\
-             {lsearch;DIR/aux-fixed/TESTNUM/$local_part}{*}}
+             {lsearch;${bless:DIR/aux-fixed/TESTNUM/$local_part}}{*}}
   file = DIR/aux-fixed/TESTNUM/${bless:$local_part}
   forbid_pipe
   forbid_file
diff --git a/test/confs/0307 b/test/confs/0307
index 1f61ca3..81857ec 100644
--- a/test/confs/0307
+++ b/test/confs/0307
@@ -22,7 +22,7 @@ r1:
   senders = ${if eq {$local_part_suffix}{-request}{*}\
             {\
             ${if exists {DIR/aux-fixed/TESTNUM/$local_part}\
-             {lsearch;DIR/aux-fixed/TESTNUM/$local_part}{*}}\
+             {lsearch;${bless:DIR/aux-fixed/TESTNUM/$local_part}}{*}}\
             }}
   file = DIR/aux-fixed/TESTNUM/${bless:$local_part$local_part_suffix}
   forbid_pipe
diff --git a/test/stderr/0023 b/test/stderr/0023
index 8111c9f..ddf364b 100644
--- a/test/stderr/0023
+++ b/test/stderr/0023
@@ -1254,7 +1254,7 @@ LOG: H=[30.30.30.30] F=<a@???> rejected RCPT <x@y>: domain=test.e

 >>> check dnslists = test.ex/$sender_address_domain+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
 >>>                = test.ex/y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END
 >>> dnslists check: test.ex/y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END

-LOG: dnslist query is too long (ignored): y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+...
+LOG: dnslist query is too long (ignored): y+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+extra+END.test.ex...
>>> deny: condition test failed in ACL "acl_31_31_31"
>>> processing "accept" (TESTSUITE/test-config 168)
>>> accept: condition test succeeded in ACL "acl_31_31_31"