31affc
From ab7848a4a30d79c7433a1689ba1ea18897b73453 Mon Sep 17 00:00:00 2001
31affc
From: Mark Reynolds <mreynolds@redhat.com>
31affc
Date: Tue, 18 Sep 2018 16:39:26 -0400
31affc
Subject: [PATCH] Bug 1624004 - potential denial of service attack
31affc
31affc
Bug: a search request passing 8MB of NULL bytes as search attributes will
31affc
     keep one thread busy for a long time.
31affc
     The reason is that the attr array is copied/normalized to the searchattrs in
31affc
     the search operation and does this using charray_add() which iterates thru
31affc
     the array to determine the size of the array and then allocate one element more.
31affc
     so this means we iterat 8 million times an array with a then average size of
31affc
     4 million elements.
31affc
31affc
Fix: We already have traversed the array once and know the size, so we can allocate
31affc
     the needed size once and only copy the element.
31affc
     In addition we check for the kind of degenerated attributes "" as used in this
31affc
     test scenario.
31affc
     So the fix will reject invalid attr liste and improve performance for valid ones
31affc
31affc
https://bugzilla.redhat.com/show_bug.cgi?id=1624004
31affc
---
31affc
 ldap/servers/slapd/search.c | 16 ++++++++++++++--
31affc
 ldap/servers/slapd/unbind.c |  4 ++--
31affc
 2 files changed, 16 insertions(+), 4 deletions(-)
31affc
31affc
diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c
31affc
index 731c6519e..dc26fc4d2 100644
31affc
--- a/ldap/servers/slapd/search.c
31affc
+++ b/ldap/servers/slapd/search.c
31affc
@@ -209,6 +209,7 @@ do_search(Slapi_PBlock *pb)
31affc
     if (attrs != NULL) {
31affc
         char *normaci = slapi_attr_syntax_normalize("aci");
31affc
         int replace_aci = 0;
31affc
+        int attr_count = 0;
31affc
         if (!normaci) {
31affc
             normaci = slapi_ch_strdup("aci");
31affc
         } else if (strcasecmp(normaci, "aci")) {
31affc
@@ -218,9 +219,19 @@ do_search(Slapi_PBlock *pb)
31affc
         /*
31affc
          * . store gerattrs if any
31affc
          * . add "aci" once if "*" is given
31affc
+         * . check that attrs are not degenerated
31affc
          */
31affc
         for (i = 0; attrs[i] != NULL; i++) {
31affc
             char *p = NULL;
31affc
+            attr_count++;
31affc
+
31affc
+            if ( attrs[i][0] == '\0') {
31affc
+                log_search_access(pb, base, scope, fstr, "invalid attribute request");
31affc
+                send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
31affc
+                slapi_ch_free_string(&normaci);
31affc
+                goto free_and_return;
31affc
+            }
31affc
+
31affc
             /* check if @<objectclass> is included */
31affc
             p = strchr(attrs[i], '@');
31affc
             if (p) {
31affc
@@ -244,6 +255,7 @@ do_search(Slapi_PBlock *pb)
31affc
             } else if (strcmp(attrs[i], LDAP_ALL_USER_ATTRS /* '*' */) == 0) {
31affc
                 if (!charray_inlist(attrs, normaci)) {
31affc
                     charray_add(&attrs, slapi_ch_strdup(normaci));
31affc
+                    attr_count++;
31affc
                 }
31affc
             } else if (replace_aci && (strcasecmp(attrs[i], "aci") == 0)) {
31affc
                 slapi_ch_free_string(&attrs[i]);
31affc
@@ -263,13 +275,13 @@ do_search(Slapi_PBlock *pb)
31affc
             }
31affc
         } else {
31affc
             /* return the chopped type, e.g., "sn" */
31affc
-            operation->o_searchattrs = NULL;
31affc
+            operation->o_searchattrs = (char **)slapi_ch_calloc(sizeof(char *), attr_count+1);
31affc
             for (i = 0; attrs[i] != NULL; i++) {
31affc
                 char *type;
31affc
                 type = slapi_attr_syntax_normalize_ext(attrs[i],
31affc
                                                        ATTR_SYNTAX_NORM_ORIG_ATTR);
31affc
                 /* attrs[i] is consumed */
31affc
-                charray_add(&operation->o_searchattrs, attrs[i]);
31affc
+                operation->o_searchattrs[i] = attrs[i];
31affc
                 attrs[i] = type;
31affc
             }
31affc
         }
31affc
diff --git a/ldap/servers/slapd/unbind.c b/ldap/servers/slapd/unbind.c
31affc
index 90f7b1546..686e27a8e 100644
31affc
--- a/ldap/servers/slapd/unbind.c
31affc
+++ b/ldap/servers/slapd/unbind.c
31affc
@@ -87,8 +87,8 @@ do_unbind(Slapi_PBlock *pb)
31affc
     /* pass the unbind to all backends */
31affc
     be_unbindall(pb_conn, operation);
31affc
 
31affc
+free_and_return:;
31affc
+
31affc
     /* close the connection to the client */
31affc
     disconnect_server(pb_conn, operation->o_connid, operation->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
31affc
-
31affc
-free_and_return:;
31affc
 }
31affc
-- 
31affc
2.17.1
31affc