update to 4.11.12
This commit is contained in:
parent
12efca8953
commit
47aed4a7e0
@ -1,222 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,82 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,547 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,52 +0,0 @@
|
|||||||
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;
|
|
||||||
@ -1,96 +0,0 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
@ -1,163 +0,0 @@
|
|||||||
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 = {
|
|
||||||
@ -1,211 +0,0 @@
|
|||||||
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);
|
|
||||||
@ -1,66 +0,0 @@
|
|||||||
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
|
|
||||||
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
From b8628cb44766ac4c4817b1a50f09ca316425bd8b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Tue, 5 May 2020 12:54:59 +1200
|
|
||||||
Subject: [PATCH 01/22] CVE-2020-10730: vlv: Use strcmp(), not strncmp()
|
|
||||||
checking the NULL terminated control OIDs
|
|
||||||
|
|
||||||
The end result is the same, as sizeof() includes the trailing NUL, but this
|
|
||||||
avoids having to think about that.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/samdb/ldb_modules/vlv_pagination.c | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
index 980177cb05e..31e64b4bd78 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
@@ -682,8 +682,8 @@ vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
|
|
||||||
if (control->oid == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
- if (strncmp(control->oid, LDB_CONTROL_VLV_REQ_OID, sizeof(LDB_CONTROL_VLV_REQ_OID)) == 0 ||
|
|
||||||
- strncmp(control->oid, LDB_CONTROL_SERVER_SORT_OID, sizeof(LDB_CONTROL_SERVER_SORT_OID)) == 0) {
|
|
||||||
+ if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
|
|
||||||
+ strcmp(control->oid, LDB_CONTROL_SERVER_SORT_OID) == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
new_controls[j] = talloc_steal(new_controls, control);
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
From 303947c58abf9311a666fe63ebd4ce26655ff36e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Date: Wed, 13 May 2020 10:56:56 +1200
|
|
||||||
Subject: [PATCH 10/22] CVE-2020-10730: lib ldb: Check if
|
|
||||||
ldb_lock_backend_callback called twice
|
|
||||||
|
|
||||||
Prevent use after free issues if ldb_lock_backend_callback is called
|
|
||||||
twice, usually due to ldb_module_done being called twice. This can happen if a
|
|
||||||
module ignores the return value from function a function that calls
|
|
||||||
ldb_module_done as part of it's error handling.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
lib/ldb/common/ldb.c | 9 ++++++++-
|
|
||||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/lib/ldb/common/ldb.c b/lib/ldb/common/ldb.c
|
|
||||||
index 95e9138a56b..2d0926ffaf9 100644
|
|
||||||
--- a/lib/ldb/common/ldb.c
|
|
||||||
+++ b/lib/ldb/common/ldb.c
|
|
||||||
@@ -1018,6 +1018,13 @@ static int ldb_lock_backend_callback(struct ldb_request *req,
|
|
||||||
struct ldb_db_lock_context *lock_context;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
+ if (req->context == NULL) {
|
|
||||||
+ /*
|
|
||||||
+ * The usual way to get here is to ignore the return codes
|
|
||||||
+ * and continuing processing after an error.
|
|
||||||
+ */
|
|
||||||
+ abort();
|
|
||||||
+ }
|
|
||||||
lock_context = talloc_get_type(req->context,
|
|
||||||
struct ldb_db_lock_context);
|
|
||||||
|
|
||||||
@@ -1032,7 +1039,7 @@ static int ldb_lock_backend_callback(struct ldb_request *req,
|
|
||||||
* If this is a LDB_REPLY_DONE or an error, unlock the
|
|
||||||
* DB by calling the destructor on this context
|
|
||||||
*/
|
|
||||||
- talloc_free(lock_context);
|
|
||||||
+ TALLOC_FREE(req->context);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,46 +0,0 @@
|
|||||||
From 2041c05d9b41fb0255c3492d118628c14a0c4b3d Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Tue, 5 May 2020 12:55:57 +1200
|
|
||||||
Subject: [PATCH 02/22] CVE-2020-10730: vlv: Do not re-ASQ search the results
|
|
||||||
of an ASQ search with VLV
|
|
||||||
|
|
||||||
This is a silly combination, but at least try and keep the results sensible
|
|
||||||
and avoid a double-dereference.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/samdb/ldb_modules/vlv_pagination.c | 11 +++++++++++
|
|
||||||
1 file changed, 11 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
index 31e64b4bd78..d58a62482c9 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
@@ -682,10 +682,21 @@ vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
|
|
||||||
if (control->oid == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
+ /*
|
|
||||||
+ * Do not re-use VLV, nor the server-sort, both are
|
|
||||||
+ * already handled here.
|
|
||||||
+ */
|
|
||||||
if (strcmp(control->oid, LDB_CONTROL_VLV_REQ_OID) == 0 ||
|
|
||||||
strcmp(control->oid, LDB_CONTROL_SERVER_SORT_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);
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,57 +0,0 @@
|
|||||||
From cf10f9b9a9a2f94afc526995a4034c1c6f05f5b4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Tue, 5 May 2020 13:16:48 +1200
|
|
||||||
Subject: [PATCH 03/22] CVE-2020-10730: selftest: Add test to confirm VLV
|
|
||||||
interaction with ASQ
|
|
||||||
|
|
||||||
Tested against Windows 1709.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/tests/python/asq.py | 27 +++++++++++++++++++++++++++
|
|
||||||
1 file changed, 27 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/tests/python/asq.py b/source4/dsdb/tests/python/asq.py
|
|
||||||
index a32c9f40cd3..1c93a45f131 100644
|
|
||||||
--- a/source4/dsdb/tests/python/asq.py
|
|
||||||
+++ b/source4/dsdb/tests/python/asq.py
|
|
||||||
@@ -162,6 +162,33 @@ class ASQLDAPTest(samba.tests.TestCase):
|
|
||||||
self.assertIn(ldb.Dn(self.ldb, str(group)),
|
|
||||||
self.members)
|
|
||||||
|
|
||||||
+ def test_asq_vlv(self):
|
|
||||||
+ """Testing ASQ behaviour with VLV 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!
|
|
||||||
+
|
|
||||||
+ """
|
|
||||||
+
|
|
||||||
+ sort_control = "server_sort:1:0:cn"
|
|
||||||
+
|
|
||||||
+ msgs = self.ldb.search(base=self.top_dn,
|
|
||||||
+ scope=ldb.SCOPE_BASE,
|
|
||||||
+ attrs=["objectGUID", "cn", "member"],
|
|
||||||
+ controls=["asq:1:member",
|
|
||||||
+ sort_control,
|
|
||||||
+ "vlv:1:20:20:11:0"])
|
|
||||||
+
|
|
||||||
+ 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
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
From 3fd7ce69761fd2e21a85101772196aafc5ae57df Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Tue, 5 May 2020 16:34:11 +1200
|
|
||||||
Subject: [PATCH 04/22] CVE-2020-10730: vlv: Another workaround for mixing ASQ
|
|
||||||
and VLV
|
|
||||||
|
|
||||||
This is essentially an alternative patch, but without the correct
|
|
||||||
behaviour. Instead this just avoids a segfault.
|
|
||||||
|
|
||||||
Included in case we have something simialr again in
|
|
||||||
another module.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
.../dsdb/samdb/ldb_modules/vlv_pagination.c | 19 +++++++++++++++----
|
|
||||||
1 file changed, 15 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
index d58a62482c9..720b5e95638 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
@@ -442,10 +442,21 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
ret = vlv_search_by_dn_guid(ac->module, ac, &result, guid,
|
|
||||||
ac->req->op.search.attrs);
|
|
||||||
|
|
||||||
- if (ret == LDAP_NO_SUCH_OBJECT) {
|
|
||||||
- /* The thing isn't there, which we quietly
|
|
||||||
- ignore and go on to send an extra one
|
|
||||||
- instead. */
|
|
||||||
+ if (ret == LDAP_NO_SUCH_OBJECT
|
|
||||||
+ || result->count != 1) {
|
|
||||||
+ /*
|
|
||||||
+ * The thing isn't there, which we quietly
|
|
||||||
+ * ignore and go on to send an extra one
|
|
||||||
+ * instead.
|
|
||||||
+ *
|
|
||||||
+ * result->count == 0 or > 1 can only
|
|
||||||
+ * happen if ASQ (which breaks all the
|
|
||||||
+ * rules) is somehow invoked (as this
|
|
||||||
+ * is a BASE search).
|
|
||||||
+ *
|
|
||||||
+ * (We skip the ASQ cookie for the
|
|
||||||
+ * GUID searches)
|
|
||||||
+ */
|
|
||||||
if (last_i < ac->store->num_entries - 1) {
|
|
||||||
last_i++;
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,92 +0,0 @@
|
|||||||
From 01cce3d1fc69f04cdc237425b2f2ad1f2ac973d4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Wed, 6 May 2020 16:19:01 +1200
|
|
||||||
Subject: [PATCH 05/22] CVE-2020-10730: selftest: Add test to show that VLV and
|
|
||||||
paged_results are incompatible
|
|
||||||
|
|
||||||
As tested against Windows Server 1709
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/tests/python/asq.py | 27 +++++++++++++++++++++++++++
|
|
||||||
source4/dsdb/tests/python/vlv.py | 23 +++++++++++++++++++++++
|
|
||||||
2 files changed, 50 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/tests/python/asq.py b/source4/dsdb/tests/python/asq.py
|
|
||||||
index 1c93a45f131..33973d66c37 100644
|
|
||||||
--- a/source4/dsdb/tests/python/asq.py
|
|
||||||
+++ b/source4/dsdb/tests/python/asq.py
|
|
||||||
@@ -189,6 +189,33 @@ class ASQLDAPTest(samba.tests.TestCase):
|
|
||||||
self.assertIn(ldb.Dn(self.ldb, str(group)),
|
|
||||||
self.members)
|
|
||||||
|
|
||||||
+ def test_asq_vlv_paged(self):
|
|
||||||
+ """Testing ASQ behaviour with VLV and 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!
|
|
||||||
+
|
|
||||||
+ Thankfully combining both of these gives
|
|
||||||
+ unavailable-critical-extension against Windows 1709
|
|
||||||
+
|
|
||||||
+ """
|
|
||||||
+
|
|
||||||
+ sort_control = "server_sort:1:0:cn"
|
|
||||||
+
|
|
||||||
+ try:
|
|
||||||
+ msgs = self.ldb.search(base=self.top_dn,
|
|
||||||
+ scope=ldb.SCOPE_BASE,
|
|
||||||
+ attrs=["objectGUID", "cn", "member"],
|
|
||||||
+ controls=["asq:1:member",
|
|
||||||
+ sort_control,
|
|
||||||
+ "vlv:1:20:20:11:0",
|
|
||||||
+ "paged_results:1:1024"])
|
|
||||||
+ self.fail("should have failed with LDAP_UNAVAILABLE_CRITICAL_EXTENSION")
|
|
||||||
+ except ldb.LdbError as e:
|
|
||||||
+ (enum, estr) = e.args
|
|
||||||
+ self.assertEqual(enum, ldb.ERR_UNSUPPORTED_CRITICAL_EXTENSION)
|
|
||||||
+
|
|
||||||
if "://" not in url:
|
|
||||||
if os.path.isfile(url):
|
|
||||||
url = "tdb://%s" % url
|
|
||||||
diff --git a/source4/dsdb/tests/python/vlv.py b/source4/dsdb/tests/python/vlv.py
|
|
||||||
index 2efcaa5e7a3..f3c603e3a39 100644
|
|
||||||
--- a/source4/dsdb/tests/python/vlv.py
|
|
||||||
+++ b/source4/dsdb/tests/python/vlv.py
|
|
||||||
@@ -1644,6 +1644,29 @@ class PagedResultsTests(TestsWithUserOU):
|
|
||||||
page_size=len(self.users))
|
|
||||||
self.assertEqual(results, set_2[ps*2:])
|
|
||||||
|
|
||||||
+ def test_vlv_paged(self):
|
|
||||||
+ """Testing behaviour with VLV and paged_results set.
|
|
||||||
+
|
|
||||||
+ A strange combination, certainly
|
|
||||||
+
|
|
||||||
+ Thankfully combining both of these gives
|
|
||||||
+ unavailable-critical-extension against Windows 1709
|
|
||||||
+
|
|
||||||
+ """
|
|
||||||
+ sort_control = "server_sort:1:0:cn"
|
|
||||||
+
|
|
||||||
+ try:
|
|
||||||
+ msgs = self.ldb.search(base=self.base_dn,
|
|
||||||
+ scope=ldb.SCOPE_SUBTREE,
|
|
||||||
+ attrs=["objectGUID", "cn", "member"],
|
|
||||||
+ controls=["vlv:1:20:20:11:0",
|
|
||||||
+ sort_control,
|
|
||||||
+ "paged_results:1:1024"])
|
|
||||||
+ self.fail("should have failed with LDAP_UNAVAILABLE_CRITICAL_EXTENSION")
|
|
||||||
+ except ldb.LdbError as e:
|
|
||||||
+ (enum, estr) = e.args
|
|
||||||
+ self.assertEqual(enum, ldb.ERR_UNSUPPORTED_CRITICAL_EXTENSION)
|
|
||||||
+
|
|
||||||
|
|
||||||
if "://" not in host:
|
|
||||||
if os.path.isfile(host):
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
From c7608e43c933d9a33d94e32371080e64cc1d4fcb Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Wed, 6 May 2020 17:05:30 +1200
|
|
||||||
Subject: [PATCH 06/22] CVE-2020-10730: dsdb: Fix crash when vlv and
|
|
||||||
paged_results are combined
|
|
||||||
|
|
||||||
The GUID is not returned in the DN for some reason in this (to be banned)
|
|
||||||
combination.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/samdb/ldb_modules/paged_results.c | 4 ++++
|
|
||||||
1 file changed, 4 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
index dc211dd18ce..f720a2e4337 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
@@ -416,6 +416,10 @@ static int paged_search_callback(struct ldb_request *req,
|
|
||||||
|
|
||||||
guid_blob = ldb_dn_get_extended_component(ares->message->dn,
|
|
||||||
"GUID");
|
|
||||||
+ if (guid_blob == NULL) {
|
|
||||||
+ return ldb_module_done(ac->req, NULL, NULL,
|
|
||||||
+ LDB_ERR_OPERATIONS_ERROR);
|
|
||||||
+ }
|
|
||||||
status = GUID_from_ndr_blob(guid_blob, &guid);
|
|
||||||
if (!NT_STATUS_IS_OK(status)) {
|
|
||||||
return ldb_module_done(ac->req, NULL, NULL,
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,48 +0,0 @@
|
|||||||
From 0c8cd0a9fbd9d17c1d7219f977ca35f88f0a2ea3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Wed, 6 May 2020 16:18:19 +1200
|
|
||||||
Subject: [PATCH 07/22] CVE-2020-10730: dsdb: Ban the combination of
|
|
||||||
paged_results and VLV
|
|
||||||
|
|
||||||
This (two different paging controls) makes no sense and fails against
|
|
||||||
Windows Server 1709.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
source4/dsdb/samdb/ldb_modules/paged_results.c | 10 ++++++++++
|
|
||||||
1 file changed, 10 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
index f720a2e4337..aa49a6e4aa5 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
@@ -589,6 +589,7 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
|
|
||||||
{
|
|
||||||
struct ldb_context *ldb;
|
|
||||||
struct ldb_control *control;
|
|
||||||
+ struct ldb_control *vlv_control;
|
|
||||||
struct private_data *private_data;
|
|
||||||
struct ldb_paged_control *paged_ctrl;
|
|
||||||
struct ldb_request *search_req;
|
|
||||||
@@ -612,6 +613,15 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
|
|
||||||
private_data = talloc_get_type(ldb_module_get_private(module),
|
|
||||||
struct private_data);
|
|
||||||
|
|
||||||
+ vlv_control = ldb_request_get_control(req, LDB_CONTROL_VLV_REQ_OID);
|
|
||||||
+ if (vlv_control != NULL) {
|
|
||||||
+ /*
|
|
||||||
+ * VLV and paged_results are not allowed at the same
|
|
||||||
+ * time
|
|
||||||
+ */
|
|
||||||
+ return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
ac = talloc_zero(req, struct paged_context);
|
|
||||||
if (ac == NULL) {
|
|
||||||
ldb_set_errstring(ldb, "Out of Memory");
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,138 +0,0 @@
|
|||||||
From dcf713038ff10e35a74ee255f1634be81103e360 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Date: Mon, 18 May 2020 12:36:57 +1200
|
|
||||||
Subject: [PATCH 08/22] CVE-2020-10730: s4 dsdb paged_results: Prevent repeat
|
|
||||||
call of ldb_module_done
|
|
||||||
|
|
||||||
Check the return code from paged_results, if it is not LDB_SUCCESS
|
|
||||||
ldb_module_done has already been called, and SHOULD NOT be called again.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
.../dsdb/samdb/ldb_modules/paged_results.c | 43 +++++++++++++++----
|
|
||||||
1 file changed, 34 insertions(+), 9 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
index aa49a6e4aa5..735883e8802 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
@@ -237,14 +237,16 @@ static int paged_search_by_dn_guid(struct ldb_module *module,
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
-static int paged_results(struct paged_context *ac)
|
|
||||||
+static int paged_results(struct paged_context *ac, struct ldb_reply *ares)
|
|
||||||
{
|
|
||||||
struct ldb_paged_control *paged;
|
|
||||||
unsigned int i, num_ctrls;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (ac->store == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (ac->store->last_i < ac->store->num_entries && ac->size > 0) {
|
|
||||||
@@ -273,12 +275,17 @@ static int paged_results(struct paged_context *ac)
|
|
||||||
instead. */
|
|
||||||
continue;
|
|
||||||
} else if (ret != LDB_SUCCESS) {
|
|
||||||
- return ret;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ldb_module_send_entry(ac->req, result->msgs[0],
|
|
||||||
NULL);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
+ /*
|
|
||||||
+ * ldb_module_send_entry will have called
|
|
||||||
+ * ldb_module_done if an error occurred.
|
|
||||||
+ */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -289,6 +296,10 @@ static int paged_results(struct paged_context *ac)
|
|
||||||
*/
|
|
||||||
ret = send_referrals(ac->store, ac->req);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
+ /*
|
|
||||||
+ * send_referrals will have called ldb_module_done
|
|
||||||
+ * if an error occurred.
|
|
||||||
+ */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -305,7 +316,9 @@ static int paged_results(struct paged_context *ac)
|
|
||||||
|
|
||||||
ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls +1);
|
|
||||||
if (ac->controls == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
ac->controls[num_ctrls] = NULL;
|
|
||||||
|
|
||||||
@@ -316,20 +329,26 @@ static int paged_results(struct paged_context *ac)
|
|
||||||
|
|
||||||
ac->controls[i] = talloc(ac->controls, struct ldb_control);
|
|
||||||
if (ac->controls[i] == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ac->controls[i]->oid = talloc_strdup(ac->controls[i],
|
|
||||||
LDB_CONTROL_PAGED_RESULTS_OID);
|
|
||||||
if (ac->controls[i]->oid == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ac->controls[i]->critical = 0;
|
|
||||||
|
|
||||||
paged = talloc(ac->controls[i], struct ldb_paged_control);
|
|
||||||
if (paged == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ac->controls[i]->data = paged;
|
|
||||||
@@ -456,7 +475,13 @@ static int paged_search_callback(struct ldb_request *req,
|
|
||||||
store->result_array_size = store->num_entries;
|
|
||||||
|
|
||||||
ac->store->controls = talloc_move(ac->store, &ares->controls);
|
|
||||||
- ret = paged_results(ac);
|
|
||||||
+ ret = paged_results(ac, ares);
|
|
||||||
+ if (ret != LDB_SUCCESS) {
|
|
||||||
+ /* paged_results will have called ldb_module_done
|
|
||||||
+ * if an error occurred
|
|
||||||
+ */
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
return ldb_module_done(ac->req, ac->controls,
|
|
||||||
ares->response, ret);
|
|
||||||
}
|
|
||||||
@@ -768,7 +793,7 @@ static int paged_search(struct ldb_module *module, struct ldb_request *req)
|
|
||||||
LDB_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
- ret = paged_results(ac);
|
|
||||||
+ ret = paged_results(ac, NULL);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
return ldb_module_done(req, NULL, NULL, ret);
|
|
||||||
}
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,171 +0,0 @@
|
|||||||
From ae6e9445ac8bf8f6870a8caa24406153cd2ee2bf Mon Sep 17 00:00:00 2001
|
|
||||||
From: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Date: Mon, 18 May 2020 12:37:39 +1200
|
|
||||||
Subject: [PATCH 09/22] CVE-2020-10730: s4 dsdb vlv_pagination: Prevent repeat
|
|
||||||
call of ldb_module_done
|
|
||||||
|
|
||||||
Check the return code from vlv_results, if it is not LDB_SUCCESS
|
|
||||||
ldb_module_done has already been called, and SHOULD NOT be called again.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14364
|
|
||||||
|
|
||||||
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
.../dsdb/samdb/ldb_modules/vlv_pagination.c | 61 +++++++++++++++----
|
|
||||||
1 file changed, 49 insertions(+), 12 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
index 720b5e95638..b103bda5f52 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
@@ -387,7 +387,7 @@ static int vlv_calc_real_offset(int offset, int denominator, int n_entries)
|
|
||||||
has been prepared earlier and saved -- or by vlv_search_callback() when a
|
|
||||||
search has just been completed. */
|
|
||||||
|
|
||||||
-static int vlv_results(struct vlv_context *ac)
|
|
||||||
+static int vlv_results(struct vlv_context *ac, struct ldb_reply *ares)
|
|
||||||
{
|
|
||||||
struct ldb_vlv_resp_control *vlv;
|
|
||||||
unsigned int num_ctrls;
|
|
||||||
@@ -397,7 +397,9 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
int target = 0;
|
|
||||||
|
|
||||||
if (ac->store == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ac->store->first_ref) {
|
|
||||||
@@ -406,6 +408,10 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
*/
|
|
||||||
ret = send_referrals(ac->store, ac->req);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
+ /*
|
|
||||||
+ * send_referrals will have called ldb_module_done
|
|
||||||
+ * if there was an error.
|
|
||||||
+ */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -419,14 +425,23 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
vlv_details,
|
|
||||||
sort_details, &ret);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
- return ret;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req,
|
|
||||||
+ ac->controls,
|
|
||||||
+ ares->response,
|
|
||||||
+ ret);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
target = vlv_calc_real_offset(vlv_details->match.byOffset.offset,
|
|
||||||
vlv_details->match.byOffset.contentCount,
|
|
||||||
ac->store->num_entries);
|
|
||||||
if (target == -1) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req,
|
|
||||||
+ ac->controls,
|
|
||||||
+ ares->response,
|
|
||||||
+ ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -462,12 +477,20 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else if (ret != LDB_SUCCESS) {
|
|
||||||
- return ret;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req,
|
|
||||||
+ ac->controls,
|
|
||||||
+ ares->response,
|
|
||||||
+ ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ldb_module_send_entry(ac->req, result->msgs[0],
|
|
||||||
NULL);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
+ /*
|
|
||||||
+ * ldb_module_send_entry will have called
|
|
||||||
+ * ldb_module_done if there was an error
|
|
||||||
+ */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -488,7 +511,9 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
|
|
||||||
ac->controls = talloc_array(ac, struct ldb_control *, num_ctrls + 1);
|
|
||||||
if (ac->controls == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
ac->controls[num_ctrls] = NULL;
|
|
||||||
|
|
||||||
@@ -498,20 +523,26 @@ static int vlv_results(struct vlv_context *ac)
|
|
||||||
|
|
||||||
ac->controls[i] = talloc(ac->controls, struct ldb_control);
|
|
||||||
if (ac->controls[i] == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ac->controls[i]->oid = talloc_strdup(ac->controls[i],
|
|
||||||
LDB_CONTROL_VLV_RESP_OID);
|
|
||||||
if (ac->controls[i]->oid == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ac->controls[i]->critical = 0;
|
|
||||||
|
|
||||||
vlv = talloc(ac->controls[i], struct ldb_vlv_resp_control);
|
|
||||||
if (vlv == NULL) {
|
|
||||||
- return LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ ret = LDB_ERR_OPERATIONS_ERROR;
|
|
||||||
+ return ldb_module_done(
|
|
||||||
+ ac->req, ac->controls, ares->response, ret);
|
|
||||||
}
|
|
||||||
ac->controls[i]->data = vlv;
|
|
||||||
|
|
||||||
@@ -600,7 +631,13 @@ static int vlv_search_callback(struct ldb_request *req, struct ldb_reply *ares)
|
|
||||||
store->result_array_size = store->num_entries;
|
|
||||||
|
|
||||||
ac->store->controls = talloc_move(ac->store, &ares->controls);
|
|
||||||
- ret = vlv_results(ac);
|
|
||||||
+ ret = vlv_results(ac, ares);
|
|
||||||
+ if (ret != LDB_SUCCESS) {
|
|
||||||
+ /* vlv_results will have called ldb_module_done
|
|
||||||
+ * if there was an error.
|
|
||||||
+ */
|
|
||||||
+ return ret;
|
|
||||||
+ }
|
|
||||||
return ldb_module_done(ac->req, ac->controls,
|
|
||||||
ares->response, ret);
|
|
||||||
}
|
|
||||||
@@ -845,9 +882,9 @@ static int vlv_search(struct ldb_module *module, struct ldb_request *req)
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
- ret = vlv_results(ac);
|
|
||||||
+ ret = vlv_results(ac, NULL);
|
|
||||||
if (ret != LDB_SUCCESS) {
|
|
||||||
- return ldb_module_done(req, NULL, NULL, ret);
|
|
||||||
+ return ret;
|
|
||||||
}
|
|
||||||
return ldb_module_done(req, ac->controls, NULL,
|
|
||||||
LDB_SUCCESS);
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,272 +0,0 @@
|
|||||||
From ddd3ed7ce2e2776839c463010bd975f01dd0977d Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Thu, 11 Jun 2020 17:38:51 +1200
|
|
||||||
Subject: [PATCH 12/22] CVE-2020-10745: pytests: hand-rolled invalid dns/nbt
|
|
||||||
packet tests
|
|
||||||
|
|
||||||
The client libraries don't allow us to make packets that are broken in
|
|
||||||
certain ways, so we need to construct them as byte strings.
|
|
||||||
|
|
||||||
These tests all fail at present, proving the server is rendered
|
|
||||||
unresponsive, which is the crux of CVE-2020-10745.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
python/samba/tests/dns_packet.py | 211 +++++++++++++++++++++++++++++++
|
|
||||||
selftest/knownfail.d/dns_packet | 2 +
|
|
||||||
source4/selftest/tests.py | 10 ++
|
|
||||||
3 files changed, 223 insertions(+)
|
|
||||||
create mode 100644 python/samba/tests/dns_packet.py
|
|
||||||
create mode 100644 selftest/knownfail.d/dns_packet
|
|
||||||
|
|
||||||
diff --git a/python/samba/tests/dns_packet.py b/python/samba/tests/dns_packet.py
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..c4f843eb613
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/python/samba/tests/dns_packet.py
|
|
||||||
@@ -0,0 +1,211 @@
|
|
||||||
+# Tests of malformed DNS packets
|
|
||||||
+# Copyright (C) Catalyst.NET ltd
|
|
||||||
+#
|
|
||||||
+# written by Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
+#
|
|
||||||
+# 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/>.
|
|
||||||
+
|
|
||||||
+"""Sanity tests for DNS and NBT server parsing.
|
|
||||||
+
|
|
||||||
+We don't use a proper client library so we can make improper packets.
|
|
||||||
+"""
|
|
||||||
+
|
|
||||||
+import os
|
|
||||||
+import struct
|
|
||||||
+import socket
|
|
||||||
+import select
|
|
||||||
+from samba.dcerpc import dns, nbt
|
|
||||||
+
|
|
||||||
+from samba.tests import TestCase
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def _msg_id():
|
|
||||||
+ while True:
|
|
||||||
+ for i in range(1, 0xffff):
|
|
||||||
+ yield i
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+SERVER = os.environ['SERVER_IP']
|
|
||||||
+SERVER_NAME = f"{os.environ['SERVER']}.{os.environ['REALM']}"
|
|
||||||
+TIMEOUT = 0.5
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def encode_netbios_bytes(chars):
|
|
||||||
+ """Even RFC 1002 uses distancing quotes when calling this "compression"."""
|
|
||||||
+ out = []
|
|
||||||
+ chars = (chars + b' ')[:16]
|
|
||||||
+ for c in chars:
|
|
||||||
+ out.append((c >> 4) + 65)
|
|
||||||
+ out.append((c & 15) + 65)
|
|
||||||
+ return bytes(out)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class TestDnsPacketBase(TestCase):
|
|
||||||
+ msg_id = _msg_id()
|
|
||||||
+
|
|
||||||
+ def tearDown(self):
|
|
||||||
+ # we need to ensure the DNS server is responsive before
|
|
||||||
+ # continuing.
|
|
||||||
+ for i in range(40):
|
|
||||||
+ ok = self._known_good_query()
|
|
||||||
+ if ok:
|
|
||||||
+ return
|
|
||||||
+ print(f"the server is STILL unresponsive after {40 * TIMEOUT} seconds")
|
|
||||||
+
|
|
||||||
+ def decode_reply(self, data):
|
|
||||||
+ header = data[:12]
|
|
||||||
+ id, flags, n_q, n_a, n_rec, n_exta = struct.unpack('!6H',
|
|
||||||
+ header)
|
|
||||||
+ return {
|
|
||||||
+ 'rcode': flags & 0xf
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ def construct_query(self, names):
|
|
||||||
+ """Create a query packet containing one query record.
|
|
||||||
+
|
|
||||||
+ *names* is either a single string name in the usual dotted
|
|
||||||
+ form, or a list of names. In the latter case, each name can
|
|
||||||
+ be a dotted string or a list of byte components, which allows
|
|
||||||
+ dots in components. Where I say list, I mean non-string
|
|
||||||
+ iterable.
|
|
||||||
+
|
|
||||||
+ Examples:
|
|
||||||
+
|
|
||||||
+ # these 3 are all the same
|
|
||||||
+ "example.com"
|
|
||||||
+ ["example.com"]
|
|
||||||
+ [[b"example", b"com"]]
|
|
||||||
+
|
|
||||||
+ # this is three names in the same request
|
|
||||||
+ ["example.com",
|
|
||||||
+ [b"example", b"com", b"..!"],
|
|
||||||
+ (b"first component", b" 2nd component")]
|
|
||||||
+ """
|
|
||||||
+ header = struct.pack('!6H',
|
|
||||||
+ next(self.msg_id),
|
|
||||||
+ 0x0100, # query, with recursion
|
|
||||||
+ len(names), # number of queries
|
|
||||||
+ 0x0000, # no answers
|
|
||||||
+ 0x0000, # no records
|
|
||||||
+ 0x0000, # no extra records
|
|
||||||
+ )
|
|
||||||
+ tail = struct.pack('!BHH',
|
|
||||||
+ 0x00, # root node
|
|
||||||
+ self.qtype,
|
|
||||||
+ 0x0001, # class IN-ternet
|
|
||||||
+ )
|
|
||||||
+ encoded_bits = []
|
|
||||||
+ for name in names:
|
|
||||||
+ if isinstance(name, str):
|
|
||||||
+ bits = name.encode('utf8').split(b'.')
|
|
||||||
+ else:
|
|
||||||
+ bits = name
|
|
||||||
+
|
|
||||||
+ for b in bits:
|
|
||||||
+ encoded_bits.append(b'%c%s' % (len(b), b))
|
|
||||||
+ encoded_bits.append(tail)
|
|
||||||
+
|
|
||||||
+ return header + b''.join(encoded_bits)
|
|
||||||
+
|
|
||||||
+ def _test_query(self, names=(), expected_rcode=None):
|
|
||||||
+
|
|
||||||
+ if isinstance(names, str):
|
|
||||||
+ names = [names]
|
|
||||||
+
|
|
||||||
+ packet = self.construct_query(names)
|
|
||||||
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
+ s.sendto(packet, self.server)
|
|
||||||
+ r, _, _ = select.select([s], [], [], TIMEOUT)
|
|
||||||
+ s.close()
|
|
||||||
+ # It is reasonable to not reply to these packets (Windows
|
|
||||||
+ # doesn't), but it is not reasonable to render the server
|
|
||||||
+ # unresponsive.
|
|
||||||
+ if r != [s]:
|
|
||||||
+ ok = self._known_good_query()
|
|
||||||
+ self.assertTrue(ok, f"the server is unresponsive")
|
|
||||||
+
|
|
||||||
+ def _known_good_query(self):
|
|
||||||
+ if self.server[1] == 53:
|
|
||||||
+ name = SERVER_NAME
|
|
||||||
+ expected_rcode = dns.DNS_RCODE_OK
|
|
||||||
+ else:
|
|
||||||
+ name = [encode_netbios_bytes(b'nxdomain'), b'nxdomain']
|
|
||||||
+ expected_rcode = nbt.NBT_RCODE_NAM
|
|
||||||
+
|
|
||||||
+ packet = self.construct_query([name])
|
|
||||||
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
+ s.sendto(packet, self.server)
|
|
||||||
+ r, _, _ = select.select([s], [], [], TIMEOUT)
|
|
||||||
+ if r != [s]:
|
|
||||||
+ s.close()
|
|
||||||
+ return False
|
|
||||||
+
|
|
||||||
+ data, addr = s.recvfrom(4096)
|
|
||||||
+ s.close()
|
|
||||||
+ rcode = self.decode_reply(data)['rcode']
|
|
||||||
+ return expected_rcode == rcode
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class TestDnsPackets(TestDnsPacketBase):
|
|
||||||
+ server = (SERVER, 53)
|
|
||||||
+ qtype = 1 # dns type A
|
|
||||||
+
|
|
||||||
+ def _test_many_repeated_components(self, label, n, expected_rcode=None):
|
|
||||||
+ name = [label] * n
|
|
||||||
+ self._test_query([name],
|
|
||||||
+ expected_rcode=expected_rcode)
|
|
||||||
+
|
|
||||||
+ def test_127_very_dotty_components(self):
|
|
||||||
+ label = b'.' * 63
|
|
||||||
+ self._test_many_repeated_components(label, 127)
|
|
||||||
+
|
|
||||||
+ def test_127_half_dotty_components(self):
|
|
||||||
+ label = b'x.' * 31 + b'x'
|
|
||||||
+ self._test_many_repeated_components(label, 127)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class TestNbtPackets(TestDnsPacketBase):
|
|
||||||
+ server = (SERVER, 137)
|
|
||||||
+ qtype = 0x20 # NBT_QTYPE_NETBIOS
|
|
||||||
+
|
|
||||||
+ def _test_nbt_encode_query(self, names, *args, **kwargs):
|
|
||||||
+ if isinstance(names, str):
|
|
||||||
+ names = [names]
|
|
||||||
+
|
|
||||||
+ nbt_names = []
|
|
||||||
+ for name in names:
|
|
||||||
+ if isinstance(name, str):
|
|
||||||
+ bits = name.encode('utf8').split(b'.')
|
|
||||||
+ else:
|
|
||||||
+ bits = name
|
|
||||||
+
|
|
||||||
+ encoded = [encode_netbios_bytes(bits[0])]
|
|
||||||
+ encoded.extend(bits[1:])
|
|
||||||
+ nbt_names.append(encoded)
|
|
||||||
+
|
|
||||||
+ self._test_query(nbt_names, *args, **kwargs)
|
|
||||||
+
|
|
||||||
+ def _test_many_repeated_components(self, label, n, expected_rcode=None):
|
|
||||||
+ name = [label] * n
|
|
||||||
+ name[0] = encode_netbios_bytes(label)
|
|
||||||
+ self._test_query([name],
|
|
||||||
+ expected_rcode=expected_rcode)
|
|
||||||
+
|
|
||||||
+ def test_127_very_dotty_components(self):
|
|
||||||
+ label = b'.' * 63
|
|
||||||
+ self._test_many_repeated_components(label, 127)
|
|
||||||
+
|
|
||||||
+ def test_127_half_dotty_components(self):
|
|
||||||
+ label = b'x.' * 31 + b'x'
|
|
||||||
+ self._test_many_repeated_components(label, 127)
|
|
||||||
diff --git a/selftest/knownfail.d/dns_packet b/selftest/knownfail.d/dns_packet
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..6e2e5a699de
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/selftest/knownfail.d/dns_packet
|
|
||||||
@@ -0,0 +1,2 @@
|
|
||||||
+samba.tests.dns_packet.samba.tests.dns_packet.TestDnsPackets.test_127_very_dotty_components
|
|
||||||
+samba.tests.dns_packet.samba.tests.dns_packet.TestNbtPackets.test_127_very_dotty_components
|
|
||||||
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
|
|
||||||
index f7645365384..6281b7e8f12 100755
|
|
||||||
--- a/source4/selftest/tests.py
|
|
||||||
+++ b/source4/selftest/tests.py
|
|
||||||
@@ -421,6 +421,16 @@ plantestsuite_loadlist("samba.tests.dns_wildcard", "ad_dc", [python, os.path.joi
|
|
||||||
|
|
||||||
plantestsuite_loadlist("samba.tests.dns_invalid", "ad_dc", [python, os.path.join(srcdir(), "python/samba/tests/dns_invalid.py"), '$SERVER_IP', '--machine-pass', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT'])
|
|
||||||
|
|
||||||
+plantestsuite_loadlist("samba.tests.dns_packet",
|
|
||||||
+ "ad_dc",
|
|
||||||
+ [python,
|
|
||||||
+ '-msamba.subunit.run',
|
|
||||||
+ '$LOADLIST',
|
|
||||||
+ "$LISTOPT"
|
|
||||||
+ "samba.tests.dns_packet"
|
|
||||||
+ ])
|
|
||||||
+
|
|
||||||
+
|
|
||||||
for t in smbtorture4_testsuites("dns_internal."):
|
|
||||||
plansmbtorture4testsuite(t, "ad_dc_default:local", '//$SERVER/whavever')
|
|
||||||
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,316 +0,0 @@
|
|||||||
From ddeabf87957ce73e12030977948418c93436a05c Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Fri, 12 Jun 2020 14:26:38 +1200
|
|
||||||
Subject: [PATCH 13/22] CVE-2020-10745: librpc/tests: cmocka tests of dns and
|
|
||||||
ndr strings
|
|
||||||
|
|
||||||
These time the push and pull function in isolation.
|
|
||||||
|
|
||||||
Timing should be under 0.0001 seconds on even quite old hardware; we
|
|
||||||
assert it must be under 0.2 seconds.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
(backported from master commit)
|
|
||||||
[abartlet@samba.org: backported due to differences in pre-existing
|
|
||||||
tests - eg test_ndr - mentioned in wscript_build and tests.py]
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/tests/test_ndr_dns_nbt.c | 236 +++++++++++++++++++++++++++++++
|
|
||||||
librpc/wscript_build | 13 ++
|
|
||||||
selftest/knownfail.d/ndr_dns_nbt | 4 +
|
|
||||||
source4/selftest/tests.py | 2 +
|
|
||||||
4 files changed, 255 insertions(+)
|
|
||||||
create mode 100644 librpc/tests/test_ndr_dns_nbt.c
|
|
||||||
create mode 100644 selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
|
|
||||||
diff --git a/librpc/tests/test_ndr_dns_nbt.c b/librpc/tests/test_ndr_dns_nbt.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..1e2ef45c10d
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/librpc/tests/test_ndr_dns_nbt.c
|
|
||||||
@@ -0,0 +1,236 @@
|
|
||||||
+/*
|
|
||||||
+ * Tests for librpc ndr functions
|
|
||||||
+ *
|
|
||||||
+ * Copyright (C) Catalyst.NET Ltd 2020
|
|
||||||
+ *
|
|
||||||
+ * 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/>.
|
|
||||||
+ *
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+#include "replace.h"
|
|
||||||
+#include <setjmp.h>
|
|
||||||
+#include <cmocka.h>
|
|
||||||
+
|
|
||||||
+#include "includes.h"
|
|
||||||
+#include "librpc/ndr/libndr.h"
|
|
||||||
+#include "librpc/gen_ndr/ndr_dns.h"
|
|
||||||
+#include "librpc/gen_ndr/ndr_nbt.h"
|
|
||||||
+#include "lib/util/time.h"
|
|
||||||
+
|
|
||||||
+#define NBT_NAME "EOGFGLGPCACACACACACACACACACACACA" /* "neko" */
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static DATA_BLOB generate_obnoxious_dns_name(TALLOC_CTX *mem_ctx,
|
|
||||||
+ size_t n_labels,
|
|
||||||
+ size_t dot_every,
|
|
||||||
+ bool is_nbt)
|
|
||||||
+{
|
|
||||||
+ size_t i, j;
|
|
||||||
+ char *s;
|
|
||||||
+ DATA_BLOB name = data_blob_talloc(mem_ctx, NULL, 64 * n_labels + 1);
|
|
||||||
+ assert_non_null(name.data);
|
|
||||||
+
|
|
||||||
+ s = (char*)name.data;
|
|
||||||
+ if (is_nbt) {
|
|
||||||
+ size_t len = strlen(NBT_NAME);
|
|
||||||
+ *s = len;
|
|
||||||
+ s++;
|
|
||||||
+ memcpy(s, NBT_NAME, len);
|
|
||||||
+ s += len;
|
|
||||||
+ n_labels--;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (i = 0; i < n_labels; i++) {
|
|
||||||
+ *s = 63;
|
|
||||||
+ s++;
|
|
||||||
+ for (j = 0; j < 63; j++) {
|
|
||||||
+ if (j % dot_every == (dot_every - 1)) {
|
|
||||||
+ *s = '.';
|
|
||||||
+ } else {
|
|
||||||
+ *s = 'x';
|
|
||||||
+ }
|
|
||||||
+ s++;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ *s = 0;
|
|
||||||
+ s++;
|
|
||||||
+ name.length = s - (char*)name.data;
|
|
||||||
+ return name;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static char *_test_ndr_pull_dns_string_list(TALLOC_CTX *mem_ctx,
|
|
||||||
+ size_t n_labels,
|
|
||||||
+ size_t dot_every,
|
|
||||||
+ bool is_nbt)
|
|
||||||
+{
|
|
||||||
+ enum ndr_err_code ndr_err;
|
|
||||||
+ DATA_BLOB blob = generate_obnoxious_dns_name(mem_ctx,
|
|
||||||
+ n_labels,
|
|
||||||
+ dot_every,
|
|
||||||
+ is_nbt);
|
|
||||||
+
|
|
||||||
+ char *name;
|
|
||||||
+ ndr_pull_flags_fn_t fn;
|
|
||||||
+
|
|
||||||
+ if (is_nbt) {
|
|
||||||
+ fn = (ndr_pull_flags_fn_t)ndr_pull_nbt_string;
|
|
||||||
+ } else {
|
|
||||||
+ fn = (ndr_pull_flags_fn_t)ndr_pull_dns_string;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ndr_err = ndr_pull_struct_blob(&blob,
|
|
||||||
+ mem_ctx,
|
|
||||||
+ &name,
|
|
||||||
+ fn);
|
|
||||||
+ /* Success here is not expected, but we let it go to measure timing. */
|
|
||||||
+ if (ndr_err == NDR_ERR_SUCCESS) {
|
|
||||||
+ printf("pull succeed\n");
|
|
||||||
+ } else {
|
|
||||||
+ assert_int_equal(ndr_err, NDR_ERR_STRING);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ TALLOC_FREE(blob.data);
|
|
||||||
+ return name;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void _test_ndr_push_dns_string_list(TALLOC_CTX *mem_ctx,
|
|
||||||
+ char *name,
|
|
||||||
+ bool is_nbt)
|
|
||||||
+{
|
|
||||||
+ DATA_BLOB blob;
|
|
||||||
+ enum ndr_err_code ndr_err;
|
|
||||||
+ ndr_push_flags_fn_t fn;
|
|
||||||
+
|
|
||||||
+ if (is_nbt) {
|
|
||||||
+ fn = (ndr_push_flags_fn_t)ndr_push_nbt_string;
|
|
||||||
+ } else {
|
|
||||||
+ fn = (ndr_push_flags_fn_t)ndr_push_dns_string;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ndr_err = ndr_push_struct_blob(&blob,
|
|
||||||
+ mem_ctx,
|
|
||||||
+ name,
|
|
||||||
+ fn);
|
|
||||||
+
|
|
||||||
+ /* Success here is not expected, but we let it go to measure timing. */
|
|
||||||
+ if (ndr_err == NDR_ERR_SUCCESS) {
|
|
||||||
+ printf("push succeed\n");
|
|
||||||
+ } else {
|
|
||||||
+ assert_int_equal(ndr_err, NDR_ERR_STRING);
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static uint64_t elapsed_time(struct timespec start, const char *print)
|
|
||||||
+{
|
|
||||||
+ struct timespec end;
|
|
||||||
+ unsigned long long microsecs;
|
|
||||||
+ clock_gettime_mono(&end);
|
|
||||||
+ end.tv_sec -= start.tv_sec;
|
|
||||||
+ if (end.tv_nsec < start.tv_nsec) {
|
|
||||||
+ /* we need to borrow */
|
|
||||||
+ end.tv_nsec += 1000 * 1000 * 1000;
|
|
||||||
+ end.tv_sec -= 1;
|
|
||||||
+ }
|
|
||||||
+ end.tv_nsec -= start.tv_nsec;
|
|
||||||
+ microsecs = end.tv_sec * 1000000;
|
|
||||||
+ microsecs += end.tv_nsec / 1000;
|
|
||||||
+
|
|
||||||
+ if (print != NULL) {
|
|
||||||
+ printf(" %s: %llu microseconds\n", print, microsecs);
|
|
||||||
+ }
|
|
||||||
+ return microsecs;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+static void test_ndr_dns_string_half_dots(void **state)
|
|
||||||
+{
|
|
||||||
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
||||||
+ char *name;
|
|
||||||
+ struct timespec start;
|
|
||||||
+ uint64_t elapsed;
|
|
||||||
+
|
|
||||||
+ clock_gettime_mono(&start);
|
|
||||||
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, false);
|
|
||||||
+ elapsed_time(start, "pull");
|
|
||||||
+ _test_ndr_push_dns_string_list(mem_ctx, name, false);
|
|
||||||
+ elapsed = elapsed_time(start, "total");
|
|
||||||
+ assert_in_range(elapsed, 0, 200000);
|
|
||||||
+ talloc_free(mem_ctx);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void test_ndr_nbt_string_half_dots(void **state)
|
|
||||||
+{
|
|
||||||
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
||||||
+ char *name;
|
|
||||||
+ struct timespec start;
|
|
||||||
+ uint64_t elapsed;
|
|
||||||
+
|
|
||||||
+ clock_gettime_mono(&start);
|
|
||||||
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 2, true);
|
|
||||||
+ elapsed_time(start, "pull");
|
|
||||||
+ _test_ndr_push_dns_string_list(mem_ctx, name, true);
|
|
||||||
+ elapsed = elapsed_time(start, "total");
|
|
||||||
+ assert_in_range(elapsed, 0, 200000);
|
|
||||||
+ talloc_free(mem_ctx);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void test_ndr_dns_string_all_dots(void **state)
|
|
||||||
+{
|
|
||||||
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
||||||
+ char *name;
|
|
||||||
+ struct timespec start;
|
|
||||||
+ uint64_t elapsed;
|
|
||||||
+
|
|
||||||
+ clock_gettime_mono(&start);
|
|
||||||
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, false);
|
|
||||||
+ elapsed_time(start, "pull");
|
|
||||||
+ _test_ndr_push_dns_string_list(mem_ctx, name, false);
|
|
||||||
+ elapsed = elapsed_time(start, "total");
|
|
||||||
+ assert_in_range(elapsed, 0, 200000);
|
|
||||||
+ talloc_free(mem_ctx);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void test_ndr_nbt_string_all_dots(void **state)
|
|
||||||
+{
|
|
||||||
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
|
||||||
+ char *name;
|
|
||||||
+ struct timespec start;
|
|
||||||
+ uint64_t elapsed;
|
|
||||||
+
|
|
||||||
+ clock_gettime_mono(&start);
|
|
||||||
+ name =_test_ndr_pull_dns_string_list(mem_ctx, 127, 1, true);
|
|
||||||
+ elapsed_time(start, "pull");
|
|
||||||
+ _test_ndr_push_dns_string_list(mem_ctx, name, true);
|
|
||||||
+ elapsed = elapsed_time(start, "total");
|
|
||||||
+ assert_in_range(elapsed, 0, 200000);
|
|
||||||
+ talloc_free(mem_ctx);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+int main(int argc, const char **argv)
|
|
||||||
+{
|
|
||||||
+ const struct CMUnitTest tests[] = {
|
|
||||||
+ cmocka_unit_test(test_ndr_nbt_string_half_dots),
|
|
||||||
+ cmocka_unit_test(test_ndr_dns_string_half_dots),
|
|
||||||
+ cmocka_unit_test(test_ndr_nbt_string_all_dots),
|
|
||||||
+ cmocka_unit_test(test_ndr_dns_string_all_dots),
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
|
|
||||||
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
|
||||||
+}
|
|
||||||
diff --git a/librpc/wscript_build b/librpc/wscript_build
|
|
||||||
index 70fe8c2f7fe..e3be298c725 100644
|
|
||||||
--- a/librpc/wscript_build
|
|
||||||
+++ b/librpc/wscript_build
|
|
||||||
@@ -656,3 +656,16 @@ bld.SAMBA_SUBSYSTEM('NDR_FSRVP_STATE',
|
|
||||||
source='gen_ndr/ndr_fsrvp_state.c',
|
|
||||||
public_deps='ndr'
|
|
||||||
)
|
|
||||||
+#
|
|
||||||
+# Cmocka tests
|
|
||||||
+#
|
|
||||||
+
|
|
||||||
+bld.SAMBA_BINARY('test_ndr_dns_nbt',
|
|
||||||
+ source='tests/test_ndr_dns_nbt.c',
|
|
||||||
+ deps='''
|
|
||||||
+ cmocka
|
|
||||||
+ ndr
|
|
||||||
+ ndr_nbt
|
|
||||||
+ NDR_DNS
|
|
||||||
+ ''',
|
|
||||||
+ install=False)
|
|
||||||
diff --git a/selftest/knownfail.d/ndr_dns_nbt b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..f30217c4033
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
@@ -0,0 +1,4 @@
|
|
||||||
+librpc.ndr.ndr_dns_nbt.test_ndr_dns_string_all_dots
|
|
||||||
+librpc.ndr.ndr_dns_nbt.test_ndr_dns_string_half_dots
|
|
||||||
+librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_all_dots
|
|
||||||
+librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_half_dots
|
|
||||||
diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py
|
|
||||||
index 6281b7e8f12..e8dbed71a18 100755
|
|
||||||
--- a/source4/selftest/tests.py
|
|
||||||
+++ b/source4/selftest/tests.py
|
|
||||||
@@ -1337,6 +1337,8 @@ plantestsuite("samba4.dcerpc.dnsserver.dnsutils", "none",
|
|
||||||
[os.path.join(bindir(), "test_rpc_dns_server_dnsutils")])
|
|
||||||
plantestsuite("libcli.drsuapi.repl_decrypt", "none",
|
|
||||||
[os.path.join(bindir(), "test_repl_decrypt")])
|
|
||||||
+plantestsuite("librpc.ndr.ndr_dns_nbt", "none",
|
|
||||||
+ [os.path.join(bindir(), "test_ndr_dns_nbt")])
|
|
||||||
|
|
||||||
# process restart and limit tests, these break the environment so need to run
|
|
||||||
# in their own specific environment
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,241 +0,0 @@
|
|||||||
From 37cacb8f41b9b2ea19a9c1bbfade4ea250dced46 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Sat, 25 Apr 2020 11:02:08 +1200
|
|
||||||
Subject: [PATCH 14/22] CVE-2020-10745: ndr_dns: move ndr_push_dns_string core
|
|
||||||
into sharable function
|
|
||||||
|
|
||||||
This is because ndr_nbt.c does almost exactly the same thing with
|
|
||||||
almost exactly the same code, and they both do it wrong. Soon they
|
|
||||||
will both be using the better version that this will become. Though in
|
|
||||||
this patch we just move the code, not fix it.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/ndr/ndr_dns.c | 79 +++-------------------------------
|
|
||||||
librpc/ndr/ndr_dns_utils.c | 88 ++++++++++++++++++++++++++++++++++++++
|
|
||||||
librpc/ndr/ndr_dns_utils.h | 5 +++
|
|
||||||
librpc/wscript_build | 2 +-
|
|
||||||
4 files changed, 99 insertions(+), 75 deletions(-)
|
|
||||||
create mode 100644 librpc/ndr/ndr_dns_utils.c
|
|
||||||
create mode 100644 librpc/ndr/ndr_dns_utils.h
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
|
|
||||||
index d37c8cc2ece..68a3c9de782 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns.c
|
|
||||||
@@ -33,6 +33,7 @@
|
|
||||||
#include "librpc/gen_ndr/ndr_dnsp.h"
|
|
||||||
#include "system/locale.h"
|
|
||||||
#include "lib/util/util_net.h"
|
|
||||||
+#include "ndr_dns_utils.h"
|
|
||||||
|
|
||||||
/* don't allow an unlimited number of name components */
|
|
||||||
#define MAX_COMPONENTS 128
|
|
||||||
@@ -159,80 +160,10 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
|
|
||||||
int ndr_flags,
|
|
||||||
const char *s)
|
|
||||||
{
|
|
||||||
- if (!(ndr_flags & NDR_SCALARS)) {
|
|
||||||
- return NDR_ERR_SUCCESS;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- while (s && *s) {
|
|
||||||
- enum ndr_err_code ndr_err;
|
|
||||||
- char *compname;
|
|
||||||
- size_t complen;
|
|
||||||
- uint32_t offset;
|
|
||||||
-
|
|
||||||
- if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
- /* see if we have pushed the remaining string already,
|
|
||||||
- * if so we use a label pointer to this string
|
|
||||||
- */
|
|
||||||
- ndr_err = ndr_token_retrieve_cmp_fn(&ndr->dns_string_list, s,
|
|
||||||
- &offset,
|
|
||||||
- (comparison_fn_t)strcmp,
|
|
||||||
- false);
|
|
||||||
- if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|
||||||
- uint8_t b[2];
|
|
||||||
-
|
|
||||||
- if (offset > 0x3FFF) {
|
|
||||||
- return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
- "offset for dns string " \
|
|
||||||
- "label pointer " \
|
|
||||||
- "%u[%08X] > 0x00003FFF",
|
|
||||||
- offset, offset);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- b[0] = 0xC0 | (offset>>8);
|
|
||||||
- b[1] = (offset & 0xFF);
|
|
||||||
-
|
|
||||||
- return ndr_push_bytes(ndr, b, 2);
|
|
||||||
- }
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- complen = strcspn(s, ".");
|
|
||||||
-
|
|
||||||
- /* we need to make sure the length fits into 6 bytes */
|
|
||||||
- if (complen > 0x3F) {
|
|
||||||
- return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
- "component length %u[%08X] > " \
|
|
||||||
- "0x0000003F",
|
|
||||||
- (unsigned)complen,
|
|
||||||
- (unsigned)complen);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- compname = talloc_asprintf(ndr, "%c%*.*s",
|
|
||||||
- (unsigned char)complen,
|
|
||||||
- (unsigned char)complen,
|
|
||||||
- (unsigned char)complen, s);
|
|
||||||
- NDR_ERR_HAVE_NO_MEMORY(compname);
|
|
||||||
-
|
|
||||||
- /* remember the current component + the rest of the string
|
|
||||||
- * so it can be reused later
|
|
||||||
- */
|
|
||||||
- if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
- NDR_CHECK(ndr_token_store(ndr, &ndr->dns_string_list, s,
|
|
||||||
- ndr->offset));
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* push just this component into the blob */
|
|
||||||
- NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
|
|
||||||
- complen+1));
|
|
||||||
- talloc_free(compname);
|
|
||||||
-
|
|
||||||
- s += complen;
|
|
||||||
- if (*s == '.') s++;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* if we reach the end of the string and have pushed the last component
|
|
||||||
- * without using a label pointer, we need to terminate the string
|
|
||||||
- */
|
|
||||||
- return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
|
|
||||||
+ return ndr_push_dns_string_list(ndr,
|
|
||||||
+ &ndr->dns_string_list,
|
|
||||||
+ ndr_flags,
|
|
||||||
+ s);
|
|
||||||
}
|
|
||||||
|
|
||||||
_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, int ndr_flags, struct dns_txt_record *r)
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..2d9b5f1bc1e
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
@@ -0,0 +1,88 @@
|
|
||||||
+#include "includes.h"
|
|
||||||
+#include "../librpc/ndr/libndr.h"
|
|
||||||
+#include "ndr_dns_utils.h"
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ push a dns/nbt string list to the wire
|
|
||||||
+*/
|
|
||||||
+enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
+ struct ndr_token_list *string_list,
|
|
||||||
+ int ndr_flags,
|
|
||||||
+ const char *s)
|
|
||||||
+{
|
|
||||||
+ if (!(ndr_flags & NDR_SCALARS)) {
|
|
||||||
+ return NDR_ERR_SUCCESS;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ while (s && *s) {
|
|
||||||
+ enum ndr_err_code ndr_err;
|
|
||||||
+ char *compname;
|
|
||||||
+ size_t complen;
|
|
||||||
+ uint32_t offset;
|
|
||||||
+
|
|
||||||
+ if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
+ /* see if we have pushed the remaining string already,
|
|
||||||
+ * if so we use a label pointer to this string
|
|
||||||
+ */
|
|
||||||
+ ndr_err = ndr_token_retrieve_cmp_fn(string_list, s,
|
|
||||||
+ &offset,
|
|
||||||
+ (comparison_fn_t)strcmp,
|
|
||||||
+ false);
|
|
||||||
+ if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|
||||||
+ uint8_t b[2];
|
|
||||||
+
|
|
||||||
+ if (offset > 0x3FFF) {
|
|
||||||
+ return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
+ "offset for dns string " \
|
|
||||||
+ "label pointer " \
|
|
||||||
+ "%u[%08X] > 0x00003FFF",
|
|
||||||
+ offset, offset);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ b[0] = 0xC0 | (offset>>8);
|
|
||||||
+ b[1] = (offset & 0xFF);
|
|
||||||
+
|
|
||||||
+ return ndr_push_bytes(ndr, b, 2);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ complen = strcspn(s, ".");
|
|
||||||
+
|
|
||||||
+ /* we need to make sure the length fits into 6 bytes */
|
|
||||||
+ if (complen > 0x3F) {
|
|
||||||
+ return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
+ "component length %u[%08X] > " \
|
|
||||||
+ "0x0000003F",
|
|
||||||
+ (unsigned)complen,
|
|
||||||
+ (unsigned)complen);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ compname = talloc_asprintf(ndr, "%c%*.*s",
|
|
||||||
+ (unsigned char)complen,
|
|
||||||
+ (unsigned char)complen,
|
|
||||||
+ (unsigned char)complen, s);
|
|
||||||
+ NDR_ERR_HAVE_NO_MEMORY(compname);
|
|
||||||
+
|
|
||||||
+ /* remember the current component + the rest of the string
|
|
||||||
+ * so it can be reused later
|
|
||||||
+ */
|
|
||||||
+ if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
+ NDR_CHECK(ndr_token_store(ndr, string_list, s,
|
|
||||||
+ ndr->offset));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* push just this component into the blob */
|
|
||||||
+ NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname,
|
|
||||||
+ complen+1));
|
|
||||||
+ talloc_free(compname);
|
|
||||||
+
|
|
||||||
+ s += complen;
|
|
||||||
+ if (*s == '.') s++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* if we reach the end of the string and have pushed the last component
|
|
||||||
+ * without using a label pointer, we need to terminate the string
|
|
||||||
+ */
|
|
||||||
+ return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
|
|
||||||
+}
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.h b/librpc/ndr/ndr_dns_utils.h
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..823e3201112
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.h
|
|
||||||
@@ -0,0 +1,5 @@
|
|
||||||
+
|
|
||||||
+enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
+ struct ndr_token_list *string_list,
|
|
||||||
+ int ndr_flags,
|
|
||||||
+ const char *s);
|
|
||||||
diff --git a/librpc/wscript_build b/librpc/wscript_build
|
|
||||||
index e3be298c725..c165500644b 100644
|
|
||||||
--- a/librpc/wscript_build
|
|
||||||
+++ b/librpc/wscript_build
|
|
||||||
@@ -31,7 +31,7 @@ bld.SAMBA_SUBSYSTEM('NDR_DNSSERVER',
|
|
||||||
)
|
|
||||||
|
|
||||||
bld.SAMBA_SUBSYSTEM('NDR_DNS',
|
|
||||||
- source='gen_ndr/ndr_dns.c ndr/ndr_dns.c',
|
|
||||||
+ source='gen_ndr/ndr_dns.c ndr/ndr_dns.c ndr/ndr_dns_utils.c',
|
|
||||||
public_deps='ndr NDR_DNSP'
|
|
||||||
)
|
|
||||||
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
From b687813ac362ff71085d192a4b7821235345feea Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Sat, 25 Apr 2020 11:03:30 +1200
|
|
||||||
Subject: [PATCH 15/22] CVE-2020-10745: ndr/dns_utils: correct a comment
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/ndr/ndr_dns_utils.c | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
index 2d9b5f1bc1e..2ce300863bc 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns_utils.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
@@ -49,7 +49,7 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
|
|
||||||
complen = strcspn(s, ".");
|
|
||||||
|
|
||||||
- /* we need to make sure the length fits into 6 bytes */
|
|
||||||
+ /* the length must fit into 6 bits (i.e. <= 63) */
|
|
||||||
if (complen > 0x3F) {
|
|
||||||
return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
"component length %u[%08X] > " \
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,54 +0,0 @@
|
|||||||
From 507503f80e8913450364dcd8ab080f3211b6f855 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Sat, 25 Apr 2020 11:10:18 +1200
|
|
||||||
Subject: [PATCH 16/22] CVE-2020-10745: ndr_dns: do not allow consecutive dots
|
|
||||||
|
|
||||||
The empty subdomain component is reserved for the root domain, which we
|
|
||||||
should only (and always) see at the end of the list. That is, we expect
|
|
||||||
"example.com.", but never "example..com".
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/ndr/ndr_dns_utils.c | 6 ++++++
|
|
||||||
selftest/knownfail.d/dns_packet | 1 -
|
|
||||||
selftest/knownfail.d/ndr_dns_nbt | 1 -
|
|
||||||
3 files changed, 6 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
index 2ce300863bc..6931dac422d 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns_utils.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
@@ -58,6 +58,12 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
(unsigned)complen);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (complen == 0 && s[complen] == '.') {
|
|
||||||
+ return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
+ "component length is 0 "
|
|
||||||
+ "(consecutive dots)");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
compname = talloc_asprintf(ndr, "%c%*.*s",
|
|
||||||
(unsigned char)complen,
|
|
||||||
(unsigned char)complen,
|
|
||||||
diff --git a/selftest/knownfail.d/dns_packet b/selftest/knownfail.d/dns_packet
|
|
||||||
index 6e2e5a699de..0662266f689 100644
|
|
||||||
--- a/selftest/knownfail.d/dns_packet
|
|
||||||
+++ b/selftest/knownfail.d/dns_packet
|
|
||||||
@@ -1,2 +1 @@
|
|
||||||
-samba.tests.dns_packet.samba.tests.dns_packet.TestDnsPackets.test_127_very_dotty_components
|
|
||||||
samba.tests.dns_packet.samba.tests.dns_packet.TestNbtPackets.test_127_very_dotty_components
|
|
||||||
diff --git a/selftest/knownfail.d/ndr_dns_nbt b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
index f30217c4033..e11c121b7a7 100644
|
|
||||||
--- a/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
+++ b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
@@ -1,4 +1,3 @@
|
|
||||||
-librpc.ndr.ndr_dns_nbt.test_ndr_dns_string_all_dots
|
|
||||||
librpc.ndr.ndr_dns_nbt.test_ndr_dns_string_half_dots
|
|
||||||
librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_all_dots
|
|
||||||
librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_half_dots
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,55 +0,0 @@
|
|||||||
From 83b00656ea0e8cfdce8a9c1cef71e41477e8e6f0 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Fri, 15 May 2020 00:06:08 +1200
|
|
||||||
Subject: [PATCH 17/22] CVE-2020-10745: dns_util/push: forbid names longer than
|
|
||||||
255 bytes
|
|
||||||
|
|
||||||
As per RFC 1035.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/ndr/ndr_dns_utils.c | 10 +++++++++-
|
|
||||||
selftest/knownfail.d/ndr_dns_nbt | 1 -
|
|
||||||
2 files changed, 9 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
index 6931dac422d..b7f11dbab4e 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns_utils.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
@@ -11,6 +11,8 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
int ndr_flags,
|
|
||||||
const char *s)
|
|
||||||
{
|
|
||||||
+ const char *start = s;
|
|
||||||
+
|
|
||||||
if (!(ndr_flags & NDR_SCALARS)) {
|
|
||||||
return NDR_ERR_SUCCESS;
|
|
||||||
}
|
|
||||||
@@ -84,7 +86,13 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
talloc_free(compname);
|
|
||||||
|
|
||||||
s += complen;
|
|
||||||
- if (*s == '.') s++;
|
|
||||||
+ if (*s == '.') {
|
|
||||||
+ s++;
|
|
||||||
+ }
|
|
||||||
+ if (s - start > 255) {
|
|
||||||
+ return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
+ "name > 255 character long");
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if we reach the end of the string and have pushed the last component
|
|
||||||
diff --git a/selftest/knownfail.d/ndr_dns_nbt b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
index e11c121b7a7..603395c8c50 100644
|
|
||||||
--- a/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
+++ b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
@@ -1,3 +1,2 @@
|
|
||||||
-librpc.ndr.ndr_dns_nbt.test_ndr_dns_string_half_dots
|
|
||||||
librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_all_dots
|
|
||||||
librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_half_dots
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,267 +0,0 @@
|
|||||||
From 23e9eb71052e02aecf726609db0256c0d93e0b57 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
Date: Fri, 15 May 2020 10:52:45 +1200
|
|
||||||
Subject: [PATCH 18/22] CVE-2020-10745: ndr/dns-utils: prepare for NBT
|
|
||||||
compatibility
|
|
||||||
|
|
||||||
NBT has a funny thing where it sometimes needs to send a trailing dot as
|
|
||||||
part of the last component, because the string representation is a user
|
|
||||||
name. In DNS, "example.com", and "example.com." are the same, both
|
|
||||||
having three components ("example", "com", ""); in NBT, we want to treat
|
|
||||||
them differently, with the second form having the three components
|
|
||||||
("example", "com.", "").
|
|
||||||
|
|
||||||
This retains the logic of e6e2ec0001fe3c010445e26cc0efddbc1f73416b.
|
|
||||||
|
|
||||||
Also DNS compression cannot be turned off for NBT.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14378
|
|
||||||
|
|
||||||
Signed-off-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
librpc/ndr/ndr_dns.c | 3 +-
|
|
||||||
librpc/ndr/ndr_dns_utils.c | 42 ++++++++++++++++---
|
|
||||||
librpc/ndr/ndr_dns_utils.h | 3 +-
|
|
||||||
librpc/ndr/ndr_nbt.c | 72 ++++----------------------------
|
|
||||||
librpc/wscript_build | 3 +-
|
|
||||||
selftest/knownfail.d/dns_packet | 1 -
|
|
||||||
selftest/knownfail.d/ndr_dns_nbt | 2 -
|
|
||||||
7 files changed, 49 insertions(+), 77 deletions(-)
|
|
||||||
delete mode 100644 selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns.c b/librpc/ndr/ndr_dns.c
|
|
||||||
index 68a3c9de782..966e0b59786 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns.c
|
|
||||||
@@ -163,7 +163,8 @@ _PUBLIC_ enum ndr_err_code ndr_push_dns_string(struct ndr_push *ndr,
|
|
||||||
return ndr_push_dns_string_list(ndr,
|
|
||||||
&ndr->dns_string_list,
|
|
||||||
ndr_flags,
|
|
||||||
- s);
|
|
||||||
+ s,
|
|
||||||
+ false);
|
|
||||||
}
|
|
||||||
|
|
||||||
_PUBLIC_ enum ndr_err_code ndr_pull_dns_txt_record(struct ndr_pull *ndr, int ndr_flags, struct dns_txt_record *r)
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.c b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
index b7f11dbab4e..325d9c68bea 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns_utils.c
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.c
|
|
||||||
@@ -9,9 +9,32 @@
|
|
||||||
enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
struct ndr_token_list *string_list,
|
|
||||||
int ndr_flags,
|
|
||||||
- const char *s)
|
|
||||||
+ const char *s,
|
|
||||||
+ bool is_nbt)
|
|
||||||
{
|
|
||||||
const char *start = s;
|
|
||||||
+ bool use_compression;
|
|
||||||
+ size_t max_length;
|
|
||||||
+ if (is_nbt) {
|
|
||||||
+ use_compression = true;
|
|
||||||
+ /*
|
|
||||||
+ * Max length is longer in NBT/Wins, because Windows counts
|
|
||||||
+ * the semi-decompressed size of the netbios name (16 bytes)
|
|
||||||
+ * rather than the wire size of 32, which is what you'd expect
|
|
||||||
+ * if it followed RFC1002 (it uses the short form in
|
|
||||||
+ * [MS-WINSRA]). In other words the maximum size of the
|
|
||||||
+ * "scope" is 237, not 221.
|
|
||||||
+ *
|
|
||||||
+ * We make the size limit slightly larger than 255 + 16,
|
|
||||||
+ * because the 237 scope limit is already enforced in the
|
|
||||||
+ * winsserver code with a specific return value; bailing out
|
|
||||||
+ * here would muck with that.
|
|
||||||
+ */
|
|
||||||
+ max_length = 274;
|
|
||||||
+ } else {
|
|
||||||
+ use_compression = !(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION);
|
|
||||||
+ max_length = 255;
|
|
||||||
+ }
|
|
||||||
|
|
||||||
if (!(ndr_flags & NDR_SCALARS)) {
|
|
||||||
return NDR_ERR_SUCCESS;
|
|
||||||
@@ -23,7 +46,7 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
size_t complen;
|
|
||||||
uint32_t offset;
|
|
||||||
|
|
||||||
- if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
+ if (use_compression) {
|
|
||||||
/* see if we have pushed the remaining string already,
|
|
||||||
* if so we use a label pointer to this string
|
|
||||||
*/
|
|
||||||
@@ -66,6 +89,14 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
"(consecutive dots)");
|
|
||||||
}
|
|
||||||
|
|
||||||
+ if (is_nbt && s[complen] == '.' && s[complen + 1] == '\0') {
|
|
||||||
+ /* nbt names are sometimes usernames, and we need to
|
|
||||||
+ * keep a trailing dot to ensure it is byte-identical,
|
|
||||||
+ * (not just semantically identical given DNS
|
|
||||||
+ * semantics). */
|
|
||||||
+ complen++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
compname = talloc_asprintf(ndr, "%c%*.*s",
|
|
||||||
(unsigned char)complen,
|
|
||||||
(unsigned char)complen,
|
|
||||||
@@ -75,7 +106,7 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
/* remember the current component + the rest of the string
|
|
||||||
* so it can be reused later
|
|
||||||
*/
|
|
||||||
- if (!(ndr->flags & LIBNDR_FLAG_NO_COMPRESSION)) {
|
|
||||||
+ if (use_compression) {
|
|
||||||
NDR_CHECK(ndr_token_store(ndr, string_list, s,
|
|
||||||
ndr->offset));
|
|
||||||
}
|
|
||||||
@@ -89,9 +120,10 @@ enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
if (*s == '.') {
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
- if (s - start > 255) {
|
|
||||||
+ if (s - start > max_length) {
|
|
||||||
return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
- "name > 255 character long");
|
|
||||||
+ "name > %zu character long",
|
|
||||||
+ max_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/librpc/ndr/ndr_dns_utils.h b/librpc/ndr/ndr_dns_utils.h
|
|
||||||
index 823e3201112..71a65433bbb 100644
|
|
||||||
--- a/librpc/ndr/ndr_dns_utils.h
|
|
||||||
+++ b/librpc/ndr/ndr_dns_utils.h
|
|
||||||
@@ -2,4 +2,5 @@
|
|
||||||
enum ndr_err_code ndr_push_dns_string_list(struct ndr_push *ndr,
|
|
||||||
struct ndr_token_list *string_list,
|
|
||||||
int ndr_flags,
|
|
||||||
- const char *s);
|
|
||||||
+ const char *s,
|
|
||||||
+ bool is_nbt);
|
|
||||||
diff --git a/librpc/ndr/ndr_nbt.c b/librpc/ndr/ndr_nbt.c
|
|
||||||
index 838f947a168..e8dd7549a53 100644
|
|
||||||
--- a/librpc/ndr/ndr_nbt.c
|
|
||||||
+++ b/librpc/ndr/ndr_nbt.c
|
|
||||||
@@ -25,6 +25,8 @@
|
|
||||||
#include "includes.h"
|
|
||||||
#include "../libcli/nbt/libnbt.h"
|
|
||||||
#include "../libcli/netlogon/netlogon.h"
|
|
||||||
+#include "ndr_dns_utils.h"
|
|
||||||
+
|
|
||||||
|
|
||||||
/* don't allow an unlimited number of name components */
|
|
||||||
#define MAX_COMPONENTS 128
|
|
||||||
@@ -141,71 +143,11 @@ _PUBLIC_ enum ndr_err_code ndr_pull_nbt_string(struct ndr_pull *ndr, int ndr_fla
|
|
||||||
*/
|
|
||||||
_PUBLIC_ enum ndr_err_code ndr_push_nbt_string(struct ndr_push *ndr, int ndr_flags, const char *s)
|
|
||||||
{
|
|
||||||
- if (!(ndr_flags & NDR_SCALARS)) {
|
|
||||||
- return NDR_ERR_SUCCESS;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- while (s && *s) {
|
|
||||||
- enum ndr_err_code ndr_err;
|
|
||||||
- char *compname;
|
|
||||||
- size_t complen;
|
|
||||||
- uint32_t offset;
|
|
||||||
-
|
|
||||||
- /* see if we have pushed the remaining string already,
|
|
||||||
- * if so we use a label pointer to this string
|
|
||||||
- */
|
|
||||||
- ndr_err = ndr_token_retrieve_cmp_fn(&ndr->nbt_string_list, s, &offset, (comparison_fn_t)strcmp, false);
|
|
||||||
- if (NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
|
||||||
- uint8_t b[2];
|
|
||||||
-
|
|
||||||
- if (offset > 0x3FFF) {
|
|
||||||
- return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
- "offset for nbt string label pointer %u[%08X] > 0x00003FFF",
|
|
||||||
- offset, offset);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- b[0] = 0xC0 | (offset>>8);
|
|
||||||
- b[1] = (offset & 0xFF);
|
|
||||||
-
|
|
||||||
- return ndr_push_bytes(ndr, b, 2);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- complen = strcspn(s, ".");
|
|
||||||
-
|
|
||||||
- /* we need to make sure the length fits into 6 bytes */
|
|
||||||
- if (complen > 0x3F) {
|
|
||||||
- return ndr_push_error(ndr, NDR_ERR_STRING,
|
|
||||||
- "component length %u[%08X] > 0x0000003F",
|
|
||||||
- (unsigned)complen, (unsigned)complen);
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- if (s[complen] == '.' && s[complen+1] == '\0') {
|
|
||||||
- complen++;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- compname = talloc_asprintf(ndr, "%c%*.*s",
|
|
||||||
- (unsigned char)complen,
|
|
||||||
- (unsigned char)complen,
|
|
||||||
- (unsigned char)complen, s);
|
|
||||||
- NDR_ERR_HAVE_NO_MEMORY(compname);
|
|
||||||
-
|
|
||||||
- /* remember the current componemt + the rest of the string
|
|
||||||
- * so it can be reused later
|
|
||||||
- */
|
|
||||||
- NDR_CHECK(ndr_token_store(ndr, &ndr->nbt_string_list, s, ndr->offset));
|
|
||||||
-
|
|
||||||
- /* push just this component into the blob */
|
|
||||||
- NDR_CHECK(ndr_push_bytes(ndr, (const uint8_t *)compname, complen+1));
|
|
||||||
- talloc_free(compname);
|
|
||||||
-
|
|
||||||
- s += complen;
|
|
||||||
- if (*s == '.') s++;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- /* if we reach the end of the string and have pushed the last component
|
|
||||||
- * without using a label pointer, we need to terminate the string
|
|
||||||
- */
|
|
||||||
- return ndr_push_bytes(ndr, (const uint8_t *)"", 1);
|
|
||||||
+ return ndr_push_dns_string_list(ndr,
|
|
||||||
+ &ndr->dns_string_list,
|
|
||||||
+ ndr_flags,
|
|
||||||
+ s,
|
|
||||||
+ true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/librpc/wscript_build b/librpc/wscript_build
|
|
||||||
index c165500644b..4917928a9c4 100644
|
|
||||||
--- a/librpc/wscript_build
|
|
||||||
+++ b/librpc/wscript_build
|
|
||||||
@@ -401,7 +401,7 @@ bld.SAMBA_SUBSYSTEM('NDR_SCHANNEL',
|
|
||||||
|
|
||||||
bld.SAMBA_LIBRARY('ndr_nbt',
|
|
||||||
source='gen_ndr/ndr_nbt.c ndr/ndr_nbt.c',
|
|
||||||
- public_deps='ndr NDR_NBT_BUF NDR_SECURITY',
|
|
||||||
+ public_deps='ndr NDR_NBT_BUF NDR_SECURITY NDR_DNS',
|
|
||||||
public_headers='gen_ndr/nbt.h gen_ndr/ndr_nbt.h ndr/ndr_nbt.h',
|
|
||||||
header_path=[ ('gen_ndr*', 'gen_ndr'), ('ndr*', 'ndr')],
|
|
||||||
pc_files='ndr_nbt.pc',
|
|
||||||
@@ -666,6 +666,5 @@ bld.SAMBA_BINARY('test_ndr_dns_nbt',
|
|
||||||
cmocka
|
|
||||||
ndr
|
|
||||||
ndr_nbt
|
|
||||||
- NDR_DNS
|
|
||||||
''',
|
|
||||||
install=False)
|
|
||||||
diff --git a/selftest/knownfail.d/dns_packet b/selftest/knownfail.d/dns_packet
|
|
||||||
index 0662266f689..e69de29bb2d 100644
|
|
||||||
--- a/selftest/knownfail.d/dns_packet
|
|
||||||
+++ b/selftest/knownfail.d/dns_packet
|
|
||||||
@@ -1 +0,0 @@
|
|
||||||
-samba.tests.dns_packet.samba.tests.dns_packet.TestNbtPackets.test_127_very_dotty_components
|
|
||||||
diff --git a/selftest/knownfail.d/ndr_dns_nbt b/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
deleted file mode 100644
|
|
||||||
index 603395c8c50..00000000000
|
|
||||||
--- a/selftest/knownfail.d/ndr_dns_nbt
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1,2 +0,0 @@
|
|
||||||
-librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_all_dots
|
|
||||||
-librpc.ndr.ndr_dns_nbt.test_ndr_nbt_string_half_dots
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
From 4def2dc554754033174c60f5860f51b46d8502c1 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Fri, 5 Jun 2020 22:14:48 +1200
|
|
||||||
Subject: [PATCH 21/22] CVE-2020-10760 dsdb: Ensure a proper talloc tree for
|
|
||||||
saved controls
|
|
||||||
|
|
||||||
Otherwise a paged search on the GC port will fail as the ->data was
|
|
||||||
not kept around for the second page of searches.
|
|
||||||
|
|
||||||
An example command to produce this is
|
|
||||||
bin/ldbsearch --paged -H ldap://$SERVER:3268 -U$USERNAME%$PASSWORD
|
|
||||||
|
|
||||||
This shows up later in the partition module as:
|
|
||||||
|
|
||||||
ERROR: AddressSanitizer: heap-use-after-free on address 0x60b00151ef20 at pc 0x7fec3f801aac bp 0x7ffe8472c270 sp 0x7ffe8472c260
|
|
||||||
READ of size 4 at 0x60b00151ef20 thread T0 (ldap(0))
|
|
||||||
#0 0x7fec3f801aab in talloc_chunk_from_ptr ../../lib/talloc/talloc.c:526
|
|
||||||
#1 0x7fec3f801aab in __talloc_get_name ../../lib/talloc/talloc.c:1559
|
|
||||||
#2 0x7fec3f801aab in talloc_check_name ../../lib/talloc/talloc.c:1582
|
|
||||||
#3 0x7fec1b86b2e1 in partition_search ../../source4/dsdb/samdb/ldb_modules/partition.c:780
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
smb_panic_default: PANIC (pid 13287): Bad talloc magic value - unknown value
|
|
||||||
(from source4/dsdb/samdb/ldb_modules/partition.c:780)
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14402
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
source4/dsdb/samdb/ldb_modules/paged_results.c | 8 ++++++++
|
|
||||||
source4/dsdb/samdb/ldb_modules/vlv_pagination.c | 7 +++++++
|
|
||||||
2 files changed, 15 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/paged_results.c b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
index 735883e8802..3eea3236e7d 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/paged_results.c
|
|
||||||
@@ -523,6 +523,14 @@ paged_results_copy_down_controls(TALLOC_CTX *mem_ctx,
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
new_controls[j] = talloc_steal(new_controls, control);
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Sadly the caller is not obliged to make this a
|
|
||||||
+ * proper talloc tree, so we do so here.
|
|
||||||
+ */
|
|
||||||
+ if (control->data) {
|
|
||||||
+ talloc_steal(control, control->data);
|
|
||||||
+ }
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
new_controls[j] = NULL;
|
|
||||||
diff --git a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
index b103bda5f52..d6d6039e849 100644
|
|
||||||
--- a/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
+++ b/source4/dsdb/samdb/ldb_modules/vlv_pagination.c
|
|
||||||
@@ -746,6 +746,13 @@ vlv_copy_down_controls(TALLOC_CTX *mem_ctx, struct ldb_control **controls)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
new_controls[j] = talloc_steal(new_controls, control);
|
|
||||||
+ /*
|
|
||||||
+ * Sadly the caller is not obliged to make this a
|
|
||||||
+ * proper talloc tree, so we do so here.
|
|
||||||
+ */
|
|
||||||
+ if (control->data) {
|
|
||||||
+ talloc_steal(control, control->data);
|
|
||||||
+ }
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
new_controls[j] = NULL;
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,247 +0,0 @@
|
|||||||
From df599b6b79010759279eb7f52486f1d0a59d06d3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Mon, 8 Jun 2020 16:32:14 +1200
|
|
||||||
Subject: [PATCH 22/22] CVE-2020-10760 dsdb: Add tests for paged_results and
|
|
||||||
VLV over the Global Catalog port
|
|
||||||
|
|
||||||
This should avoid a regression.
|
|
||||||
|
|
||||||
(backported from master patch)
|
|
||||||
[abartlet@samba.org: sort=True parameter on test_paged_delete_during_search
|
|
||||||
is not in 4.11]
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
selftest/knownfail.d/vlv | 2 +-
|
|
||||||
source4/dsdb/tests/python/vlv.py | 171 +++++++++++++++++++------------
|
|
||||||
2 files changed, 107 insertions(+), 66 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/selftest/knownfail.d/vlv b/selftest/knownfail.d/vlv
|
|
||||||
index f187a2ed55e..7ae02baf17b 100644
|
|
||||||
--- a/selftest/knownfail.d/vlv
|
|
||||||
+++ b/selftest/knownfail.d/vlv
|
|
||||||
@@ -1,2 +1,2 @@
|
|
||||||
samba4.ldap.vlv.python.*__main__.VLVTests.test_vlv_change_search_expr
|
|
||||||
-samba4.ldap.vlv.python.*__main__.PagedResultsTests.test_paged_cant_change_controls_data
|
|
||||||
+samba4.ldap.vlv.python.*__main__.PagedResultsTestsRW.test_paged_cant_change_controls_data
|
|
||||||
diff --git a/source4/dsdb/tests/python/vlv.py b/source4/dsdb/tests/python/vlv.py
|
|
||||||
index f3c603e3a39..ba03b425a5b 100644
|
|
||||||
--- a/source4/dsdb/tests/python/vlv.py
|
|
||||||
+++ b/source4/dsdb/tests/python/vlv.py
|
|
||||||
@@ -152,7 +152,7 @@ class TestsWithUserOU(samba.tests.TestCase):
|
|
||||||
super(TestsWithUserOU, self).setUp()
|
|
||||||
self.ldb = SamDB(host, credentials=creds,
|
|
||||||
session_info=system_session(lp), lp=lp)
|
|
||||||
-
|
|
||||||
+ self.ldb_ro = self.ldb
|
|
||||||
self.base_dn = self.ldb.domain_dn()
|
|
||||||
self.tree_dn = "ou=vlvtesttree,%s" % self.base_dn
|
|
||||||
self.ou = "ou=vlvou,%s" % self.tree_dn
|
|
||||||
@@ -199,8 +199,60 @@ class TestsWithUserOU(samba.tests.TestCase):
|
|
||||||
self.ldb.delete(self.tree_dn, ['tree_delete:1'])
|
|
||||||
|
|
||||||
|
|
||||||
-class VLVTests(TestsWithUserOU):
|
|
||||||
+class VLVTestsBase(TestsWithUserOU):
|
|
||||||
+
|
|
||||||
+ # Run a vlv search and return important fields of the response control
|
|
||||||
+ def vlv_search(self, attr, expr, cookie="", after_count=0, offset=1):
|
|
||||||
+ sort_ctrl = "server_sort:1:0:%s" % attr
|
|
||||||
+ ctrl = "vlv:1:0:%d:%d:0" % (after_count, offset)
|
|
||||||
+ if cookie:
|
|
||||||
+ ctrl += ":" + cookie
|
|
||||||
+
|
|
||||||
+ res = self.ldb_ro.search(self.ou,
|
|
||||||
+ expression=expr,
|
|
||||||
+ scope=ldb.SCOPE_ONELEVEL,
|
|
||||||
+ attrs=[attr],
|
|
||||||
+ controls=[ctrl, sort_ctrl])
|
|
||||||
+ results = [str(x[attr][0]) for x in res]
|
|
||||||
+
|
|
||||||
+ ctrls = [str(c) for c in res.controls if
|
|
||||||
+ str(c).startswith('vlv')]
|
|
||||||
+ self.assertEqual(len(ctrls), 1)
|
|
||||||
+
|
|
||||||
+ spl = ctrls[0].rsplit(':')
|
|
||||||
+ cookie = ""
|
|
||||||
+ if len(spl) == 6:
|
|
||||||
+ cookie = spl[-1]
|
|
||||||
+
|
|
||||||
+ return results, cookie
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class VLVTestsRO(VLVTestsBase):
|
|
||||||
+ def test_vlv_simple_double_run(self):
|
|
||||||
+ """Do the simplest possible VLV query to confirm if VLV
|
|
||||||
+ works at all. Useful for showing VLV as a whole works
|
|
||||||
+ on Global Catalog (for example)"""
|
|
||||||
+ attr = 'roomNumber'
|
|
||||||
+ expr = "(objectclass=user)"
|
|
||||||
|
|
||||||
+ # Start new search
|
|
||||||
+ full_results, cookie = self.vlv_search(attr, expr,
|
|
||||||
+ after_count=len(self.users))
|
|
||||||
+
|
|
||||||
+ results, cookie = self.vlv_search(attr, expr, cookie=cookie,
|
|
||||||
+ after_count=len(self.users))
|
|
||||||
+ expected_results = full_results
|
|
||||||
+ self.assertEqual(results, expected_results)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class VLVTestsGC(VLVTestsRO):
|
|
||||||
+ def setUp(self):
|
|
||||||
+ super(VLVTestsRO, self).setUp()
|
|
||||||
+ self.ldb_ro = SamDB(host + ":3268", credentials=creds,
|
|
||||||
+ session_info=system_session(lp), lp=lp)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class VLVTests(VLVTestsBase):
|
|
||||||
def get_full_list(self, attr, include_cn=False):
|
|
||||||
"""Fetch the whole list sorted on the attribute, using the VLV.
|
|
||||||
This way you get a VLV cookie."""
|
|
||||||
@@ -1081,31 +1133,6 @@ class VLVTests(TestsWithUserOU):
|
|
||||||
controls=[sort_control,
|
|
||||||
"vlv:0:1:1:1:0:%s" % vlv_cookies[-1]])
|
|
||||||
|
|
||||||
- # Run a vlv search and return important fields of the response control
|
|
||||||
- def vlv_search(self, attr, expr, cookie="", after_count=0, offset=1):
|
|
||||||
- sort_ctrl = "server_sort:1:0:%s" % attr
|
|
||||||
- ctrl = "vlv:1:0:%d:%d:0" % (after_count, offset)
|
|
||||||
- if cookie:
|
|
||||||
- ctrl += ":" + cookie
|
|
||||||
-
|
|
||||||
- res = self.ldb.search(self.ou,
|
|
||||||
- expression=expr,
|
|
||||||
- scope=ldb.SCOPE_ONELEVEL,
|
|
||||||
- attrs=[attr],
|
|
||||||
- controls=[ctrl, sort_ctrl])
|
|
||||||
- results = [str(x[attr][0]) for x in res]
|
|
||||||
-
|
|
||||||
- ctrls = [str(c) for c in res.controls if
|
|
||||||
- str(c).startswith('vlv')]
|
|
||||||
- self.assertEqual(len(ctrls), 1)
|
|
||||||
-
|
|
||||||
- spl = ctrls[0].rsplit(':')
|
|
||||||
- cookie = ""
|
|
||||||
- if len(spl) == 6:
|
|
||||||
- cookie = spl[-1]
|
|
||||||
-
|
|
||||||
- return results, cookie
|
|
||||||
-
|
|
||||||
def test_vlv_modify_during_view(self):
|
|
||||||
attr = 'roomNumber'
|
|
||||||
expr = "(objectclass=user)"
|
|
||||||
@@ -1218,11 +1245,11 @@ class PagedResultsTests(TestsWithUserOU):
|
|
||||||
if subtree:
|
|
||||||
scope = ldb.SCOPE_SUBTREE
|
|
||||||
|
|
||||||
- res = self.ldb.search(ou,
|
|
||||||
- expression=expr,
|
|
||||||
- scope=scope,
|
|
||||||
- controls=controls,
|
|
||||||
- **kwargs)
|
|
||||||
+ res = self.ldb_ro.search(ou,
|
|
||||||
+ expression=expr,
|
|
||||||
+ scope=scope,
|
|
||||||
+ controls=controls,
|
|
||||||
+ **kwargs)
|
|
||||||
results = [str(r['cn'][0]) for r in res]
|
|
||||||
|
|
||||||
ctrls = [str(c) for c in res.controls if
|
|
||||||
@@ -1235,6 +1262,53 @@ class PagedResultsTests(TestsWithUserOU):
|
|
||||||
cookie = spl[-1]
|
|
||||||
return results, cookie
|
|
||||||
|
|
||||||
+
|
|
||||||
+class PagedResultsTestsRO(PagedResultsTests):
|
|
||||||
+
|
|
||||||
+ def test_paged_search_lockstep(self):
|
|
||||||
+ expr = "(objectClass=*)"
|
|
||||||
+ ps = 3
|
|
||||||
+
|
|
||||||
+ all_results, _ = self.paged_search(expr, page_size=len(self.users)+1)
|
|
||||||
+
|
|
||||||
+ # Run two different but overlapping paged searches simultaneously.
|
|
||||||
+ set_1_index = int((len(all_results))//3)
|
|
||||||
+ set_2_index = int((2*len(all_results))//3)
|
|
||||||
+ set_1 = all_results[set_1_index:]
|
|
||||||
+ set_2 = all_results[:set_2_index+1]
|
|
||||||
+ set_1_expr = "(cn>=%s)" % (all_results[set_1_index])
|
|
||||||
+ set_2_expr = "(cn<=%s)" % (all_results[set_2_index])
|
|
||||||
+
|
|
||||||
+ results, cookie1 = self.paged_search(set_1_expr, page_size=ps)
|
|
||||||
+ self.assertEqual(results, set_1[:ps])
|
|
||||||
+ results, cookie2 = self.paged_search(set_2_expr, page_size=ps)
|
|
||||||
+ self.assertEqual(results, set_2[:ps])
|
|
||||||
+
|
|
||||||
+ results, cookie1 = self.paged_search(set_1_expr, cookie=cookie1,
|
|
||||||
+ page_size=ps)
|
|
||||||
+ self.assertEqual(results, set_1[ps:ps*2])
|
|
||||||
+ results, cookie2 = self.paged_search(set_2_expr, cookie=cookie2,
|
|
||||||
+ page_size=ps)
|
|
||||||
+ self.assertEqual(results, set_2[ps:ps*2])
|
|
||||||
+
|
|
||||||
+ results, _ = self.paged_search(set_1_expr, cookie=cookie1,
|
|
||||||
+ page_size=len(self.users))
|
|
||||||
+ self.assertEqual(results, set_1[ps*2:])
|
|
||||||
+ results, _ = self.paged_search(set_2_expr, cookie=cookie2,
|
|
||||||
+ page_size=len(self.users))
|
|
||||||
+ self.assertEqual(results, set_2[ps*2:])
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class PagedResultsTestsGC(PagedResultsTestsRO):
|
|
||||||
+
|
|
||||||
+ def setUp(self):
|
|
||||||
+ super(PagedResultsTestsRO, self).setUp()
|
|
||||||
+ self.ldb_ro = SamDB(host + ":3268", credentials=creds,
|
|
||||||
+ session_info=system_session(lp), lp=lp)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class PagedResultsTestsRW(PagedResultsTests):
|
|
||||||
+
|
|
||||||
def test_paged_delete_during_search(self):
|
|
||||||
expr = "(objectClass=*)"
|
|
||||||
|
|
||||||
@@ -1611,39 +1685,6 @@ class PagedResultsTests(TestsWithUserOU):
|
|
||||||
cookie, attrs=changed_attrs,
|
|
||||||
extra_ctrls=[])
|
|
||||||
|
|
||||||
- def test_paged_search_lockstep(self):
|
|
||||||
- expr = "(objectClass=*)"
|
|
||||||
- ps = 3
|
|
||||||
-
|
|
||||||
- all_results, _ = self.paged_search(expr, page_size=len(self.users)+1)
|
|
||||||
-
|
|
||||||
- # Run two different but overlapping paged searches simultaneously.
|
|
||||||
- set_1_index = int((len(all_results))//3)
|
|
||||||
- set_2_index = int((2*len(all_results))//3)
|
|
||||||
- set_1 = all_results[set_1_index:]
|
|
||||||
- set_2 = all_results[:set_2_index+1]
|
|
||||||
- set_1_expr = "(cn>=%s)" % (all_results[set_1_index])
|
|
||||||
- set_2_expr = "(cn<=%s)" % (all_results[set_2_index])
|
|
||||||
-
|
|
||||||
- results, cookie1 = self.paged_search(set_1_expr, page_size=ps)
|
|
||||||
- self.assertEqual(results, set_1[:ps])
|
|
||||||
- results, cookie2 = self.paged_search(set_2_expr, page_size=ps)
|
|
||||||
- self.assertEqual(results, set_2[:ps])
|
|
||||||
-
|
|
||||||
- results, cookie1 = self.paged_search(set_1_expr, cookie=cookie1,
|
|
||||||
- page_size=ps)
|
|
||||||
- self.assertEqual(results, set_1[ps:ps*2])
|
|
||||||
- results, cookie2 = self.paged_search(set_2_expr, cookie=cookie2,
|
|
||||||
- page_size=ps)
|
|
||||||
- self.assertEqual(results, set_2[ps:ps*2])
|
|
||||||
-
|
|
||||||
- results, _ = self.paged_search(set_1_expr, cookie=cookie1,
|
|
||||||
- page_size=len(self.users))
|
|
||||||
- self.assertEqual(results, set_1[ps*2:])
|
|
||||||
- results, _ = self.paged_search(set_2_expr, cookie=cookie2,
|
|
||||||
- page_size=len(self.users))
|
|
||||||
- self.assertEqual(results, set_2[ps*2:])
|
|
||||||
-
|
|
||||||
def test_vlv_paged(self):
|
|
||||||
"""Testing behaviour with VLV and paged_results set.
|
|
||||||
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
From 11034ea33fca9b8a1c2e14480e70069b55fca6a2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
Date: Thu, 25 Jun 2020 11:59:54 +1200
|
|
||||||
Subject: [PATCH 19/22] CVE-2020-14303 Ensure an empty packet will not DoS the
|
|
||||||
NBT server
|
|
||||||
|
|
||||||
Signed-off-by: Andrew Bartlett <abartlet@samba.org>
|
|
||||||
---
|
|
||||||
python/samba/tests/dns_packet.py | 19 +++++++++++++++++++
|
|
||||||
selftest/knownfail.d/empty-nbt | 1 +
|
|
||||||
2 files changed, 20 insertions(+)
|
|
||||||
create mode 100644 selftest/knownfail.d/empty-nbt
|
|
||||||
|
|
||||||
diff --git a/python/samba/tests/dns_packet.py b/python/samba/tests/dns_packet.py
|
|
||||||
index c4f843eb613..ae7bcb3ad8c 100644
|
|
||||||
--- a/python/samba/tests/dns_packet.py
|
|
||||||
+++ b/python/samba/tests/dns_packet.py
|
|
||||||
@@ -156,6 +156,19 @@ class TestDnsPacketBase(TestCase):
|
|
||||||
rcode = self.decode_reply(data)['rcode']
|
|
||||||
return expected_rcode == rcode
|
|
||||||
|
|
||||||
+ def _test_empty_packet(self):
|
|
||||||
+
|
|
||||||
+ packet = b""
|
|
||||||
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
+ s.sendto(packet, self.server)
|
|
||||||
+ s.close()
|
|
||||||
+
|
|
||||||
+ # It is reasonable not to reply to an empty packet
|
|
||||||
+ # but it is not reasonable to render the server
|
|
||||||
+ # unresponsive.
|
|
||||||
+ ok = self._known_good_query()
|
|
||||||
+ self.assertTrue(ok, f"the server is unresponsive")
|
|
||||||
+
|
|
||||||
|
|
||||||
class TestDnsPackets(TestDnsPacketBase):
|
|
||||||
server = (SERVER, 53)
|
|
||||||
@@ -174,6 +187,9 @@ class TestDnsPackets(TestDnsPacketBase):
|
|
||||||
label = b'x.' * 31 + b'x'
|
|
||||||
self._test_many_repeated_components(label, 127)
|
|
||||||
|
|
||||||
+ def test_empty_packet(self):
|
|
||||||
+ self._test_empty_packet()
|
|
||||||
+
|
|
||||||
|
|
||||||
class TestNbtPackets(TestDnsPacketBase):
|
|
||||||
server = (SERVER, 137)
|
|
||||||
@@ -209,3 +225,6 @@ class TestNbtPackets(TestDnsPacketBase):
|
|
||||||
def test_127_half_dotty_components(self):
|
|
||||||
label = b'x.' * 31 + b'x'
|
|
||||||
self._test_many_repeated_components(label, 127)
|
|
||||||
+
|
|
||||||
+ def test_empty_packet(self):
|
|
||||||
+ self._test_empty_packet()
|
|
||||||
diff --git a/selftest/knownfail.d/empty-nbt b/selftest/knownfail.d/empty-nbt
|
|
||||||
new file mode 100644
|
|
||||||
index 00000000000..e4bcccab4e5
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/selftest/knownfail.d/empty-nbt
|
|
||||||
@@ -0,0 +1 @@
|
|
||||||
+^samba.tests.dns_packet.samba.tests.dns_packet.TestNbtPackets.test_empty_packet
|
|
||||||
\ No newline at end of file
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
@ -1,58 +0,0 @@
|
|||||||
From 153c8db09b26455aa9802ff95943dd8a75f31893 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
Date: Wed, 24 Jun 2020 14:27:08 +1200
|
|
||||||
Subject: [PATCH 20/22] CVE-2020-14303: s4 nbt: fix busy loop on empty UDP
|
|
||||||
packet
|
|
||||||
|
|
||||||
An empty UDP packet put the nbt server into a busy loop that consumes
|
|
||||||
100% of a cpu.
|
|
||||||
|
|
||||||
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14417
|
|
||||||
|
|
||||||
Signed-off-by: Gary Lockyer <gary@catalyst.net.nz>
|
|
||||||
---
|
|
||||||
libcli/nbt/nbtsocket.c | 17 ++++++++++++++++-
|
|
||||||
selftest/knownfail.d/empty-nbt | 1 -
|
|
||||||
2 files changed, 16 insertions(+), 2 deletions(-)
|
|
||||||
delete mode 100644 selftest/knownfail.d/empty-nbt
|
|
||||||
|
|
||||||
diff --git a/libcli/nbt/nbtsocket.c b/libcli/nbt/nbtsocket.c
|
|
||||||
index 33d53fba993..8aecaf73247 100644
|
|
||||||
--- a/libcli/nbt/nbtsocket.c
|
|
||||||
+++ b/libcli/nbt/nbtsocket.c
|
|
||||||
@@ -167,8 +167,23 @@ static void nbt_name_socket_recv(struct nbt_name_socket *nbtsock)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /*
|
|
||||||
+ * Given a zero length, data_blob_talloc() returns the
|
|
||||||
+ * NULL blob {NULL, 0}.
|
|
||||||
+ *
|
|
||||||
+ * We only want to error return here on a real out of memory condition
|
|
||||||
+ * (i.e. dsize != 0, so the UDP packet has data, but the return of the
|
|
||||||
+ * allocation failed, so blob.data==NULL).
|
|
||||||
+ *
|
|
||||||
+ * Given an actual zero length UDP packet having blob.data == NULL
|
|
||||||
+ * isn't an out of memory error condition, that's the defined semantics
|
|
||||||
+ * of data_blob_talloc() when asked for zero bytes.
|
|
||||||
+ *
|
|
||||||
+ * We still need to continue to do the zero-length socket_recvfrom()
|
|
||||||
+ * read in order to clear the "read pending" condition on the socket.
|
|
||||||
+ */
|
|
||||||
blob = data_blob_talloc(tmp_ctx, NULL, dsize);
|
|
||||||
- if (blob.data == NULL) {
|
|
||||||
+ if (blob.data == NULL && dsize != 0) {
|
|
||||||
talloc_free(tmp_ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
diff --git a/selftest/knownfail.d/empty-nbt b/selftest/knownfail.d/empty-nbt
|
|
||||||
deleted file mode 100644
|
|
||||||
index e4bcccab4e5..00000000000
|
|
||||||
--- a/selftest/knownfail.d/empty-nbt
|
|
||||||
+++ /dev/null
|
|
||||||
@@ -1 +0,0 @@
|
|
||||||
-^samba.tests.dns_packet.samba.tests.dns_packet.TestNbtPackets.test_empty_packet
|
|
||||||
\ No newline at end of file
|
|
||||||
--
|
|
||||||
2.17.1
|
|
||||||
|
|
||||||
7
samba-4.11.12.tar.asc
Normal file
7
samba-4.11.12.tar.asc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iHMEABECADMWIQRS+8C4bZVLCEMyTNxvM5FbZWi36gUCX0TCrBUcc2FtYmEtYnVn
|
||||||
|
c0BzYW1iYS5vcmcACgkQbzORW2Vot+pkIgCePoB8Vb0cE4j0tafdJDK411aAP9YA
|
||||||
|
n0xcJD8v1hc1/qlhXLjA6bG3i7Rx
|
||||||
|
=GXx8
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
Binary file not shown.
28
samba-4.11.13-lib_util_wscript.patch
Normal file
28
samba-4.11.13-lib_util_wscript.patch
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
From 7f2c62dcdebb387b086df37c8dd38a6027d8b631 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?G=C3=BCnther=20Deschner?= <gd@samba.org>
|
||||||
|
Date: Tue, 25 Aug 2020 10:37:18 +0200
|
||||||
|
Subject: [PATCH] lib/util: do not install /usr/bin/test_util
|
||||||
|
|
||||||
|
BUG: https://bugzilla.samba.org/show_bug.cgi?id=14166
|
||||||
|
|
||||||
|
Guenther
|
||||||
|
|
||||||
|
Signed-off-by: Guenther Deschner <gd@samba.org>
|
||||||
|
---
|
||||||
|
lib/util/wscript_build | 3 ++-
|
||||||
|
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
|
||||||
|
index 4ac0a9cc064..e04752cb130 100644
|
||||||
|
--- a/lib/util/wscript_build
|
||||||
|
+++ b/lib/util/wscript_build
|
||||||
|
@@ -291,4 +291,5 @@ else:
|
||||||
|
bld.SAMBA_BINARY('test_util',
|
||||||
|
source='tests/test_util.c',
|
||||||
|
deps='cmocka replace talloc samba-util',
|
||||||
|
- local_include=False)
|
||||||
|
+ local_include=False,
|
||||||
|
+ install=False)
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iHMEABECADMWIQRS+8C4bZVLCEMyTNxvM5FbZWi36gUCXjALthUcc2FtYmEtYnVn
|
|
||||||
c0BzYW1iYS5vcmcACgkQbzORW2Vot+od+ACgpzREKkVcyLse9EwufX0vS/JMUYIA
|
|
||||||
n2xGjOlyTFJJUD9heWInjmYzy4W0
|
|
||||||
=472O
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
50
samba.spec
50
samba.spec
@ -4,7 +4,7 @@
|
|||||||
%define talloc_version 2.2.0
|
%define talloc_version 2.2.0
|
||||||
%define tdb_version 1.4.2
|
%define tdb_version 1.4.2
|
||||||
%define tevent_version 0.10.0
|
%define tevent_version 0.10.0
|
||||||
%define ldb_version 2.0.8
|
%define ldb_version 2.0.12
|
||||||
|
|
||||||
%undefine _strict_symbol_defs_build
|
%undefine _strict_symbol_defs_build
|
||||||
|
|
||||||
@ -48,8 +48,8 @@
|
|||||||
%define samba_depver %{version}-%{release}
|
%define samba_depver %{version}-%{release}
|
||||||
|
|
||||||
Name: samba
|
Name: samba
|
||||||
Version: 4.11.6
|
Version: 4.11.12
|
||||||
Release: 8
|
Release: 1
|
||||||
|
|
||||||
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,35 +69,7 @@ Source201: README.downgrade
|
|||||||
Patch0: 0000-use-gnutls-for-des-cbc.patch
|
Patch0: 0000-use-gnutls-for-des-cbc.patch
|
||||||
Patch1: 0001-handle-removal-des-enctypes-from-krb5.patch
|
Patch1: 0001-handle-removal-des-enctypes-from-krb5.patch
|
||||||
Patch2: 0002-samba-tool-create-working-private-krb5.conf.patch
|
Patch2: 0002-samba-tool-create-working-private-krb5.conf.patch
|
||||||
Patch3: CVE-2020-10700-1.patch
|
Patch3: samba-4.11.13-lib_util_wscript.patch
|
||||||
Patch4: CVE-2020-10700-3.patch
|
|
||||||
Patch5: CVE-2020-10704-1.patch
|
|
||||||
Patch6: CVE-2020-10704-3.patch
|
|
||||||
Patch7: CVE-2020-10704-5.patch
|
|
||||||
Patch8: CVE-2020-10704-6.patch
|
|
||||||
Patch9: CVE-2020-10704-7.patch
|
|
||||||
Patch10: CVE-2020-10704-8.patch
|
|
||||||
Patch11: CVE-2020-10730-1.patch
|
|
||||||
Patch12: CVE-2020-10730-2.patch
|
|
||||||
Patch13: CVE-2020-10730-3.patch
|
|
||||||
Patch14: CVE-2020-10730-4.patch
|
|
||||||
Patch15: CVE-2020-10730-5.patch
|
|
||||||
Patch16: CVE-2020-10730-6.patch
|
|
||||||
Patch17: CVE-2020-10730-7.patch
|
|
||||||
Patch18: CVE-2020-10730-8.patch
|
|
||||||
Patch19: CVE-2020-10730-9.patch
|
|
||||||
Patch20: CVE-2020-10730-10.patch
|
|
||||||
Patch21: CVE-2020-10745-1.patch
|
|
||||||
Patch22: CVE-2020-10745-2.patch
|
|
||||||
Patch23: CVE-2020-10745-3.patch
|
|
||||||
Patch24: CVE-2020-10745-4.patch
|
|
||||||
Patch25: CVE-2020-10745-5.patch
|
|
||||||
Patch26: CVE-2020-10745-6.patch
|
|
||||||
Patch27: CVE-2020-10745-7.patch
|
|
||||||
Patch28: CVE-2020-14303-1.patch
|
|
||||||
Patch29: CVE-2020-14303-2.patch
|
|
||||||
Patch30: CVE-2020-10760-1.patch
|
|
||||||
Patch31: CVE-2020-10760-2.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
|
||||||
@ -1856,6 +1828,7 @@ fi
|
|||||||
%{python3_sitearch}/samba/tests/__pycache__/hostconfig.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/hostconfig.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/__pycache__/join.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/join.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/__pycache__/krb5_credentials.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/krb5_credentials.*.pyc
|
||||||
|
%{python3_sitearch}/samba/tests/__pycache__/ldap_raw.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/__pycache__/ldap_referrals.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/ldap_referrals.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/__pycache__/loadparm.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/loadparm.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/__pycache__/libsmb.*.pyc
|
%{python3_sitearch}/samba/tests/__pycache__/libsmb.*.pyc
|
||||||
@ -2039,6 +2012,7 @@ fi
|
|||||||
%{python3_sitearch}/samba/tests/kcc/kcc_utils.py
|
%{python3_sitearch}/samba/tests/kcc/kcc_utils.py
|
||||||
%{python3_sitearch}/samba/tests/kcc/ldif_import_export.py
|
%{python3_sitearch}/samba/tests/kcc/ldif_import_export.py
|
||||||
%{python3_sitearch}/samba/tests/krb5_credentials.py
|
%{python3_sitearch}/samba/tests/krb5_credentials.py
|
||||||
|
%{python3_sitearch}/samba/tests/ldap_raw.py
|
||||||
%{python3_sitearch}/samba/tests/ldap_referrals.py
|
%{python3_sitearch}/samba/tests/ldap_referrals.py
|
||||||
%{python3_sitearch}/samba/tests/libsmb.py
|
%{python3_sitearch}/samba/tests/libsmb.py
|
||||||
%{python3_sitearch}/samba/tests/loadparm.py
|
%{python3_sitearch}/samba/tests/loadparm.py
|
||||||
@ -2113,6 +2087,9 @@ fi
|
|||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_check_password_script.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_check_password_script.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA.*.pyc
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_base.*.pyc
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_gpg.*.pyc
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_virtualCryptSHA_userPassword.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_wdigest.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/user_wdigest.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize.*.pyc
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize_drs.*.pyc
|
%{python3_sitearch}/samba/tests/samba_tool/__pycache__/visualize_drs.*.pyc
|
||||||
@ -2144,6 +2121,9 @@ fi
|
|||||||
%{python3_sitearch}/samba/tests/samba_tool/user.py
|
%{python3_sitearch}/samba/tests/samba_tool/user.py
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/user_check_password_script.py
|
%{python3_sitearch}/samba/tests/samba_tool/user_check_password_script.py
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA.py
|
%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA.py
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_base.py
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_gpg.py
|
||||||
|
%{python3_sitearch}/samba/tests/samba_tool/user_virtualCryptSHA_userPassword.py
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/user_wdigest.py
|
%{python3_sitearch}/samba/tests/samba_tool/user_wdigest.py
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/visualize.py
|
%{python3_sitearch}/samba/tests/samba_tool/visualize.py
|
||||||
%{python3_sitearch}/samba/tests/samba_tool/visualize_drs.py
|
%{python3_sitearch}/samba/tests/samba_tool/visualize_drs.py
|
||||||
@ -3076,6 +3056,12 @@ fi
|
|||||||
%{_mandir}/man*
|
%{_mandir}/man*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Aug 31 2020 yuboyun <yuboyun@huawei.com> - 4.11.12-1
|
||||||
|
- Type:NA
|
||||||
|
- ID:NA
|
||||||
|
- SUG:NA
|
||||||
|
- DESC:update to 4.11.12
|
||||||
|
|
||||||
* Wed Aug 05 2020 yuboyun <yuboyun@huawei.com> - 4.11.6-8
|
* Wed Aug 05 2020 yuboyun <yuboyun@huawei.com> - 4.11.6-8
|
||||||
- Type:cves
|
- Type:cves
|
||||||
- ID:CVE-2020-10730 CVE-2020-10745 CVE-2020-14303 CVE-2020-10760
|
- ID:CVE-2020-10730 CVE-2020-10745 CVE-2020-14303 CVE-2020-10760
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user