summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Lockyer <gary@catalyst.net.nz>2020-04-08 08:49:23 +1200
committerKarolin Seeger <kseeger@samba.org>2020-04-22 12:50:42 +0200
commitdb78f2667eb51c106c66edebcf66914ea580bfc6 (patch)
tree7a3fd1e016a79e22e0aca35c9a4ff9d316987860
parent8729c05b1cd6a63d9f8e163b2e438007db3eb4f8 (diff)
downloadsamba-db78f2667eb51c106c66edebcf66914ea580bfc6.tar.gz
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>
-rw-r--r--docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml18
-rw-r--r--lib/fuzzing/fuzz_ldap_decode.c9
-rw-r--r--lib/param/loadparm.c2
-rw-r--r--libcli/cldap/cldap.c18
-rw-r--r--libcli/ldap/ldap_message.c1
-rw-r--r--libcli/ldap/ldap_message.h5
-rw-r--r--libcli/ldap/tests/ldap_message_test.c24
-rw-r--r--source3/param/loadparm.c1
-rw-r--r--source4/ldap_server/ldap_server.c10
-rw-r--r--source4/libcli/ldap/ldap_client.c3
10 files changed, 80 insertions, 11 deletions
diff --git a/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml
new file mode 100644
index 00000000000..ebeb0816c01
--- /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>
diff --git a/lib/fuzzing/fuzz_ldap_decode.c b/lib/fuzzing/fuzz_ldap_decode.c
index d89ba637061..e3bcf7b9d0a 100644
--- a/lib/fuzzing/fuzz_ldap_decode.c
+++ b/lib/fuzzing/fuzz_ldap_decode.c
@@ -32,6 +32,12 @@ int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
TALLOC_CTX *mem_ctx = talloc_init(__FUNCTION__);
struct asn1_data *asn1;
struct ldap_message *ldap_msg;
+ struct ldap_request_limits limits = {
+ /*
+ * The default size is currently 256000 bytes
+ */
+ .max_search_size = 256000
+ };
NTSTATUS status;
/*
@@ -50,7 +56,8 @@ int LLVMFuzzerTestOneInput(uint8_t *buf, size_t len)
goto out;
}
- status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg);
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
out:
talloc_free(mem_ctx);
diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c
index 2eed5aa082d..63291283905 100644
--- a/lib/param/loadparm.c
+++ b/lib/param/loadparm.c
@@ -3045,6 +3045,8 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx)
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)) {
diff --git a/libcli/cldap/cldap.c b/libcli/cldap/cldap.c
index 3f687728517..7de72b5e899 100644
--- 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) {
@@ -228,6 +233,9 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
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;
@@ -246,7 +254,7 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c,
}
/* 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;
}
@@ -774,6 +782,9 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
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;
@@ -784,7 +795,7 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
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;
}
@@ -800,7 +811,8 @@ NTSTATUS cldap_search_recv(struct tevent_req *req,
*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;
}
diff --git a/libcli/ldap/ldap_message.c b/libcli/ldap/ldap_message.c
index ba82bddeab1..d38fa0b3b61 100644
--- a/libcli/ldap/ldap_message.c
+++ b/libcli/ldap/ldap_message.c
@@ -1162,6 +1162,7 @@ static bool ldap_decode_attribs(TALLOC_CTX *mem_ctx, struct asn1_data *data,
/* 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)
{
diff --git a/libcli/ldap/ldap_message.h b/libcli/ldap/ldap_message.h
index 2f64881c053..19bfb99ac97 100644
--- 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,
diff --git a/libcli/ldap/tests/ldap_message_test.c b/libcli/ldap/tests/ldap_message_test.c
index 9cc9cc5d8a0..c5aacd4bc6b 100644
--- a/libcli/ldap/tests/ldap_message_test.c
+++ b/libcli/ldap/tests/ldap_message_test.c
@@ -117,6 +117,9 @@ static void test_empty_input(void **state)
NTSTATUS status;
uint8_t buf[0];
size_t len = 0;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
@@ -127,7 +130,8 @@ static void test_empty_input(void **state)
ldap_msg = talloc(test_ctx, struct ldap_message);
assert_non_null(ldap_msg);
- status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg);
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
}
@@ -149,6 +153,9 @@ static void test_recursion_depth_large(void **state)
uint8_t *buffer = NULL;
const size_t BUFF_SIZE = 1048576;
size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
/*
@@ -169,7 +176,8 @@ static void test_recursion_depth_large(void **state)
ldap_msg = talloc(test_ctx, struct ldap_message);
assert_non_null(ldap_msg);
- status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg);
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
}
@@ -189,6 +197,9 @@ static void test_recursion_depth_equals_max(void **state)
uint8_t *buffer = NULL;
const size_t BUFF_SIZE = 1048576;
size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
@@ -205,7 +216,8 @@ static void test_recursion_depth_equals_max(void **state)
ldap_msg = talloc(test_ctx, struct ldap_message);
assert_non_null(ldap_msg);
- status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg);
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
assert_true(NT_STATUS_IS_OK(status));
}
@@ -225,6 +237,9 @@ static void test_recursion_depth_greater_than_max(void **state)
uint8_t *buffer = NULL;
const size_t BUFF_SIZE = 1048576;
size_t len;
+ struct ldap_request_limits limits = {
+ .max_search_size = 256000,
+ };
buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
@@ -241,7 +256,8 @@ static void test_recursion_depth_greater_than_max(void **state)
ldap_msg = talloc(test_ctx, struct ldap_message);
assert_non_null(ldap_msg);
- status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg);
+ status = ldap_decode(
+ asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
}
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index dd51042c125..d3d81f6ece5 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -957,6 +957,7 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals)
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();
diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c
index a730667abb9..a9b162b284e 100644
--- a/source4/ldap_server/ldap_server.c
+++ b/source4/ldap_server/ldap_server.c
@@ -538,6 +538,7 @@ static void ldapsrv_call_read_done(struct tevent_req *subreq)
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(struct tevent_req *subreq)
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;
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
index 319ef3a60a7..abe4e523585 100644
--- a/source4/libcli/ldap/ldap_client.c
+++ b/source4/libcli/ldap/ldap_client.c
@@ -277,6 +277,7 @@ static void ldap_connection_recv_done(struct tevent_req *subreq)
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(struct tevent_req *subreq)
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);