fix CVE-2020-10700 and CVE-2020-10704
This commit is contained in:
parent
b406be5258
commit
7cef557ed7
222
CVE-2020-10700-1.patch
Normal file
222
CVE-2020-10700-1.patch
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
From 0e77fa7747d789bd8c9256373498a352251f6877 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
Date: Mon, 30 Mar 2020 09:44:20 +0000
|
||||||
|
Subject: [PATCH 1/4] CVE-2020-10700: dsdb: Add test for ASQ and ASQ in
|
||||||
|
combination with paged_results
|
||||||
|
|
||||||
|
Thanks to Andrei Popa <andrei.popa@next-gen.ro> for finding,
|
||||||
|
reporting and working with us to diagnose this issue!
|
||||||
|
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14331
|
||||||
|
|
||||||
|
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
---
|
||||||
|
selftest/knownfail.d/asq | 1 +
|
||||||
|
source4/dsdb/tests/python/asq.py | 171 +++++++++++++++++++++++++++++++
|
||||||
|
source4/selftest/tests.py | 1 +
|
||||||
|
3 files changed, 173 insertions(+)
|
||||||
|
create mode 100644 selftest/knownfail.d/asq
|
||||||
|
create mode 100644 source4/dsdb/tests/python/asq.py
|
||||||
|
|
||||||
|
diff --git a/selftest/knownfail.d/asq b/selftest/knownfail.d/asq
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000000..eb0e3e0aba1
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/selftest/knownfail.d/asq
|
||||||
|
@@ -0,0 +1 @@
|
||||||
|
+samba4.asq.python\(ad_dc_default\).__main__.ASQLDAPTest.test_asq_paged
|
||||||
|
\ No newline at end of file
|
||||||
|
diff --git a/source4/dsdb/tests/python/asq.py b/source4/dsdb/tests/python/asq.py
|
||||||
|
new file mode 100644
|
||||||
|
index 00000000000..a32c9f40cd3
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/source4/dsdb/tests/python/asq.py
|
||||||
|
@@ -0,0 +1,171 @@
|
||||||
|
+#!/usr/bin/env python3
|
||||||
|
+#
|
||||||
|
+# Test ASQ LDAP control behaviour in Samba
|
||||||
|
+# Copyright (C) Andrew Bartlett 2019-2020
|
||||||
|
+#
|
||||||
|
+# Based on Unit tests for the notification control
|
||||||
|
+# Copyright (C) Stefan Metzmacher 2016
|
||||||
|
+#
|
||||||
|
+# This program is free software; you can redistribute it and/or modify
|
||||||
|
+# it under the terms of the GNU General Public License as published by
|
||||||
|
+# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
+# (at your option) any later version.
|
||||||
|
+#
|
||||||
|
+# This program is distributed in the hope that it will be useful,
|
||||||
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
+# GNU General Public License for more details.
|
||||||
|
+#
|
||||||
|
+# You should have received a copy of the GNU General Public License
|
||||||
|
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
+
|
||||||
|
+import optparse
|
||||||
|
+import sys
|
||||||
|
+import os
|
||||||
|
+import random
|
||||||
|
+
|
||||||
|
+sys.path.insert(0, "bin/python")
|
||||||
|
+import samba
|
||||||
|
+from samba.tests.subunitrun import SubunitOptions, TestProgram
|
||||||
|
+
|
||||||
|
+import samba.getopt as options
|
||||||
|
+
|
||||||
|
+from samba.auth import system_session
|
||||||
|
+from samba import ldb
|
||||||
|
+from samba.samdb import SamDB
|
||||||
|
+from samba.ndr import ndr_unpack
|
||||||
|
+from samba import gensec
|
||||||
|
+from samba.credentials import Credentials
|
||||||
|
+import samba.tests
|
||||||
|
+
|
||||||
|
+from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError
|
||||||
|
+from ldb import ERR_TIME_LIMIT_EXCEEDED, ERR_ADMIN_LIMIT_EXCEEDED, ERR_UNWILLING_TO_PERFORM
|
||||||
|
+from ldb import Message
|
||||||
|
+
|
||||||
|
+parser = optparse.OptionParser("large_ldap.py [options] <host>")
|
||||||
|
+sambaopts = options.SambaOptions(parser)
|
||||||
|
+parser.add_option_group(sambaopts)
|
||||||
|
+parser.add_option_group(options.VersionOptions(parser))
|
||||||
|
+# use command line creds if available
|
||||||
|
+credopts = options.CredentialsOptions(parser)
|
||||||
|
+parser.add_option_group(credopts)
|
||||||
|
+subunitopts = SubunitOptions(parser)
|
||||||
|
+parser.add_option_group(subunitopts)
|
||||||
|
+opts, args = parser.parse_args()
|
||||||
|
+
|
||||||
|
+if len(args) < 1:
|
||||||
|
+ parser.print_usage()
|
||||||
|
+ sys.exit(1)
|
||||||
|
+
|
||||||
|
+url = args[0]
|
||||||
|
+
|
||||||
|
+lp = sambaopts.get_loadparm()
|
||||||
|
+creds = credopts.get_credentials(lp)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class ASQLDAPTest(samba.tests.TestCase):
|
||||||
|
+
|
||||||
|
+ def setUp(self):
|
||||||
|
+ super(ASQLDAPTest, self).setUp()
|
||||||
|
+ self.ldb = samba.Ldb(url, credentials=creds, session_info=system_session(lp), lp=lp)
|
||||||
|
+ self.base_dn = self.ldb.get_default_basedn()
|
||||||
|
+ self.NAME_ASQ="asq_" + format(random.randint(0, 99999), "05")
|
||||||
|
+ self.OU_NAME_ASQ= self.NAME_ASQ + "_ou"
|
||||||
|
+ self.ou_dn = ldb.Dn(self.ldb, "ou=" + self.OU_NAME_ASQ + "," + str(self.base_dn))
|
||||||
|
+
|
||||||
|
+ samba.tests.delete_force(self.ldb, self.ou_dn,
|
||||||
|
+ controls=['tree_delete:1'])
|
||||||
|
+
|
||||||
|
+ self.ldb.add({
|
||||||
|
+ "dn": self.ou_dn,
|
||||||
|
+ "objectclass": "organizationalUnit",
|
||||||
|
+ "ou": self.OU_NAME_ASQ})
|
||||||
|
+
|
||||||
|
+ self.members = []
|
||||||
|
+ self.members2 = []
|
||||||
|
+
|
||||||
|
+ for x in range(20):
|
||||||
|
+ name = self.NAME_ASQ + "_" + str(x)
|
||||||
|
+ dn = ldb.Dn(self.ldb,
|
||||||
|
+ "cn=" + name + "," + str(self.ou_dn))
|
||||||
|
+ self.members.append(dn)
|
||||||
|
+ self.ldb.add({
|
||||||
|
+ "dn": dn,
|
||||||
|
+ "objectclass": "group"})
|
||||||
|
+
|
||||||
|
+ for x in range(20):
|
||||||
|
+ name = self.NAME_ASQ + "_" + str(x + 20)
|
||||||
|
+ dn = ldb.Dn(self.ldb,
|
||||||
|
+ "cn=" + name + "," + str(self.ou_dn))
|
||||||
|
+ self.members2.append(dn)
|
||||||
|
+ self.ldb.add({
|
||||||
|
+ "dn": dn,
|
||||||
|
+ "objectclass": "group",
|
||||||
|
+ "member": [str(x) for x in self.members]})
|
||||||
|
+
|
||||||
|
+ name = self.NAME_ASQ + "_" + str(x + 40)
|
||||||
|
+ self.top_dn = ldb.Dn(self.ldb,
|
||||||
|
+ "cn=" + name + "," + str(self.ou_dn))
|
||||||
|
+ self.ldb.add({
|
||||||
|
+ "dn": self.top_dn,
|
||||||
|
+ "objectclass": "group",
|
||||||
|
+ "member": [str(x) for x in self.members2]})
|
||||||
|
+
|
||||||
|
+ def tearDown(self):
|
||||||
|
+ samba.tests.delete_force(self.ldb, self.ou_dn,
|
||||||
|
+ controls=['tree_delete:1'])
|
||||||
|
+
|
||||||
|
+ def test_asq(self):
|
||||||
|
+ """Testing ASQ behaviour.
|
||||||
|
+
|
||||||
|
+ ASQ is very strange, it turns a BASE search into a search for
|
||||||
|
+ all the objects pointed to by the specified attribute,
|
||||||
|
+ returning multiple entries!
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ msgs = self.ldb.search(base=self.top_dn,
|
||||||
|
+ scope=ldb.SCOPE_BASE,
|
||||||
|
+ attrs=["objectGUID", "cn", "member"],
|
||||||
|
+ controls=["asq:1:member"])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(len(msgs), 20)
|
||||||
|
+
|
||||||
|
+ for msg in msgs:
|
||||||
|
+ self.assertNotEqual(msg.dn, self.top_dn)
|
||||||
|
+ self.assertIn(msg.dn, self.members2)
|
||||||
|
+ for group in msg["member"]:
|
||||||
|
+ self.assertIn(ldb.Dn(self.ldb, str(group)),
|
||||||
|
+ self.members)
|
||||||
|
+
|
||||||
|
+ def test_asq_paged(self):
|
||||||
|
+ """Testing ASQ behaviour with paged_results set.
|
||||||
|
+
|
||||||
|
+ ASQ is very strange, it turns a BASE search into a search for
|
||||||
|
+ all the objects pointed to by the specified attribute,
|
||||||
|
+ returning multiple entries!
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ msgs = self.ldb.search(base=self.top_dn,
|
||||||
|
+ scope=ldb.SCOPE_BASE,
|
||||||
|
+ attrs=["objectGUID", "cn", "member"],
|
||||||
|
+ controls=["asq:1:member",
|
||||||
|
+ "paged_results:1:1024"])
|
||||||
|
+
|
||||||
|
+ self.assertEqual(len(msgs), 20)
|
||||||
|
+
|
||||||
|
+ for msg in msgs:
|
||||||
|
+ self.assertNotEqual(msg.dn, self.top_dn)
|
||||||
|
+ self.assertIn(msg.dn, self.members2)
|
||||||
|
+ for group in msg["member"]:
|
||||||
|
+ self.assertIn(ldb.Dn(self.ldb, str(group)),
|
||||||
|
+ self.members)
|
||||||
|
+
|
||||||
|
+if "://" not in url:
|
||||||
|
+ if os.path.isfile(url):
|
||||||
|
+ url = "tdb://%s" % url
|
||||||
|
+ else:
|
||||||
|
+ url = "ldap://%s" % url
|
||||||
|
+
|
||||||
|
+TestProgram(module=__name__, opts=subunitopts)
|
||||||
|
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
|
||||||
|
index ae2b10ae659..52db18a872b 100755
|
||||||
|
--- a/source4/selftest/tests.py
|
||||||
|
+++ b/source4/selftest/tests.py
|
||||||
|
@@ -885,6 +885,7 @@ plantestsuite_loadlist("samba4.tokengroups.krb5.python(ad_dc_default)", "ad_dc_d
|
||||||
|
plantestsuite_loadlist("samba4.tokengroups.ntlm.python(ad_dc_default)", "ad_dc_default:local", [python, os.path.join(DSDB_PYTEST_DIR, "token_group.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '-k', 'no', '$LOADLIST', '$LISTOPT'])
|
||||||
|
plantestsuite("samba4.sam.python(fl2008r2dc)", "fl2008r2dc", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
|
||||||
|
plantestsuite("samba4.sam.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "sam.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
|
||||||
|
+plantestsuite("samba4.asq.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "asq.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
|
||||||
|
plantestsuite("samba4.user_account_control.python(ad_dc_default)", "ad_dc_default", [python, os.path.join(DSDB_PYTEST_DIR, "user_account_control.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN'])
|
||||||
|
|
||||||
|
for env in ['ad_dc_default:local', 'schema_dc:local']:
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
|
|
||||||
82
CVE-2020-10700-3.patch
Normal file
82
CVE-2020-10700-3.patch
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
From 34f9e6e969913629f9241522020c5895dc9636dc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
Date: Wed, 11 Mar 2020 16:43:31 +1300
|
||||||
|
Subject: [PATCH 3/4] CVE-2020-10700: dsdb: Do not permit the ASQ control for
|
||||||
|
the GUID search in paged_results
|
||||||
|
|
||||||
|
ASQ is a very strange control and a BASE search can return multiple results
|
||||||
|
that are NOT the requested DN, but the DNs pointed to by it!
|
||||||
|
|
||||||
|
Thanks to Andrei Popa <andrei.popa@next-gen.ro> for finding,
|
||||||
|
reporting and working with us to diagnose this issue!
|
||||||
|
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14331
|
||||||
|
|
||||||
|
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
---
|
||||||
|
selftest/knownfail.d/asq | 1 -
|
||||||
|
source4/dsdb/samdb/ldb_modules/paged_results.c | 18 +++++++++++++-----
|
||||||
|
2 files changed, 13 insertions(+), 6 deletions(-)
|
||||||
|
delete mode 100644 selftest/knownfail.d/asq
|
||||||
|
|
||||||
|
diff --git a/selftest/knownfail.d/asq b/selftest/knownfail.d/asq
|
||||||
|
deleted file mode 100644
|
||||||
|
index eb0e3e0aba1..00000000000
|
||||||
|
--- a/selftest/knownfail.d/asq
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1 +0,0 @@
|
||||||
|
-samba4.asq.python\(ad_dc_default\).__main__.ASQLDAPTest.test_asq_paged
|
||||||
|
\ No newline at end of file
|
||||||
|
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
||||||
|
index 940d2254fb0..dc211dd18ce 100644
|
||||||
|
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
|
||||||
|
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
||||||
|
@@ -483,8 +483,14 @@ paged_results_copy_down_controls(TALLOC_CTX *mem_ctx,
|
||||||
|
if (control->oid == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
- if (strncmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID,
|
||||||
|
- sizeof(LDB_CONTROL_PAGED_RESULTS_OID)) == 0) {
|
||||||
|
+ if (strcmp(control->oid, LDB_CONTROL_PAGED_RESULTS_OID) == 0) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ /*
|
||||||
|
+ * ASQ changes everything, do not copy it down for the
|
||||||
|
+ * per-GUID search
|
||||||
|
+ */
|
||||||
|
+ if (strcmp(control->oid, LDB_CONTROL_ASQ_OID) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
new_controls[j] = talloc_steal(new_controls, control);
|
||||||
|
@@ -534,21 +540,23 @@ static bool paged_controls_same(struct ldb_request *req,
|
||||||
|
|
||||||
|
num_non_null_req_controls = 0;
|
||||||
|
for (i=0; req->controls[i] != NULL; i++) {
|
||||||
|
- if (req->controls[i]->oid != NULL) {
|
||||||
|
+ if (req->controls[i]->oid != NULL &&
|
||||||
|
+ strcmp(req->controls[i]->oid,
|
||||||
|
+ LDB_CONTROL_ASQ_OID) != 0) {
|
||||||
|
num_non_null_req_controls++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point we have the number of non-null entries for both
|
||||||
|
* control lists and we know that:
|
||||||
|
- * 1. down_controls does not contain the paged control
|
||||||
|
+ * 1. down_controls does not contain the paged control or ASQ
|
||||||
|
* (because paged_results_copy_down_controls excludes it)
|
||||||
|
* 2. req->controls does contain the paged control
|
||||||
|
* (because this function is only called if this is true)
|
||||||
|
* 3. down_controls is a subset of non-null controls in req->controls
|
||||||
|
* (checked above)
|
||||||
|
* So to confirm that the two lists are identical except for the paged
|
||||||
|
- * control, all we need to check is: */
|
||||||
|
+ * control and possibly ASQ, all we need to check is: */
|
||||||
|
if (num_non_null_req_controls == num_down_controls + 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
|
|
||||||
547
CVE-2020-10704-1.patch
Normal file
547
CVE-2020-10704-1.patch
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
From b01952c6fb15b92fff3ad1bf8f1cf579875e5483 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Fri, 3 Apr 2020 12:18:03 +1300
|
||||||
|
Subject: [PATCH 1/8] CVE-2020-10704: lib util asn1: Add ASN.1 max tree depth
|
||||||
|
|
||||||
|
Add maximum parse tree depth to the call to asn1_init, which will be
|
||||||
|
used to limit the depth of the ASN.1 parse tree.
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
auth/gensec/gensec_util.c | 2 +-
|
||||||
|
lib/util/asn1.c | 17 +++++++++-
|
||||||
|
lib/util/asn1.h | 9 +++++-
|
||||||
|
lib/util/tests/asn1_tests.c | 2 +-
|
||||||
|
libcli/auth/spnego_parse.c | 6 ++--
|
||||||
|
libcli/cldap/cldap.c | 2 +-
|
||||||
|
libcli/ldap/ldap_message.c | 2 +-
|
||||||
|
source3/lib/tldap.c | 4 +--
|
||||||
|
source3/lib/tldap_util.c | 4 +--
|
||||||
|
source3/libsmb/clispnego.c | 4 +--
|
||||||
|
source3/torture/torture.c | 2 +-
|
||||||
|
source4/auth/gensec/gensec_krb5.c | 4 +--
|
||||||
|
source4/ldap_server/ldap_server.c | 2 +-
|
||||||
|
source4/libcli/ldap/ldap_client.c | 2 +-
|
||||||
|
source4/libcli/ldap/ldap_controls.c | 48 ++++++++++++++---------------
|
||||||
|
15 files changed, 66 insertions(+), 44 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/auth/gensec/gensec_util.c b/auth/gensec/gensec_util.c
|
||||||
|
index 20c9c2a1fbb..e185acc0c20 100644
|
||||||
|
--- a/auth/gensec/gensec_util.c
|
||||||
|
+++ b/auth/gensec/gensec_util.c
|
||||||
|
@@ -76,7 +76,7 @@ NTSTATUS gensec_generate_session_info_pac(TALLOC_CTX *mem_ctx,
|
||||||
|
static bool gensec_gssapi_check_oid(const DATA_BLOB *blob, const char *oid)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
- struct asn1_data *data = asn1_init(NULL);
|
||||||
|
+ struct asn1_data *data = asn1_init(NULL, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
|
||||||
|
index 51da5424956..ec6e674ce20 100644
|
||||||
|
--- a/lib/util/asn1.c
|
||||||
|
+++ b/lib/util/asn1.c
|
||||||
|
@@ -36,15 +36,19 @@ struct asn1_data {
|
||||||
|
off_t ofs;
|
||||||
|
struct nesting *nesting;
|
||||||
|
bool has_error;
|
||||||
|
+ unsigned depth;
|
||||||
|
+ unsigned max_depth;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* allocate an asn1 structure */
|
||||||
|
-struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx)
|
||||||
|
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth)
|
||||||
|
{
|
||||||
|
struct asn1_data *ret = talloc_zero(mem_ctx, struct asn1_data);
|
||||||
|
if (ret == NULL) {
|
||||||
|
DEBUG(0,("asn1_init failed! out of memory\n"));
|
||||||
|
+ return ret;
|
||||||
|
}
|
||||||
|
+ ret->max_depth = max_depth;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -480,6 +484,11 @@ bool asn1_check_BOOLEAN(struct asn1_data *data, bool v)
|
||||||
|
/* load a struct asn1_data structure with a lump of data, ready to be parsed */
|
||||||
|
bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
|
||||||
|
{
|
||||||
|
+ /*
|
||||||
|
+ * Save the maximum depth
|
||||||
|
+ */
|
||||||
|
+ unsigned max_depth = data->max_depth;
|
||||||
|
+
|
||||||
|
ZERO_STRUCTP(data);
|
||||||
|
data->data = (uint8_t *)talloc_memdup(data, blob.data, blob.length);
|
||||||
|
if (!data->data) {
|
||||||
|
@@ -487,6 +496,7 @@ bool asn1_load(struct asn1_data *data, DATA_BLOB blob)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
data->length = blob.length;
|
||||||
|
+ data->max_depth = max_depth;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1103,9 +1113,14 @@ bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
|
||||||
|
*/
|
||||||
|
void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
+ /*
|
||||||
|
+ * Save max_depth
|
||||||
|
+ */
|
||||||
|
+ unsigned max_depth = data->max_depth;
|
||||||
|
ZERO_STRUCTP(data);
|
||||||
|
data->data = buf;
|
||||||
|
data->length = len;
|
||||||
|
+ data->max_depth = max_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
|
||||||
|
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
|
||||||
|
index ddd69863574..fc365724e93 100644
|
||||||
|
--- a/lib/util/asn1.h
|
||||||
|
+++ b/lib/util/asn1.h
|
||||||
|
@@ -45,7 +45,14 @@ typedef struct asn1_data ASN1_DATA;
|
||||||
|
|
||||||
|
#define ASN1_MAX_OIDS 20
|
||||||
|
|
||||||
|
-struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx);
|
||||||
|
+/*
|
||||||
|
+ * The maximum permitted depth for an ASN.1 parse tree, the limit is chosen
|
||||||
|
+ * to align with the value for windows. Note that this value will trigger
|
||||||
|
+ * ASAN stack overflow errors.
|
||||||
|
+ */
|
||||||
|
+#define ASN1_MAX_TREE_DEPTH 512
|
||||||
|
+
|
||||||
|
+struct asn1_data *asn1_init(TALLOC_CTX *mem_ctx, unsigned max_depth);
|
||||||
|
void asn1_free(struct asn1_data *data);
|
||||||
|
bool asn1_has_error(const struct asn1_data *data);
|
||||||
|
void asn1_set_error(struct asn1_data *data);
|
||||||
|
diff --git a/lib/util/tests/asn1_tests.c b/lib/util/tests/asn1_tests.c
|
||||||
|
index e4b386ad785..ab5262c4ffb 100644
|
||||||
|
--- a/lib/util/tests/asn1_tests.c
|
||||||
|
+++ b/lib/util/tests/asn1_tests.c
|
||||||
|
@@ -330,7 +330,7 @@ static bool test_asn1_Integer(struct torture_context *tctx)
|
||||||
|
DATA_BLOB blob;
|
||||||
|
int val;
|
||||||
|
|
||||||
|
- data = asn1_init(mem_ctx);
|
||||||
|
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (!data) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
diff --git a/libcli/auth/spnego_parse.c b/libcli/auth/spnego_parse.c
|
||||||
|
index f538b44552c..f7f19b10778 100644
|
||||||
|
--- a/libcli/auth/spnego_parse.c
|
||||||
|
+++ b/libcli/auth/spnego_parse.c
|
||||||
|
@@ -296,7 +296,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- asn1 = asn1_init(mem_ctx);
|
||||||
|
+ asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
@@ -339,7 +339,7 @@ ssize_t spnego_read_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, struct spnego_data
|
||||||
|
|
||||||
|
ssize_t spnego_write_data(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, struct spnego_data *spnego)
|
||||||
|
{
|
||||||
|
- struct asn1_data *asn1 = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
ssize_t ret = -1;
|
||||||
|
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
@@ -411,7 +411,7 @@ bool spnego_write_mech_types(TALLOC_CTX *mem_ctx,
|
||||||
|
DATA_BLOB *blob)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
- struct asn1_data *asn1 = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *asn1 = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
return false;
|
||||||
|
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
|
||||||
|
index daba37a21d7..8fa9ce0b273 100644
|
||||||
|
--- a/libcli/cldap/cldap.c
|
||||||
|
+++ b/libcli/cldap/cldap.c
|
||||||
|
@@ -229,7 +229,7 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
- asn1 = asn1_init(in);
|
||||||
|
+ asn1 = asn1_init(in, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (!asn1) {
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
|
||||||
|
index f21598374a1..ba82bddeab1 100644
|
||||||
|
--- a/libcli/ldap/ldap_message.c
|
||||||
|
+++ b/libcli/ldap/ldap_message.c
|
||||||
|
@@ -390,7 +390,7 @@ _PUBLIC_ bool ldap_encode(struct ldap_message *msg,
|
||||||
|
const struct ldap_control_handler *control_handlers,
|
||||||
|
DATA_BLOB *result, TALLOC_CTX *mem_ctx)
|
||||||
|
{
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c
|
||||||
|
index d6c6e8859a6..bf5fc05d785 100644
|
||||||
|
--- a/source3/lib/tldap.c
|
||||||
|
+++ b/source3/lib/tldap.c
|
||||||
|
@@ -632,7 +632,7 @@ static void tldap_msg_received(struct tevent_req *subreq)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
- data = asn1_init(talloc_tos());
|
||||||
|
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (data == NULL) {
|
||||||
|
status = TLDAP_NO_MEMORY;
|
||||||
|
goto fail;
|
||||||
|
@@ -763,7 +763,7 @@ static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
|
||||||
|
if (req == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
- state->out = asn1_init(state);
|
||||||
|
+ state->out = asn1_init(state, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (state->out == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c
|
||||||
|
index 1b86962a32e..168932a8a96 100644
|
||||||
|
--- a/source3/lib/tldap_util.c
|
||||||
|
+++ b/source3/lib/tldap_util.c
|
||||||
|
@@ -644,7 +644,7 @@ static struct tevent_req *tldap_ship_paged_search(
|
||||||
|
struct tldap_control *pgctrl;
|
||||||
|
struct asn1_data *asn1 = NULL;
|
||||||
|
|
||||||
|
- asn1 = asn1_init(state);
|
||||||
|
+ asn1 = asn1_init(state, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
@@ -783,7 +783,7 @@ static void tldap_search_paged_done(struct tevent_req *subreq)
|
||||||
|
|
||||||
|
TALLOC_FREE(state->cookie.data);
|
||||||
|
|
||||||
|
- asn1 = asn1_init(talloc_tos());
|
||||||
|
+ asn1 = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (tevent_req_nomem(asn1, req)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c
|
||||||
|
index 4a0fbcd73af..1608f6a9960 100644
|
||||||
|
--- a/source3/libsmb/clispnego.c
|
||||||
|
+++ b/source3/libsmb/clispnego.c
|
||||||
|
@@ -50,7 +50,7 @@ bool spnego_parse_negTokenInit(TALLOC_CTX *ctx,
|
||||||
|
*secblob = data_blob_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
- data = asn1_init(talloc_tos());
|
||||||
|
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (data == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@@ -171,7 +171,7 @@ DATA_BLOB spnego_gen_krb5_wrap(TALLOC_CTX *ctx, const DATA_BLOB ticket, const ui
|
||||||
|
ASN1_DATA *data;
|
||||||
|
DATA_BLOB ret = data_blob_null;
|
||||||
|
|
||||||
|
- data = asn1_init(talloc_tos());
|
||||||
|
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (data == NULL) {
|
||||||
|
return data_blob_null;
|
||||||
|
}
|
||||||
|
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
|
||||||
|
index a795e61125f..c4b0a7bc4f9 100644
|
||||||
|
--- a/source3/torture/torture.c
|
||||||
|
+++ b/source3/torture/torture.c
|
||||||
|
@@ -11370,7 +11370,7 @@ tldap_build_extended_control(enum tldap_extended_val val)
|
||||||
|
ZERO_STRUCT(empty_control);
|
||||||
|
|
||||||
|
if (val != EXTENDED_NONE) {
|
||||||
|
- data = asn1_init(talloc_tos());
|
||||||
|
+ data = asn1_init(talloc_tos(), ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
return NULL;
|
||||||
|
diff --git a/source4/auth/gensec/gensec_krb5.c b/source4/auth/gensec/gensec_krb5.c
|
||||||
|
index 0323da87d29..b735063656a 100644
|
||||||
|
--- a/source4/auth/gensec/gensec_krb5.c
|
||||||
|
+++ b/source4/auth/gensec/gensec_krb5.c
|
||||||
|
@@ -444,7 +444,7 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
|
||||||
|
struct asn1_data *data;
|
||||||
|
DATA_BLOB ret = data_blob_null;
|
||||||
|
|
||||||
|
- data = asn1_init(mem_ctx);
|
||||||
|
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (!data || !ticket->data) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -478,7 +478,7 @@ static DATA_BLOB gensec_gssapi_gen_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLO
|
||||||
|
static bool gensec_gssapi_parse_krb5_wrap(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, DATA_BLOB *ticket, uint8_t tok_id[2])
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
int data_remaining;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
|
||||||
|
index 709b7bcacfa..6d329329909 100644
|
||||||
|
--- a/source4/ldap_server/ldap_server.c
|
||||||
|
+++ b/source4/ldap_server/ldap_server.c
|
||||||
|
@@ -560,7 +560,7 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- asn1 = asn1_init(call);
|
||||||
|
+ asn1 = asn1_init(call, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
ldapsrv_terminate_connection(conn, "no memory");
|
||||||
|
return;
|
||||||
|
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
|
||||||
|
index da84adc7769..2d75af6af6e 100644
|
||||||
|
--- a/source4/libcli/ldap/ldap_client.c
|
||||||
|
+++ b/source4/libcli/ldap/ldap_client.c
|
||||||
|
@@ -284,7 +284,7 @@ static void ldap_connection_recv_done(struct tevent_req *subreq)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- asn1 = asn1_init(conn);
|
||||||
|
+ asn1 = asn1_init(conn, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
TALLOC_FREE(msg);
|
||||||
|
ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
|
||||||
|
diff --git a/source4/libcli/ldap/ldap_controls.c b/source4/libcli/ldap/ldap_controls.c
|
||||||
|
index 716ca148308..df012a158e0 100644
|
||||||
|
--- a/source4/libcli/ldap/ldap_controls.c
|
||||||
|
+++ b/source4/libcli/ldap/ldap_controls.c
|
||||||
|
@@ -32,7 +32,7 @@ static bool decode_server_sort_response(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB attr;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_sort_resp_control *lsrc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -79,7 +79,7 @@ static bool decode_server_sort_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB attr;
|
||||||
|
DATA_BLOB rule;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_server_sort_control **lssc;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
@@ -166,7 +166,7 @@ static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- data = asn1_init(mem_ctx);
|
||||||
|
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
if (!asn1_load(data, in)) {
|
||||||
|
@@ -198,7 +198,7 @@ static bool decode_extended_dn_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
static bool decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_sd_flags_control *lsdfc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -232,7 +232,7 @@ static bool decode_sd_flags_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
static bool decode_search_options_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_search_options_control *lsoc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -267,7 +267,7 @@ static bool decode_paged_results_request(void *mem_ctx, DATA_BLOB in, void *_out
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB cookie;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_paged_control *lprc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -316,7 +316,7 @@ static bool decode_dirsync_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB cookie;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_dirsync_control *ldc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -372,7 +372,7 @@ static bool decode_asq_control(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB source_attribute;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_asq_control *lac;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -433,7 +433,7 @@ static bool decode_verify_name_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB name;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_verify_name_control *lvnc;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
@@ -485,7 +485,7 @@ static bool decode_verify_name_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
static bool encode_verify_name_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_verify_name_control *lvnc = talloc_get_type(in, struct ldb_verify_name_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
DATA_BLOB gc_utf16;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -528,7 +528,7 @@ static bool decode_vlv_request(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB assertion_value, context_id;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_vlv_req_control *lvrc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -626,7 +626,7 @@ static bool decode_vlv_response(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
DATA_BLOB context_id;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct ldb_vlv_resp_control *lvrc;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -682,7 +682,7 @@ static bool decode_vlv_response(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_sort_resp_control *lsrc = talloc_get_type(in, struct ldb_sort_resp_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -716,7 +716,7 @@ static bool encode_server_sort_response(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_server_sort_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_server_sort_control **lssc = talloc_get_type(in, struct ldb_server_sort_control *);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
int num;
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
@@ -782,7 +782,7 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- data = asn1_init(mem_ctx);
|
||||||
|
+ data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -810,7 +810,7 @@ static bool encode_extended_dn_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_sd_flags_control *lsdfc = talloc_get_type(in, struct ldb_sd_flags_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -838,7 +838,7 @@ static bool encode_sd_flags_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_search_options_control *lsoc = talloc_get_type(in, struct ldb_search_options_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -866,7 +866,7 @@ static bool encode_search_options_request(void *mem_ctx, void *in, DATA_BLOB *ou
|
||||||
|
static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_paged_control *lprc = talloc_get_type(in, struct ldb_paged_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -901,7 +901,7 @@ static bool encode_paged_results_request(void *mem_ctx, void *in, DATA_BLOB *out
|
||||||
|
static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_asq_control *lac = talloc_get_type(in, struct ldb_asq_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -936,7 +936,7 @@ static bool encode_asq_control(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_dirsync_control *ldc = talloc_get_type(in, struct ldb_dirsync_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -972,7 +972,7 @@ static bool encode_dirsync_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_vlv_req_control *lvrc = talloc_get_type(in, struct ldb_vlv_req_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -1040,7 +1040,7 @@ static bool encode_vlv_request(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool encode_vlv_response(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct ldb_vlv_resp_control *lvrc = talloc_get_type(in, struct ldb_vlv_resp_control);
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -1083,7 +1083,7 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
{
|
||||||
|
struct dsdb_openldap_dereference_control *control = talloc_get_type(in, struct dsdb_openldap_dereference_control);
|
||||||
|
int i,j;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
|
||||||
|
if (!data) return false;
|
||||||
|
|
||||||
|
@@ -1132,7 +1132,7 @@ static bool encode_openldap_dereference(void *mem_ctx, void *in, DATA_BLOB *out)
|
||||||
|
static bool decode_openldap_dereference(void *mem_ctx, DATA_BLOB in, void *_out)
|
||||||
|
{
|
||||||
|
void **out = (void **)_out;
|
||||||
|
- struct asn1_data *data = asn1_init(mem_ctx);
|
||||||
|
+ struct asn1_data *data = asn1_init(mem_ctx, ASN1_MAX_TREE_DEPTH);
|
||||||
|
struct dsdb_openldap_dereference_result_control *control;
|
||||||
|
struct dsdb_openldap_dereference_result **r = NULL;
|
||||||
|
int i = 0;
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
|
|
||||||
52
CVE-2020-10704-3.patch
Normal file
52
CVE-2020-10704-3.patch
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
Backport of:
|
||||||
|
|
||||||
|
From d3be674c3ffa3541e2ba757e2c6dfb32508db440 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Wed, 8 Apr 2020 15:30:52 +1200
|
||||||
|
Subject: [PATCH 3/8] CVE-2020-10704: lib util asn1: Check parse tree depth
|
||||||
|
|
||||||
|
Check the current depth of the parse tree and reject the input if the
|
||||||
|
depth exceeds that passed to asn1_init
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
lib/util/asn1.c | 13 +++++++++++++
|
||||||
|
selftest/knownfail.d/ldap_message | 2 --
|
||||||
|
2 files changed, 13 insertions(+), 2 deletions(-)
|
||||||
|
delete mode 100644 selftest/knownfail.d/ldap_message
|
||||||
|
|
||||||
|
--- a/lib/util/asn1.c
|
||||||
|
+++ b/lib/util/asn1.c
|
||||||
|
@@ -647,6 +647,16 @@ bool asn1_start_tag(struct asn1_data *da
|
||||||
|
uint8_t b;
|
||||||
|
struct nesting *nesting;
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * Check the depth of the parse tree and prevent it from growing
|
||||||
|
+ * too large.
|
||||||
|
+ */
|
||||||
|
+ data->depth++;
|
||||||
|
+ if (data->depth > data->max_depth) {
|
||||||
|
+ data->has_error = true;
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!asn1_read_uint8(data, &b))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
@@ -703,6 +713,9 @@ bool asn1_end_tag(struct asn1_data *data
|
||||||
|
{
|
||||||
|
struct nesting *nesting;
|
||||||
|
|
||||||
|
+ if (data->depth > 0) {
|
||||||
|
+ data->depth--;
|
||||||
|
+ }
|
||||||
|
/* make sure we read it all */
|
||||||
|
if (asn1_tag_remaining(data) != 0) {
|
||||||
|
data->has_error = true;
|
||||||
96
CVE-2020-10704-5.patch
Normal file
96
CVE-2020-10704-5.patch
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
From 9944df6ef1e421331ea1ca773f7e5652262d5d1b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Tue, 7 Apr 2020 09:09:01 +1200
|
||||||
|
Subject: [PATCH 5/8] CVE-2020-10704: smb.conf: Add max ldap request sizes
|
||||||
|
|
||||||
|
Add two new smb.conf parameters to control the maximum permitted ldap
|
||||||
|
request size.
|
||||||
|
|
||||||
|
Adds:
|
||||||
|
ldap max anonymous request size default 250Kb
|
||||||
|
ldap max authenticated request size default 16Mb
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
.../smbdotconf/ldap/ldapmaxanonrequest.xml | 18 ++++++++++++++++++
|
||||||
|
.../smbdotconf/ldap/ldapmaxauthrequest.xml | 18 ++++++++++++++++++
|
||||||
|
lib/param/loadparm.c | 5 +++++
|
||||||
|
source3/param/loadparm.c | 3 +++
|
||||||
|
4 files changed, 44 insertions(+)
|
||||||
|
create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml
|
||||||
|
create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+<samba:parameter name="ldap max anonymous request size"
|
||||||
|
+ context="G"
|
||||||
|
+ type="integer"
|
||||||
|
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
||||||
|
+<description>
|
||||||
|
+ <para>
|
||||||
|
+ This parameter specifies the maximum permitted size (in bytes)
|
||||||
|
+ for an LDAP request received on an anonymous connection.
|
||||||
|
+ </para>
|
||||||
|
+
|
||||||
|
+ <para>
|
||||||
|
+ If the request size exceeds this limit the request will be
|
||||||
|
+ rejected.
|
||||||
|
+ </para>
|
||||||
|
+</description>
|
||||||
|
+<value type="default">256000</value>
|
||||||
|
+<value type="example">500000</value>
|
||||||
|
+</samba:parameter>
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+<samba:parameter name="ldap max authenticated request size"
|
||||||
|
+ context="G"
|
||||||
|
+ type="integer"
|
||||||
|
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
||||||
|
+<description>
|
||||||
|
+ <para>
|
||||||
|
+ This parameter specifies the maximum permitted size (in bytes)
|
||||||
|
+ for an LDAP request received on an authenticated connection.
|
||||||
|
+ </para>
|
||||||
|
+
|
||||||
|
+ <para>
|
||||||
|
+ If the request size exceeds this limit the request will be
|
||||||
|
+ rejected.
|
||||||
|
+ </para>
|
||||||
|
+</description>
|
||||||
|
+<value type="default">16777216</value>
|
||||||
|
+<value type="example">4194304</value>
|
||||||
|
+</samba:parameter>
|
||||||
|
--- a/lib/param/loadparm.c
|
||||||
|
+++ b/lib/param/loadparm.c
|
||||||
|
@@ -3027,6 +3027,11 @@ struct loadparm_context *loadparm_init(T
|
||||||
|
|
||||||
|
lpcfg_do_global_parameter(lp_ctx, "debug encryption", "no");
|
||||||
|
|
||||||
|
+ lpcfg_do_global_parameter(
|
||||||
|
+ lp_ctx, "ldap max anonymous request size", "256000");
|
||||||
|
+ lpcfg_do_global_parameter(
|
||||||
|
+ lp_ctx, "ldap max authenticated request size", "16777216");
|
||||||
|
+
|
||||||
|
for (i = 0; parm_table[i].label; i++) {
|
||||||
|
if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
|
||||||
|
lp_ctx->flags[i] |= FLAG_DEFAULT;
|
||||||
|
--- a/source3/param/loadparm.c
|
||||||
|
+++ b/source3/param/loadparm.c
|
||||||
|
@@ -956,6 +956,9 @@ static void init_globals(struct loadparm
|
||||||
|
Globals.prefork_backoff_increment = 10;
|
||||||
|
Globals.prefork_maximum_backoff = 120;
|
||||||
|
|
||||||
|
+ Globals.ldap_max_anonymous_request_size = 256000;
|
||||||
|
+ Globals.ldap_max_authenticated_request_size = 16777216;
|
||||||
|
+
|
||||||
|
/* Now put back the settings that were set with lp_set_cmdline() */
|
||||||
|
apply_lp_set_cmdline();
|
||||||
|
}
|
||||||
163
CVE-2020-10704-6.patch
Normal file
163
CVE-2020-10704-6.patch
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
Backport of:
|
||||||
|
|
||||||
|
From 85619363d3280346b2253fe44bf67d4881a53ebd Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Wed, 8 Apr 2020 15:32:22 +1200
|
||||||
|
Subject: [PATCH 6/8] CVE-2020-10704: S4 ldap server: Limit request sizes
|
||||||
|
|
||||||
|
Check the size of authenticated and anonymous ldap requests and reject
|
||||||
|
them if they exceed the limits in smb.conf
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
selftest/knownfail.d/ldap_raw | 1 -
|
||||||
|
source4/ldap_server/ldap_server.c | 96 ++++++++++++++++++++++++++++++-
|
||||||
|
2 files changed, 95 insertions(+), 2 deletions(-)
|
||||||
|
delete mode 100644 selftest/knownfail.d/ldap_raw
|
||||||
|
|
||||||
|
--- a/source4/ldap_server/ldap_server.c
|
||||||
|
+++ b/source4/ldap_server/ldap_server.c
|
||||||
|
@@ -441,6 +441,10 @@ static void ldapsrv_accept_tls_done(stru
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ldapsrv_call_read_done(struct tevent_req *subreq);
|
||||||
|
+static NTSTATUS ldapsrv_packet_check(
|
||||||
|
+ void *private_data,
|
||||||
|
+ DATA_BLOB blob,
|
||||||
|
+ size_t *packet_size);
|
||||||
|
|
||||||
|
static bool ldapsrv_call_read_next(struct ldapsrv_connection *conn)
|
||||||
|
{
|
||||||
|
@@ -494,7 +498,7 @@ static bool ldapsrv_call_read_next(struc
|
||||||
|
conn->connection->event.ctx,
|
||||||
|
conn->sockets.active,
|
||||||
|
7, /* initial_read_size */
|
||||||
|
- ldap_full_packet,
|
||||||
|
+ ldapsrv_packet_check,
|
||||||
|
conn);
|
||||||
|
if (subreq == NULL) {
|
||||||
|
ldapsrv_terminate_connection(conn, "ldapsrv_call_read_next: "
|
||||||
|
@@ -520,6 +524,9 @@ static bool ldapsrv_call_read_next(struc
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ldapsrv_call_process_done(struct tevent_req *subreq);
|
||||||
|
+static int ldapsrv_check_packet_size(
|
||||||
|
+ struct ldapsrv_connection *conn,
|
||||||
|
+ size_t size);
|
||||||
|
|
||||||
|
static void ldapsrv_call_read_done(struct tevent_req *subreq)
|
||||||
|
{
|
||||||
|
@@ -530,6 +537,7 @@ static void ldapsrv_call_read_done(struc
|
||||||
|
struct ldapsrv_call *call;
|
||||||
|
struct asn1_data *asn1;
|
||||||
|
DATA_BLOB blob;
|
||||||
|
+ int ret = LDAP_SUCCESS;
|
||||||
|
|
||||||
|
conn->sockets.read_req = NULL;
|
||||||
|
|
||||||
|
@@ -560,6 +568,14 @@ static void ldapsrv_call_read_done(struc
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ ret = ldapsrv_check_packet_size(conn, blob.length);
|
||||||
|
+ if (ret != LDAP_SUCCESS) {
|
||||||
|
+ ldapsrv_terminate_connection(
|
||||||
|
+ conn,
|
||||||
|
+ "Request packet too large");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
asn1 = asn1_init(call, ASN1_MAX_TREE_DEPTH);
|
||||||
|
if (asn1 == NULL) {
|
||||||
|
ldapsrv_terminate_connection(conn, "no memory");
|
||||||
|
@@ -1362,6 +1378,84 @@ static void ldapsrv_post_fork(struct tas
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Check the size of an ldap request packet.
|
||||||
|
+ *
|
||||||
|
+ * For authenticated connections the maximum packet size is controlled by
|
||||||
|
+ * the smb.conf parameter "ldap max authenticated request size"
|
||||||
|
+ *
|
||||||
|
+ * For anonymous connections the maximum packet size is controlled by
|
||||||
|
+ * the smb.conf parameter "ldap max anonymous request size"
|
||||||
|
+ */
|
||||||
|
+static int ldapsrv_check_packet_size(
|
||||||
|
+ struct ldapsrv_connection *conn,
|
||||||
|
+ size_t size)
|
||||||
|
+{
|
||||||
|
+ bool is_anonymous = false;
|
||||||
|
+ size_t max_size = 0;
|
||||||
|
+
|
||||||
|
+ max_size = lpcfg_ldap_max_anonymous_request_size(conn->lp_ctx);
|
||||||
|
+ if (size <= max_size) {
|
||||||
|
+ return LDAP_SUCCESS;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Request is larger than the maximum unauthenticated request size.
|
||||||
|
+ * As this code is called frequently we avoid calling
|
||||||
|
+ * security_token_is_anonymous if possible
|
||||||
|
+ */
|
||||||
|
+ if (conn->session_info != NULL &&
|
||||||
|
+ conn->session_info->security_token != NULL) {
|
||||||
|
+ is_anonymous = security_token_is_anonymous(
|
||||||
|
+ conn->session_info->security_token);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (is_anonymous) {
|
||||||
|
+ DBG_WARNING(
|
||||||
|
+ "LDAP request size (%zu) exceeds (%zu)\n",
|
||||||
|
+ size,
|
||||||
|
+ max_size);
|
||||||
|
+ return LDAP_UNWILLING_TO_PERFORM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ max_size = lpcfg_ldap_max_authenticated_request_size(conn->lp_ctx);
|
||||||
|
+ if (size > max_size) {
|
||||||
|
+ DBG_WARNING(
|
||||||
|
+ "LDAP request size (%zu) exceeds (%zu)\n",
|
||||||
|
+ size,
|
||||||
|
+ max_size);
|
||||||
|
+ return LDAP_UNWILLING_TO_PERFORM;
|
||||||
|
+ }
|
||||||
|
+ return LDAP_SUCCESS;
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Check that the blob contains enough data to be a valid packet
|
||||||
|
+ * If there is a packet header check the size to ensure that it does not
|
||||||
|
+ * exceed the maximum sizes.
|
||||||
|
+ *
|
||||||
|
+ */
|
||||||
|
+static NTSTATUS ldapsrv_packet_check(
|
||||||
|
+ void *private_data,
|
||||||
|
+ DATA_BLOB blob,
|
||||||
|
+ size_t *packet_size)
|
||||||
|
+{
|
||||||
|
+ NTSTATUS ret;
|
||||||
|
+ struct ldapsrv_connection *conn = private_data;
|
||||||
|
+ int result = LDB_SUCCESS;
|
||||||
|
+
|
||||||
|
+ ret = ldap_full_packet(private_data, blob, packet_size);
|
||||||
|
+ if (!NT_STATUS_IS_OK(ret)) {
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+ result = ldapsrv_check_packet_size(conn, *packet_size);
|
||||||
|
+ if (result != LDAP_SUCCESS) {
|
||||||
|
+ return NT_STATUS_LDAP(result);
|
||||||
|
+ }
|
||||||
|
+ return NT_STATUS_OK;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
NTSTATUS server_service_ldap_init(TALLOC_CTX *ctx)
|
||||||
|
{
|
||||||
|
static const struct service_details details = {
|
||||||
211
CVE-2020-10704-7.patch
Normal file
211
CVE-2020-10704-7.patch
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
Backport of:
|
||||||
|
|
||||||
|
From 9be121c7055fde841be15f8d570ff49801b68bff Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Wed, 8 Apr 2020 08:49:23 +1200
|
||||||
|
Subject: [PATCH 7/8] CVE-2020-10704: libcli ldap_message: Add search size
|
||||||
|
limits to ldap_decode
|
||||||
|
|
||||||
|
Add search request size limits to ldap_decode calls.
|
||||||
|
|
||||||
|
The ldap server uses the smb.conf variable
|
||||||
|
"ldap max search request size" which defaults to 250Kb.
|
||||||
|
For cldap the limit is hard coded as 4096.
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
.../smbdotconf/ldap/ldapmaxsearchrequest.xml | 18 ++++++++++++++
|
||||||
|
lib/param/loadparm.c | 2 ++
|
||||||
|
libcli/cldap/cldap.c | 18 +++++++++++---
|
||||||
|
libcli/ldap/ldap_message.c | 1 +
|
||||||
|
libcli/ldap/ldap_message.h | 5 ++++
|
||||||
|
libcli/ldap/tests/ldap_message_test.c | 24 +++++++++++++++----
|
||||||
|
source3/param/loadparm.c | 1 +
|
||||||
|
source4/ldap_server/ldap_server.c | 10 ++++++--
|
||||||
|
source4/libcli/ldap/ldap_client.c | 3 ++-
|
||||||
|
9 files changed, 72 insertions(+), 10 deletions(-)
|
||||||
|
create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml
|
||||||
|
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml
|
||||||
|
@@ -0,0 +1,18 @@
|
||||||
|
+<samba:parameter name="ldap max search request size"
|
||||||
|
+ context="G"
|
||||||
|
+ type="integer"
|
||||||
|
+ xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
|
||||||
|
+<description>
|
||||||
|
+ <para>
|
||||||
|
+ This parameter specifies the maximum permitted size (in bytes)
|
||||||
|
+ for an LDAP search request.
|
||||||
|
+ </para>
|
||||||
|
+
|
||||||
|
+ <para>
|
||||||
|
+ If the request size exceeds this limit the request will be
|
||||||
|
+ rejected.
|
||||||
|
+ </para>
|
||||||
|
+</description>
|
||||||
|
+<value type="default">256000</value>
|
||||||
|
+<value type="example">4194304</value>
|
||||||
|
+</samba:parameter>
|
||||||
|
--- a/lib/param/loadparm.c
|
||||||
|
+++ b/lib/param/loadparm.c
|
||||||
|
@@ -3031,6 +3031,8 @@ struct loadparm_context *loadparm_init(T
|
||||||
|
lp_ctx, "ldap max anonymous request size", "256000");
|
||||||
|
lpcfg_do_global_parameter(
|
||||||
|
lp_ctx, "ldap max authenticated request size", "16777216");
|
||||||
|
+ lpcfg_do_global_parameter(
|
||||||
|
+ lp_ctx, "ldap max search request size", "256000");
|
||||||
|
|
||||||
|
for (i = 0; parm_table[i].label; i++) {
|
||||||
|
if (!(lp_ctx->flags[i] & FLAG_CMDLINE)) {
|
||||||
|
--- a/libcli/cldap/cldap.c
|
||||||
|
+++ b/libcli/cldap/cldap.c
|
||||||
|
@@ -111,6 +111,11 @@ struct cldap_search_state {
|
||||||
|
struct tevent_req *req;
|
||||||
|
};
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * For CLDAP we limit the maximum search request size to 4kb
|
||||||
|
+ */
|
||||||
|
+#define MAX_SEARCH_REQUEST 4096
|
||||||
|
+
|
||||||
|
static int cldap_socket_destructor(struct cldap_socket *c)
|
||||||
|
{
|
||||||
|
while (c->searches.list) {
|
||||||
|
@@ -224,6 +229,9 @@ static bool cldap_socket_recv_dgram(stru
|
||||||
|
void *p;
|
||||||
|
struct cldap_search_state *search;
|
||||||
|
NTSTATUS status;
|
||||||
|
+ struct ldap_request_limits limits = {
|
||||||
|
+ .max_search_size = MAX_SEARCH_REQUEST
|
||||||
|
+ };
|
||||||
|
|
||||||
|
if (in->recv_errno != 0) {
|
||||||
|
goto error;
|
||||||
|
@@ -242,7 +250,7 @@ static bool cldap_socket_recv_dgram(stru
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this initial decode is used to find the message id */
|
||||||
|
- status = ldap_decode(asn1, NULL, in->ldap_msg);
|
||||||
|
+ status = ldap_decode(asn1, &limits, NULL, in->ldap_msg);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
goto nterror;
|
||||||
|
}
|
||||||
|
@@ -770,6 +778,9 @@ NTSTATUS cldap_search_recv(struct tevent
|
||||||
|
struct cldap_search_state);
|
||||||
|
struct ldap_message *ldap_msg;
|
||||||
|
NTSTATUS status;
|
||||||
|
+ struct ldap_request_limits limits = {
|
||||||
|
+ .max_search_size = MAX_SEARCH_REQUEST
|
||||||
|
+ };
|
||||||
|
|
||||||
|
if (tevent_req_is_nterror(req, &status)) {
|
||||||
|
goto failed;
|
||||||
|
@@ -780,7 +791,7 @@ NTSTATUS cldap_search_recv(struct tevent
|
||||||
|
goto nomem;
|
||||||
|
}
|
||||||
|
|
||||||
|
- status = ldap_decode(state->response.asn1, NULL, ldap_msg);
|
||||||
|
+ status = ldap_decode(state->response.asn1, &limits, NULL, ldap_msg);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
@@ -796,7 +807,8 @@ NTSTATUS cldap_search_recv(struct tevent
|
||||||
|
*io->out.response = ldap_msg->r.SearchResultEntry;
|
||||||
|
|
||||||
|
/* decode the 2nd part */
|
||||||
|
- status = ldap_decode(state->response.asn1, NULL, ldap_msg);
|
||||||
|
+ status = ldap_decode(
|
||||||
|
+ state->response.asn1, &limits, NULL, ldap_msg);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
--- a/libcli/ldap/ldap_message.c
|
||||||
|
+++ b/libcli/ldap/ldap_message.c
|
||||||
|
@@ -1162,6 +1162,7 @@ static bool ldap_decode_attribs(TALLOC_C
|
||||||
|
/* This routine returns LDAP status codes */
|
||||||
|
|
||||||
|
_PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
|
||||||
|
+ const struct ldap_request_limits *limits,
|
||||||
|
const struct ldap_control_handler *control_handlers,
|
||||||
|
struct ldap_message *msg)
|
||||||
|
{
|
||||||
|
--- a/libcli/ldap/ldap_message.h
|
||||||
|
+++ b/libcli/ldap/ldap_message.h
|
||||||
|
@@ -213,10 +213,15 @@ struct ldap_control_handler {
|
||||||
|
bool (*encode)(void *mem_ctx, void *in, DATA_BLOB *out);
|
||||||
|
};
|
||||||
|
|
||||||
|
+struct ldap_request_limits {
|
||||||
|
+ unsigned max_search_size;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct asn1_data;
|
||||||
|
|
||||||
|
struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
|
||||||
|
NTSTATUS ldap_decode(struct asn1_data *data,
|
||||||
|
+ const struct ldap_request_limits *limits,
|
||||||
|
const struct ldap_control_handler *control_handlers,
|
||||||
|
struct ldap_message *msg);
|
||||||
|
bool ldap_encode(struct ldap_message *msg,
|
||||||
|
--- a/source3/param/loadparm.c
|
||||||
|
+++ b/source3/param/loadparm.c
|
||||||
|
@@ -958,6 +958,7 @@ static void init_globals(struct loadparm
|
||||||
|
|
||||||
|
Globals.ldap_max_anonymous_request_size = 256000;
|
||||||
|
Globals.ldap_max_authenticated_request_size = 16777216;
|
||||||
|
+ Globals.ldap_max_search_request_size = 256000;
|
||||||
|
|
||||||
|
/* Now put back the settings that were set with lp_set_cmdline() */
|
||||||
|
apply_lp_set_cmdline();
|
||||||
|
--- a/source4/ldap_server/ldap_server.c
|
||||||
|
+++ b/source4/ldap_server/ldap_server.c
|
||||||
|
@@ -538,6 +538,7 @@ static void ldapsrv_call_read_done(struc
|
||||||
|
struct asn1_data *asn1;
|
||||||
|
DATA_BLOB blob;
|
||||||
|
int ret = LDAP_SUCCESS;
|
||||||
|
+ struct ldap_request_limits limits = {0};
|
||||||
|
|
||||||
|
conn->sockets.read_req = NULL;
|
||||||
|
|
||||||
|
@@ -593,8 +594,13 @@ static void ldapsrv_call_read_done(struc
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
- status = ldap_decode(asn1, samba_ldap_control_handlers(),
|
||||||
|
- call->request);
|
||||||
|
+ limits.max_search_size =
|
||||||
|
+ lpcfg_ldap_max_search_request_size(conn->lp_ctx);
|
||||||
|
+ status = ldap_decode(
|
||||||
|
+ asn1,
|
||||||
|
+ &limits,
|
||||||
|
+ samba_ldap_control_handlers(),
|
||||||
|
+ call->request);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
ldapsrv_terminate_connection(conn, nt_errstr(status));
|
||||||
|
return;
|
||||||
|
--- a/source4/libcli/ldap/ldap_client.c
|
||||||
|
+++ b/source4/libcli/ldap/ldap_client.c
|
||||||
|
@@ -277,6 +277,7 @@ static void ldap_connection_recv_done(st
|
||||||
|
struct ldap_message *msg;
|
||||||
|
struct asn1_data *asn1;
|
||||||
|
DATA_BLOB blob;
|
||||||
|
+ struct ldap_request_limits limits = {0};
|
||||||
|
|
||||||
|
msg = talloc_zero(conn, struct ldap_message);
|
||||||
|
if (msg == NULL) {
|
||||||
|
@@ -306,7 +307,7 @@ static void ldap_connection_recv_done(st
|
||||||
|
|
||||||
|
asn1_load_nocopy(asn1, blob.data, blob.length);
|
||||||
|
|
||||||
|
- status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
|
||||||
|
+ status = ldap_decode(asn1, &limits, samba_ldap_control_handlers(), msg);
|
||||||
|
asn1_free(asn1);
|
||||||
|
if (!NT_STATUS_IS_OK(status)) {
|
||||||
|
TALLOC_FREE(msg);
|
||||||
66
CVE-2020-10704-8.patch
Normal file
66
CVE-2020-10704-8.patch
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
From ee3156c76b86c11829f6f3fe1e3c940b45899c56 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Date: Wed, 8 Apr 2020 10:46:44 +1200
|
||||||
|
Subject: [PATCH 8/8] CVE-2020-10704 libcli ldap: Check search request lengths.
|
||||||
|
|
||||||
|
Check the search request lengths against the limits passed to
|
||||||
|
ldap_decode.
|
||||||
|
|
||||||
|
Credit to OSS-Fuzz
|
||||||
|
|
||||||
|
REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20454
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14334
|
||||||
|
|
||||||
|
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
||||||
|
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
||||||
|
---
|
||||||
|
lib/util/asn1.c | 7 +++++++
|
||||||
|
lib/util/asn1.h | 1 +
|
||||||
|
libcli/ldap/ldap_message.c | 4 ++++
|
||||||
|
3 files changed, 12 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/lib/util/asn1.c b/lib/util/asn1.c
|
||||||
|
index ee3cff9cb65..32d7981d28f 100644
|
||||||
|
--- a/lib/util/asn1.c
|
||||||
|
+++ b/lib/util/asn1.c
|
||||||
|
@@ -1159,3 +1159,10 @@ int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size)
|
||||||
|
*packet_size = size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Get the length of the ASN.1 data
|
||||||
|
+ */
|
||||||
|
+size_t asn1_get_length(const struct asn1_data *asn1) {
|
||||||
|
+ return asn1->length;
|
||||||
|
+}
|
||||||
|
diff --git a/lib/util/asn1.h b/lib/util/asn1.h
|
||||||
|
index fc365724e93..de92a767f14 100644
|
||||||
|
--- a/lib/util/asn1.h
|
||||||
|
+++ b/lib/util/asn1.h
|
||||||
|
@@ -106,5 +106,6 @@ bool asn1_extract_blob(struct asn1_data *asn1, TALLOC_CTX *mem_ctx,
|
||||||
|
DATA_BLOB *pblob);
|
||||||
|
void asn1_load_nocopy(struct asn1_data *data, uint8_t *buf, size_t len);
|
||||||
|
int asn1_peek_full_tag(DATA_BLOB blob, uint8_t tag, size_t *packet_size);
|
||||||
|
+size_t asn1_get_length(const struct asn1_data *asn1);
|
||||||
|
|
||||||
|
#endif /* _ASN_1_H */
|
||||||
|
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
|
||||||
|
index d38fa0b3b61..69a48279532 100644
|
||||||
|
--- a/libcli/ldap/ldap_message.c
|
||||||
|
+++ b/libcli/ldap/ldap_message.c
|
||||||
|
@@ -1259,7 +1259,11 @@ _PUBLIC_ NTSTATUS ldap_decode(struct asn1_data *data,
|
||||||
|
struct ldap_SearchRequest *r = &msg->r.SearchRequest;
|
||||||
|
int sizelimit, timelimit;
|
||||||
|
const char **attrs = NULL;
|
||||||
|
+ size_t request_size = asn1_get_length(data);
|
||||||
|
msg->type = LDAP_TAG_SearchRequest;
|
||||||
|
+ if (request_size > limits->max_search_size) {
|
||||||
|
+ goto prot_err;
|
||||||
|
+ }
|
||||||
|
if (!asn1_start_tag(data, tag)) goto prot_err;
|
||||||
|
if (!asn1_read_OctetString_talloc(msg, data, &r->basedn)) goto prot_err;
|
||||||
|
if (!asn1_read_enumerated(data, (int *)(void *)&(r->scope))) goto prot_err;
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
13
samba.spec
13
samba.spec
@ -49,7 +49,7 @@
|
|||||||
|
|
||||||
Name: samba
|
Name: samba
|
||||||
Version: 4.11.6
|
Version: 4.11.6
|
||||||
Release: 5
|
Release: 6
|
||||||
|
|
||||||
Summary: A suite for Linux to interoperate with Windows
|
Summary: A suite for Linux to interoperate with Windows
|
||||||
License: GPLv3+ and LGPLv3+
|
License: GPLv3+ and LGPLv3+
|
||||||
@ -69,6 +69,14 @@ Source201: README.downgrade
|
|||||||
Patch100: 0000-use-gnutls-for-des-cbc.patch
|
Patch100: 0000-use-gnutls-for-des-cbc.patch
|
||||||
Patch101: 0001-handle-removal-des-enctypes-from-krb5.patch
|
Patch101: 0001-handle-removal-des-enctypes-from-krb5.patch
|
||||||
Patch102: 0002-samba-tool-create-working-private-krb5.conf.patch
|
Patch102: 0002-samba-tool-create-working-private-krb5.conf.patch
|
||||||
|
Patch103: CVE-2020-10700-1.patch
|
||||||
|
Patch104: CVE-2020-10700-3.patch
|
||||||
|
Patch105: CVE-2020-10704-1.patch
|
||||||
|
Patch106: CVE-2020-10704-3.patch
|
||||||
|
Patch107: CVE-2020-10704-5.patch
|
||||||
|
Patch108: CVE-2020-10704-6.patch
|
||||||
|
Patch109: CVE-2020-10704-7.patch
|
||||||
|
Patch110: CVE-2020-10704-8.patch
|
||||||
|
|
||||||
BuildRequires: avahi-devel cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel
|
BuildRequires: avahi-devel cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel
|
||||||
BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel libattr-devel
|
BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel libattr-devel
|
||||||
@ -3079,6 +3087,9 @@ fi
|
|||||||
%{_mandir}/man8/*
|
%{_mandir}/man8/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed May 20 2020 zhouyihang <zhouyihang3@huawei.com> - 4.11.6-6
|
||||||
|
- fix CVE-2020-10700,CVE-2020-10704
|
||||||
|
|
||||||
* Sat Mar 21 2020 songnannan <songnannan2@huawei.com> - 4.11.6-5
|
* Sat Mar 21 2020 songnannan <songnannan2@huawei.com> - 4.11.6-5
|
||||||
- bugfix about update
|
- bugfix about update
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user