Blame SOURCES/0041-Ticket-49471-heap-buffer-overflow-in-ss_unescape.patch

081b2d
From 25844922007eea26f78d18171e51be3aa7b5e949 Mon Sep 17 00:00:00 2001
816ad1
From: Thierry Bordaz <tbordaz@redhat.com>
816ad1
Date: Wed, 6 Dec 2017 15:14:57 +0100
816ad1
Subject: [PATCH] Ticket 49471 - heap-buffer-overflow in ss_unescape
816ad1
816ad1
Bug Description:
816ad1
	Two problems here
816ad1
		- when searching for wildcard and escape char, ss_unescape assumes the string
816ad1
		  is at least 3 chars longs. So memcmp can overflow a shorter string
816ad1
		- while splitting a string into substring pattern, it loops over
816ad1
		  wildcard and can overpass the string end
816ad1
816ad1
Fix Description:
816ad1
	For the first problem, it checks the string size is long enough to memcmp
816ad1
        a wildcard or an escape
816ad1
	For the second it exits from the loop  as soon as the end of the string is reached
816ad1
816ad1
https://pagure.io/389-ds-base/issue/49471
816ad1
816ad1
Reviewed by: William Brown
816ad1
816ad1
Platforms tested: F23
816ad1
816ad1
Flag Day: no
816ad1
816ad1
Doc impact: no
816ad1
816ad1
(cherry picked from commit 5991388ce75fba8885579b769711d57acfd43cd3)
816ad1
---
816ad1
 dirsrvtests/tests/tickets/ticket49471_test.py | 79 +++++++++++++++++++++++++++
081b2d
 ldap/servers/plugins/collation/orfilter.c     | 14 +++--
081b2d
 2 files changed, 87 insertions(+), 6 deletions(-)
816ad1
 create mode 100644 dirsrvtests/tests/tickets/ticket49471_test.py
