summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2020-04-08 15:32:22 +1200
committerKarolin Seeger <kseeger@samba.org>2020-04-22 12:50:42 +0200
commit8729c05b1cd6a63d9f8e163b2e438007db3eb4f8 (patch)
tree4372f6a21f6735cb02f7ef6d872b799ecf457db8
parent48a3bdd7703ad3952f45e04c4f0a8d289ae74190 (diff)
downloadsamba-8729c05b1cd6a63d9f8e163b2e438007db3eb4f8.tar.gz
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>
-rw-r--r--selftest/knownfail.d/ldap_raw1
-rw-r--r--source4/ldap_server/ldap_server.c96
2 files changed, 95 insertions, 2 deletions
diff --git a/selftest/knownfail.d/ldap_raw b/selftest/knownfail.d/ldap_raw
deleted file mode 100644
index 8bd2ee55166..00000000000
--- a/selftest/knownfail.d/ldap_raw
+++ /dev/null
@@ -1 +0,0 @@
-^samba.tests.ldap_raw.samba.tests.ldap_raw.RawLdapTest.test_search_exceeds_maximum_permitted_size\(ad_dc\)
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index 6d329329909..a730667abb9 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -441,6 +441,10 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq)
}
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(struct ldapsrv_connection *conn)
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(struct ldapsrv_connection *conn)
}
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(struct tevent_req *subreq)
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(struct tevent_req *subreq)
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 task_server *task, struct process_details *
}
}
+/*
+ * 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 = {