212 lines
6.8 KiB
Diff
212 lines
6.8 KiB
Diff
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);
|