816ad1
816ad1
diff --git a/dirsrvtests/tests/tickets/ticket49471_test.py b/dirsrvtests/tests/tickets/ticket49471_test.py
816ad1
new file mode 100644
816ad1
index 000000000..0456a5182
816ad1
--- /dev/null
816ad1
+++ b/dirsrvtests/tests/tickets/ticket49471_test.py
816ad1
@@ -0,0 +1,79 @@
816ad1
+import logging
816ad1
+import pytest
816ad1
+import os
816ad1
+import time
816ad1
+import ldap
816ad1
+from lib389._constants import *
816ad1
+from lib389.topologies import topology_st as topo
816ad1
+from lib389 import Entry
816ad1
+
816ad1
+DEBUGGING = os.getenv("DEBUGGING", default=False)
816ad1
+if DEBUGGING:
816ad1
+    logging.getLogger(__name__).setLevel(logging.DEBUG)
816ad1
+else:
816ad1
+    logging.getLogger(__name__).setLevel(logging.INFO)
816ad1
+log = logging.getLogger(__name__)
816ad1
+
816ad1
+
816ad1
+USER_CN='user_'
816ad1
+def _user_get_dn(no):
816ad1
+    cn = '%s%d' % (USER_CN, no)
816ad1
+    dn = 'cn=%s,ou=people,%s' % (cn, SUFFIX)
816ad1
+    return (cn, dn)
816ad1
+
816ad1
+def add_user(server, no, desc='dummy', sleep=True):
816ad1
+    (cn, dn) = _user_get_dn(no)
816ad1
+    log.fatal('Adding user (%s): ' % dn)
816ad1
+    server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'inetuser', 'userSecurityInformation'],
816ad1
+                             'cn': [cn],
816ad1
+                             'description': [desc],
816ad1
+                             'sn': [cn],
816ad1
+                             'description': ['add on that host']})))
816ad1
+    if sleep:
816ad1
+        time.sleep(2)
816ad1
+
816ad1
+def test_ticket49471(topo):
816ad1
+    """Specify a test case purpose or name here
816ad1
+
816ad1
+    :id: 457ab172-9455-4eb2-89a0-150e3de5993f
816ad1
+    :setup: Fill in set up configuration here
816ad1
+    :steps:
816ad1
+        1. Fill in test case steps here
816ad1
+        2. And indent them like this (RST format requirement)
816ad1
+    :expectedresults:
816ad1
+        1. Fill in the result that is expected
816ad1
+        2. For each test step
816ad1
+    """
816ad1
+
816ad1
+    # If you need any test suite initialization,
816ad1
+    # please, write additional fixture for that (including finalizer).
816ad1
+    # Topology for suites are predefined in lib389/topologies.py.
816ad1
+
816ad1
+    # If you need host, port or any other data about instance,
816ad1
+    # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid)
816ad1
+
816ad1
+    S1 = topo.standalone
816ad1
+    add_user(S1, 1)
816ad1
+
816ad1
+    Filter = "(description:2.16.840.1.113730.3.3.2.1.1.6:=\*on\*)"
816ad1
+    ents = S1.search_s(SUFFIX, ldap.SCOPE_SUBTREE, Filter)
816ad1
+    assert len(ents) == 1
816ad1
+
816ad1
+    #
816ad1
+    # The following is for the test 49491
816ad1
+    # skipped here else it crashes in ASAN
816ad1
+    #Filter = "(description:2.16.840.1.113730.3.3.2.1.1.6:=\*host)"
816ad1
+    #ents = S1.search_s(SUFFIX, ldap.SCOPE_SUBTREE, Filter)
816ad1
+    #assert len(ents) == 1
816ad1
+
816ad1
+    if DEBUGGING:
816ad1
+        # Add debugging steps(if any)...
816ad1
+        pass
816ad1
+
816ad1
+
816ad1
+if __name__ == '__main__':
816ad1
+    # Run isolated
816ad1
+    # -s for DEBUG mode
816ad1
+    CURRENT_FILE = os.path.realpath(__file__)
816ad1
+    pytest.main("-s %s" % CURRENT_FILE)
816ad1
+
816ad1
diff --git a/ldap/servers/plugins/collation/orfilter.c b/ldap/servers/plugins/collation/orfilter.c
081b2d
index 5a2d8a0ab..a98d90219 100644
816ad1
--- a/ldap/servers/plugins/collation/orfilter.c
816ad1
+++ b/ldap/servers/plugins/collation/orfilter.c
081b2d
@@ -313,12 +313,12 @@ ss_unescape(struct berval *val)
081b2d
     char *t = s;
081b2d
     char *limit = s + val->bv_len;
816ad1
     while (s < limit) {
081b2d
-        if (!memcmp(s, "\\2a", 3) ||
081b2d
-            !memcmp(s, "\\2A", 3)) {
816ad1
+        if (((limit - s) >= 3) &&
816ad1
+                (!memcmp(s, "\\2a", 3) || !memcmp(s, "\\2A", 3))) {
081b2d
             *t++ = WILDCARD;
081b2d
             s += 3;
081b2d
-        } else if (!memcmp(s, "\\5c", 3) ||
081b2d
-                   !memcmp(s, "\\5C", 3)) {
816ad1
+        } else if ((limit - s) >= 3 &&
816ad1
+                (!memcmp(s, "\\5c", 3) || !memcmp(s, "\\5C", 3))) {
081b2d
             *t++ = '\\';
081b2d
             s += 3;
081b2d
         } else {
081b2d
@@ -409,13 +409,15 @@ ss_filter_values(struct berval *pattern, int *query_op)
081b2d
         switch (*p) {
081b2d
         case WILDCARD:
081b2d
             result[n++] = ss_filter_value(s, p - s, &val);
081b2d
-            while (++p != plimit && *p == WILDCARD)
081b2d
-                ;
816ad1
+            while (p != plimit && *p == WILDCARD) p++;
081b2d
             s = p;
081b2d
             break;
081b2d
         default:
081b2d
             break;
081b2d
         }
816ad1
+        if (p >= plimit) {
816ad1
+            break;
816ad1
+        }
816ad1
     }
816ad1
     if (p != s || s == plimit) {
081b2d
         result[n++] = ss_filter_value(s, p - s, &val);
816ad1
-- 
816ad1
2.13.6
816ad1