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