164 lines
4.5 KiB
Diff
164 lines
4.5 KiB
Diff
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 = {
|