The Samba-Bugzilla – Attachment 15917 Details for
Bug 14334
CVE-2020-10704 [FUZZING][SECURITY] Stack overflow in AD DC (C)LDAP server
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch for V4.10 (v5)
CVE-2020-10704-4.10-V5.patch (text/plain), 79.98 KB, created by
Gary Lockyer
on 2020-04-16 05:14:01 UTC
(
hide
)
Description:
Patch for V4.10 (v5)
Filename:
MIME Type:
Creator:
Gary Lockyer
Created:
2020-04-16 05:14:01 UTC
Size:
79.98 KB
patch
obsolete
>From 5d28fe888ec60042ac080fc6bd00b1d69ace27a4 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/9] 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 +-- > 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 ++++++++++++++--------------- > 14 files changed, 65 insertions(+), 43 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 60ddfa09bcf..c6c2f3bbec2 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; > } > >@@ -473,6 +477,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) { >@@ -480,6 +489,7 @@ bool asn1_load(struct asn1_data *data, DATA_BLOB blob) > return false; > } > data->length = blob.length; >+ data->max_depth = max_depth; > return true; > } > >@@ -1096,9 +1106,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 54a9eb30bbe..9841f1ee6eb 100644 >--- a/source3/lib/tldap_util.c >+++ b/source3/lib/tldap_util.c >@@ -631,7 +631,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; > } >@@ -770,7 +770,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/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 90d32c6833a..ebd81127f37 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 1cbcd0d42d5..1113af14f92 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 > > >From 400f03fc3fbe36de463cf19c8270d21a783d5909 Mon Sep 17 00:00:00 2001 >From: Gary Lockyer <gary@catalyst.net.nz> >Date: Thu, 2 Apr 2020 15:25:53 +1300 >Subject: [PATCH 2/9] CVE-2020-10704: libcli ldap: test recursion depth in > ldap_decode_filter_tree > >Add tests to check that ASN.1 ldap requests with deeply nested elements >are rejected. Previously there was no check on the on the depth of >nesting and excessive nesting could cause a stack overflow. > >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> >--- > libcli/ldap/tests/data/10000-or.dat | Bin 0 -> 39875 bytes > libcli/ldap/tests/data/ldap-recursive.dat | Bin 0 -> 970 bytes > libcli/ldap/tests/ldap_message_test.c | 271 ++++++++++++++++++++++ > libcli/ldap/wscript_build | 15 ++ > selftest/knownfail.d/ldap_message | 2 + > source4/selftest/tests.py | 2 + > 6 files changed, 290 insertions(+) > create mode 100644 libcli/ldap/tests/data/10000-or.dat > create mode 100644 libcli/ldap/tests/data/ldap-recursive.dat > create mode 100644 libcli/ldap/tests/ldap_message_test.c > create mode 100644 selftest/knownfail.d/ldap_message > >diff --git a/libcli/ldap/tests/data/10000-or.dat b/libcli/ldap/tests/data/10000-or.dat >new file mode 100644 >index 0000000000000000000000000000000000000000..e2d6de2ce330e80d1c2f28854b3542b789de9834 >GIT binary patch >literal 39875 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 > >literal 0 >HcmV?d00001 > >diff --git a/libcli/ldap/tests/data/ldap-recursive.dat b/libcli/ldap/tests/data/ldap-recursive.dat >new file mode 100644 >index 0000000000000000000000000000000000000000..dd18d857660df41c30024264d4623680a9404613 >GIT binary patch >literal 970 >zcmXqLVm`*i$ei57yq|@EixGsFz=)BNVWC1hcYab<YI2ElPGWI!yI@LYaY<%gdTC~H >hMrw**Vs5HI6LSYk6LX73%_tlV0qTc<<|rUK1OSbr11$gm > >literal 0 >HcmV?d00001 > >diff --git a/libcli/ldap/tests/ldap_message_test.c b/libcli/ldap/tests/ldap_message_test.c >new file mode 100644 >index 00000000000..9cc9cc5d8a0 >--- /dev/null >+++ b/libcli/ldap/tests/ldap_message_test.c >@@ -0,0 +1,271 @@ >+/* >+ * Unit tests for ldap_message. >+ * >+ * 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/>. >+ * >+ */ >+ >+/* >+ * from cmocka.c: >+ * These headers or their equivalents should be included prior to >+ * including >+ * this header file. >+ * >+ * #include <stdarg.h> >+ * #include <stddef.h> >+ * #include <setjmp.h> >+ * >+ * This allows test applications to use custom definitions of C standard >+ * library functions and types. >+ * >+ */ >+#include <stdarg.h> >+#include <stddef.h> >+#include <setjmp.h> >+#include <cmocka.h> >+ >+#include "lib/util/attr.h" >+#include "includes.h" >+#include "lib/util/asn1.h" >+#include "libcli/ldap/ldap_message.h" >+#include "libcli/ldap/ldap_proto.h" >+ >+/* >+ * declare the internal cmocka cm_print so we can output messages in >+ * sub unit format >+ */ >+void cm_print_error(const char * const format, ...); >+/* >+ * helper function and macro to compare an ldap error code constant with the >+ * coresponding nt_status code >+ */ >+#define NT_STATUS_LDAP_V(code) (0xF2000000 | code) >+static void _assert_ldap_status_equal( >+ int a, >+ NTSTATUS b, >+ const char * const file, >+ const int line) >+{ >+ _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line); >+} >+ >+#define assert_ldap_status_equal(a, b) \ >+ _assert_ldap_status_equal((a), (b), __FILE__, __LINE__) >+ >+/* >+ * helper function and macro to assert there were no errors in the last >+ * file operation >+ */ >+static void _assert_not_ferror( >+ FILE *f, >+ const char * const file, >+ const int line) >+{ >+ if (f == NULL || ferror(f)) { >+ cm_print_error("ferror (%d) %s\n", errno, strerror(errno)); >+ _fail(file, line); >+ } >+} >+ >+#define assert_not_ferror(f) \ >+ _assert_not_ferror((f), __FILE__, __LINE__) >+ >+struct test_ctx { >+}; >+ >+static int setup(void **state) >+{ >+ struct test_ctx *test_ctx; >+ >+ test_ctx = talloc_zero(NULL, struct test_ctx); >+ *state = test_ctx; >+ return 0; >+} >+ >+static int teardown(void **state) >+{ >+ struct test_ctx *test_ctx = talloc_get_type_abort(*state, >+ struct test_ctx); >+ >+ TALLOC_FREE(test_ctx); >+ return 0; >+} >+ >+/* >+ * Test that an empty request is handled correctly >+ */ >+static void test_empty_input(void **state) >+{ >+ struct test_ctx *test_ctx = talloc_get_type_abort( >+ *state, >+ struct test_ctx); >+ struct asn1_data *asn1; >+ struct ldap_message *ldap_msg; >+ NTSTATUS status; >+ uint8_t buf[0]; >+ size_t len = 0; >+ >+ >+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH); >+ assert_non_null(asn1); >+ >+ asn1_load_nocopy(asn1, buf, len); >+ >+ ldap_msg = talloc(test_ctx, struct ldap_message); >+ assert_non_null(ldap_msg); >+ >+ status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg); >+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status); >+} >+ >+/* >+ * Check that a request is rejected it it's recursion depth exceeds >+ * the maximum value specified. This test uses a very deeply nested query, >+ * 10,000 or clauses. >+ * >+ */ >+static void test_recursion_depth_large(void **state) >+{ >+ struct test_ctx *test_ctx = talloc_get_type_abort( >+ *state, >+ struct test_ctx); >+ struct asn1_data *asn1; >+ struct ldap_message *ldap_msg; >+ NTSTATUS status; >+ FILE *f = NULL; >+ uint8_t *buffer = NULL; >+ const size_t BUFF_SIZE = 1048576; >+ size_t len; >+ >+ >+ /* >+ * Load a test data file containg 10,000 or clauses in encoded as >+ * an ASN.1 packet. >+ */ >+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE); >+ f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r"); >+ assert_not_ferror(f); >+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f); >+ assert_not_ferror(f); >+ assert_true(len > 0); >+ >+ asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH); >+ assert_non_null(asn1); >+ asn1_load_nocopy(asn1, buffer, len); >+ >+ ldap_msg = talloc(test_ctx, struct ldap_message); >+ assert_non_null(ldap_msg); >+ >+ status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg); >+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status); >+} >+ >+/* >+ * Check that a request is not rejected it it's recursion depth equals the >+ * maximum value >+ */ >+static void test_recursion_depth_equals_max(void **state) >+{ >+ struct test_ctx *test_ctx = talloc_get_type_abort( >+ *state, >+ struct test_ctx); >+ struct asn1_data *asn1; >+ struct ldap_message *ldap_msg; >+ NTSTATUS status; >+ FILE *f = NULL; >+ uint8_t *buffer = NULL; >+ const size_t BUFF_SIZE = 1048576; >+ size_t len; >+ >+ >+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE); >+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r"); >+ assert_not_ferror(f); >+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f); >+ assert_not_ferror(f); >+ assert_true(len > 0); >+ >+ asn1 = asn1_init(test_ctx, 4); >+ assert_non_null(asn1); >+ asn1_load_nocopy(asn1, buffer, len); >+ >+ ldap_msg = talloc(test_ctx, struct ldap_message); >+ assert_non_null(ldap_msg); >+ >+ status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg); >+ assert_true(NT_STATUS_IS_OK(status)); >+} >+ >+/* >+ * Check that a request is rejected it it's recursion depth is greater than the >+ * maximum value >+ */ >+static void test_recursion_depth_greater_than_max(void **state) >+{ >+ struct test_ctx *test_ctx = talloc_get_type_abort( >+ *state, >+ struct test_ctx); >+ struct asn1_data *asn1; >+ struct ldap_message *ldap_msg; >+ NTSTATUS status; >+ FILE *f = NULL; >+ uint8_t *buffer = NULL; >+ const size_t BUFF_SIZE = 1048576; >+ size_t len; >+ >+ >+ buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE); >+ f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r"); >+ assert_not_ferror(f); >+ len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f); >+ assert_not_ferror(f); >+ assert_true(len > 0); >+ >+ asn1 = asn1_init(test_ctx, 3); >+ assert_non_null(asn1); >+ asn1_load_nocopy(asn1, buffer, len); >+ >+ ldap_msg = talloc(test_ctx, struct ldap_message); >+ assert_non_null(ldap_msg); >+ >+ status = ldap_decode(asn1, samba_ldap_control_handlers(), ldap_msg); >+ assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status); >+} >+ >+int main(_UNUSED_ int argc, _UNUSED_ const char **argv) >+{ >+ const struct CMUnitTest tests[] = { >+ cmocka_unit_test_setup_teardown( >+ test_empty_input, >+ setup, >+ teardown), >+ cmocka_unit_test_setup_teardown( >+ test_recursion_depth_large, >+ setup, >+ teardown), >+ cmocka_unit_test_setup_teardown( >+ test_recursion_depth_equals_max, >+ setup, >+ teardown), >+ cmocka_unit_test_setup_teardown( >+ test_recursion_depth_greater_than_max, >+ setup, >+ teardown), >+ }; >+ >+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT); >+ return cmocka_run_group_tests(tests, NULL, NULL); >+} >diff --git a/libcli/ldap/wscript_build b/libcli/ldap/wscript_build >index db5b1df497a..d0aa7c11ced 100644 >--- a/libcli/ldap/wscript_build >+++ b/libcli/ldap/wscript_build >@@ -6,3 +6,18 @@ bld.SAMBA_LIBRARY('cli-ldap-common', > private_headers='ldap_message.h ldap_errors.h ldap_ndr.h', > deps='samba-util asn1util NDR_SECURITY tevent', > private_library=True) >+ >+bld.SAMBA_BINARY( >+ 'test_ldap_message', >+ source='tests/ldap_message_test.c', >+ deps=''' >+ cmocka >+ talloc >+ ldb >+ samba-util >+ asn1util >+ NDR_SECURITY >+ cli-ldap >+ ''', >+ install=False >+) >diff --git a/selftest/knownfail.d/ldap_message b/selftest/knownfail.d/ldap_message >new file mode 100644 >index 00000000000..242eff45e59 >--- /dev/null >+++ b/selftest/knownfail.d/ldap_message >@@ -0,0 +1,2 @@ >+^libcli.ldap.ldap_message.test_recursion_depth_greater_than_max\(none\) >+^libcli.ldap.ldap_message.test_recursion_depth_large\(none\) >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index c672637e2e0..4504646d9a5 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -1286,6 +1286,8 @@ plantestsuite("samba4.dsdb.samdb.ldb_modules.group_audit.errors", "none", > [os.path.join(bindir(), "test_group_audit_errors")]) > plantestsuite("samba4.dcerpc.dnsserver.dnsutils", "none", > [os.path.join(bindir(), "test_rpc_dns_server_dnsutils")]) >+plantestsuite("libcli.ldap.ldap_message", "none", >+ [os.path.join(bindir(), "test_ldap_message")]) > > # process restart and limit tests, these break the environment so need to run > # in their own specific environment >-- >2.17.1 > > >From 7030f7b9d3984964f3eae279ec6307a79885e2b7 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/9] 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 > >diff --git a/lib/util/asn1.c b/lib/util/asn1.c >index c6c2f3bbec2..def71585d38 100644 >--- a/lib/util/asn1.c >+++ b/lib/util/asn1.c >@@ -640,6 +640,16 @@ bool asn1_start_tag(struct asn1_data *data, uint8_t tag) > 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; > >@@ -696,6 +706,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; >diff --git a/selftest/knownfail.d/ldap_message b/selftest/knownfail.d/ldap_message >deleted file mode 100644 >index 242eff45e59..00000000000 >--- a/selftest/knownfail.d/ldap_message >+++ /dev/null >@@ -1,2 +0,0 @@ >-^libcli.ldap.ldap_message.test_recursion_depth_greater_than_max\(none\) >-^libcli.ldap.ldap_message.test_recursion_depth_large\(none\) >-- >2.17.1 > > >From 6ee4b469bf69899e742bfb59b0a880901ee9ee83 Mon Sep 17 00:00:00 2001 >From: Gary Lockyer <gary@catalyst.net.nz> >Date: Tue, 14 Apr 2020 13:32:32 +1200 >Subject: [PATCH 4/9] CVE-2020-10704: ldapserver tests: Limit search request > sizes > >Add tests to ensure that overly long (> 256000 bytes) LDAP search >requests are rejected. > >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> >--- > python/samba/tests/ldap_raw.py | 234 +++++++++++++++++++++++++++++++++ > selftest/knownfail.d/ldap_raw | 1 + > source4/selftest/tests.py | 6 + > 3 files changed, 241 insertions(+) > create mode 100644 python/samba/tests/ldap_raw.py > create mode 100644 selftest/knownfail.d/ldap_raw > >diff --git a/python/samba/tests/ldap_raw.py b/python/samba/tests/ldap_raw.py >new file mode 100644 >index 00000000000..334fabce230 >--- /dev/null >+++ b/python/samba/tests/ldap_raw.py >@@ -0,0 +1,234 @@ >+# Integration tests for the ldap server, using raw socket IO >+# >+# Tests for handling of malformed or large packets. >+# >+# 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/>. >+# >+ >+import socket >+ >+import samba.tests >+from samba.tests import TestCase >+ >+ >+# >+# LDAP Operations >+# >+SEARCH = b'\x63' >+ >+EQUALS = b'\xa3' >+ >+ >+# >+# ASN.1 Element types >+# >+BOOLEAN = b'\x01' >+INTEGER = b'\x02' >+OCTET_STRING = b'\x04' >+NULL = b'\x05' >+ENUMERATED = b'\x0a' >+SEQUENCE = b'\x30' >+SET = b'\x31' >+ >+ >+# >+# ASN.1 Helper functions. >+# >+def encode_element(ber_type, data): >+ ''' Encode an ASN.1 BER element. ''' >+ if data is None: >+ return ber_type + encode_length(0) >+ return ber_type + encode_length(len(data)) + data >+ >+ >+def encode_length(length): >+ ''' Encode the length of an ASN.1 BER element. ''' >+ >+ if length > 0xFFFFFF: >+ return b'\x84' + length.to_bytes(4, "big") >+ if length > 0xFFFF: >+ return b'\x83' + length.to_bytes(3, "big") >+ if length > 0xFF: >+ return b'\x82' + length.to_bytes(2, "big") >+ if length > 0x7F: >+ return b'\x81' + length.to_bytes(1, "big") >+ return length.to_bytes(1, "big") >+ >+ >+def encode_string(string): >+ ''' Encode an octet string ''' >+ return encode_element(OCTET_STRING, string) >+ >+ >+def encode_boolean(boolean): >+ ''' Encode a boolean value ''' >+ if boolean: >+ return encode_element(BOOLEAN, b'\xFF') >+ return encode_element(BOOLEAN, b'\x00') >+ >+ >+def encode_integer(integer): >+ ''' Encode an integer value ''' >+ bit_len = integer.bit_length() >+ byte_len = (bit_len // 8) + 1 >+ return encode_element(INTEGER, integer.to_bytes(byte_len, "big")) >+ >+ >+def encode_enumerated(enum): >+ ''' Encode an enumerated value ''' >+ return encode_element(ENUMERATED, enum.to_bytes(1, "big")) >+ >+ >+def encode_sequence(sequence): >+ ''' Encode a sequence ''' >+ return encode_element(SEQUENCE, sequence) >+ >+ >+class RawLdapTest(TestCase): >+ """A raw Ldap Test case.""" >+ >+ def setUp(self): >+ super(RawLdapTest, self).setUp() >+ >+ self.host = samba.tests.env_get_var_value('SERVER') >+ self.port = 389 >+ self.socket = None >+ self.connect() >+ >+ def tearDown(self): >+ self.disconnect() >+ super(RawLdapTest, self).tearDown() >+ >+ def disconnect(self): >+ ''' Disconnect from and clean up the connection to the server ''' >+ if self.socket is None: >+ return >+ self.socket.close() >+ self.socket = None >+ >+ def connect(self): >+ ''' Open a socket stream connection to the server ''' >+ try: >+ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) >+ self.socket.settimeout(10) >+ self.socket.connect((self.host, self.port)) >+ except socket.error: >+ self.socket.close() >+ raise >+ >+ def send(self, req): >+ ''' Send the request to the server ''' >+ try: >+ self.socket.sendall(req) >+ except socket.error: >+ self.disconnect() >+ raise >+ >+ def recv(self, num_recv=0xffff, timeout=None): >+ ''' recv an array of bytes from the server ''' >+ data = None >+ try: >+ if timeout is not None: >+ self.socket.settimeout(timeout) >+ data = self.socket.recv(num_recv, 0) >+ self.socket.settimeout(10) >+ if len(data) == 0: >+ self.disconnect() >+ return None >+ except socket.timeout: >+ # We ignore timeout's as the ldap server will drop the connection >+ # on the errors we're testing. So returning None on a timeout is >+ # the desired behaviour. >+ self.socket.settimeout(10) >+ except socket.error: >+ self.disconnect() >+ raise >+ return data >+ >+ def test_search_equals_maximum_permitted_size(self): >+ ''' >+ Check that an LDAP search request equal to the maximum size is accepted >+ ''' >+ >+ # Lets build an ldap search packet to query the RootDSE >+ header = encode_string(None) # Base DN, "" >+ header += encode_enumerated(0) # Enumeration scope >+ header += encode_enumerated(0) # Enumeration dereference >+ header += encode_integer(0) # Integer size limit >+ header += encode_integer(0) # Integer time limit >+ header += encode_boolean(False) # Boolean attributes only >+ >+ # >+ # build an equality search of the form x...x=y...y >+ # With the length of x...x and y...y chosen to generate an >+ # ldap request of 256000 bytes. >+ x = encode_string(b'x' * 127974) >+ y = encode_string(b'y' * 127979) >+ equals = encode_element(EQUALS, x + y) >+ trailer = encode_sequence(None) >+ search = encode_element(SEARCH, header + equals + trailer) >+ >+ msg_no = encode_integer(1) >+ packet = encode_sequence(msg_no + search) >+ # >+ # The length of the packet should be equal to the >+ # Maximum length of a search query >+ self.assertEqual(256000, len(packet)) >+ >+ self.send(packet) >+ data = self.recv() >+ self.assertIsNotNone(data) >+ >+ # Should be a sequence >+ self.assertEqual(SEQUENCE, data[0:1]) >+ >+ def test_search_exceeds_maximum_permitted_size(self): >+ ''' >+ Test that a search query longer than the maximum permitted >+ size is rejected. >+ ''' >+ >+ # Lets build an ldap search packet to query the RootDSE >+ header = encode_string(None) # Base DN, "" >+ header += encode_enumerated(0) # Enumeration scope >+ header += encode_enumerated(0) # Enumeration dereference >+ header += encode_integer(0) # Integer size limit >+ header += encode_integer(0) # Integer time limit >+ header += encode_boolean(False) # Boolean attributes only >+ >+ # >+ # build an equality search of the form x...x=y...y >+ # With the length of x...x and y...y chosen to generate an >+ # ldap request of 256001 bytes. >+ x = encode_string(b'x' * 127979) >+ y = encode_string(b'y' * 127975) >+ equals = encode_element(EQUALS, x + y) >+ trailer = encode_sequence(None) >+ search = encode_element(SEARCH, header + equals + trailer) >+ >+ msg_no = encode_integer(1) >+ packet = encode_sequence(msg_no + search) >+ # >+ # The length of the sequence data should be one greater than the >+ # Maximum length of a search query >+ self.assertEqual(256001, len(packet)) >+ >+ self.send(packet) >+ data = self.recv() >+ # >+ # The connection should be closed by the server and we should not >+ # see any data. >+ self.assertIsNone(data) >diff --git a/selftest/knownfail.d/ldap_raw b/selftest/knownfail.d/ldap_raw >new file mode 100644 >index 00000000000..8bd2ee55166 >--- /dev/null >+++ b/selftest/knownfail.d/ldap_raw >@@ -0,0 +1 @@ >+^samba.tests.ldap_raw.samba.tests.ldap_raw.RawLdapTest.test_search_exceeds_maximum_permitted_size\(ad_dc\) >diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py >index 4504646d9a5..db268acc2ab 100755 >--- a/source4/selftest/tests.py >+++ b/source4/selftest/tests.py >@@ -864,6 +864,12 @@ for env in ["ad_dc_ntvfs:local", "ad_dc:local", > "promoted_dc:local"]: > planoldpythontestsuite(env, "samba.tests.blackbox.smbcontrol", py3_compatible=True) > >+planoldpythontestsuite("ad_dc", >+ "samba.tests.ldap_raw", >+ py3_compatible= True, >+ extra_args=['-U"$USERNAME%$PASSWORD"'], >+ environ={'TEST_ENV': 'ad_dc'}) >+ > planoldpythontestsuite("none", "samba.tests.blackbox.undoguididx") > > plantestsuite_loadlist("samba4.ldap.python(ad_dc_ntvfs)", "ad_dc_ntvfs", [python, os.path.join(samba4srcdir, "dsdb/tests/python/ldap.py"), '$SERVER', '-U"$USERNAME%$PASSWORD"', '--workgroup=$DOMAIN', '$LOADLIST', '$LISTOPT']) >-- >2.17.1 > > >From 91cac20dfbd01db6654d5cd2e6e6409cf7739839 Mon Sep 17 00:00:00 2001 >From: Gary Lockyer <gary@catalyst.net.nz> >Date: Thu, 16 Apr 2020 10:49:29 +1200 >Subject: [PATCH 5/9] CVE-2020-10704: ldapserver tests: Python 2 comaptibility > >The test python/samba/tests/ldap_raw.py does not run under python 3 >which means the CI task build_ad_dc_py2 fails. The test is run and >passes in the CI task build_ad_dc. This patch adds a check for the >Python version and skips the tests if running under python 2, allowing >CI to run for V4.10. > >This patch is only applied to version 4.10. > >Signed-off-by: Gary Lockyer <gary@catalyst.net.nz> >--- > python/samba/tests/ldap_raw.py | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/python/samba/tests/ldap_raw.py b/python/samba/tests/ldap_raw.py >index 334fabce230..589a0063d3c 100644 >--- a/python/samba/tests/ldap_raw.py >+++ b/python/samba/tests/ldap_raw.py >@@ -19,6 +19,7 @@ > # > > import socket >+import sys > > import samba.tests > from samba.tests import TestCase >@@ -162,6 +163,13 @@ class RawLdapTest(TestCase): > ''' > Check that an LDAP search request equal to the maximum size is accepted > ''' >+ # >+ # Test is not compatable with python 2 so skip it for the >+ # backports. >+ # >+ (version, *_) = sys.version_info >+ if version < 3: >+ pass > > # Lets build an ldap search packet to query the RootDSE > header = encode_string(None) # Base DN, "" >@@ -200,6 +208,10 @@ class RawLdapTest(TestCase): > Test that a search query longer than the maximum permitted > size is rejected. > ''' >+ # >+ # Test is not compatable with python 2 so skip it for the >+ # backports. >+ # > > # Lets build an ldap search packet to query the RootDSE > header = encode_string(None) # Base DN, "" >-- >2.17.1 > > >From 13eb7c62b02a861ec23d3106631ecc89d0199dbb 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 6/9] 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 > >diff --git a/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml >new file mode 100644 >index 00000000000..61bdcec674d >--- /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> >diff --git a/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml b/docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml >new file mode 100644 >index 00000000000..c5934f73f95 >--- /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> >diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c >index e4d27cae8ea..a63e665f985 100644 >--- a/lib/param/loadparm.c >+++ b/lib/param/loadparm.c >@@ -3008,6 +3008,11 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) > > lpcfg_do_global_parameter(lp_ctx, "store dos attributes", "yes"); > >+ 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; >diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c >index 12f32192bfe..b324e58cb4e 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -959,6 +959,9 @@ static void init_globals(struct loadparm_context *lp_ctx, bool reinit_globals) > 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(); > } >-- >2.17.1 > > >From 3729891d4fb4ba7a86796ba78ec7ba1ecfddfcc6 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 7/9] 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 > >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 ebd81127f37..c9ac271c4a9 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"); >@@ -1292,6 +1308,84 @@ failed: > } > > >+/* >+ * 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 = { >-- >2.17.1 > > >From f68bfce200ae6843f67ef411ddbdbbbb63614216 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 8/9] 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 > >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/param/loadparm.c b/lib/param/loadparm.c >index a63e665f985..4c3dfff24f3 100644 >--- a/lib/param/loadparm.c >+++ b/lib/param/loadparm.c >@@ -3012,6 +3012,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 8fa9ce0b273..25c1b40f8d9 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) { >@@ -224,6 +229,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; >@@ -242,7 +250,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; > } >@@ -770,6 +778,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; >@@ -780,7 +791,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; > } >@@ -796,7 +807,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 b324e58cb4e..0db44e92d19 100644 >--- a/source3/param/loadparm.c >+++ b/source3/param/loadparm.c >@@ -961,6 +961,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 c9ac271c4a9..25c3b624abc 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 1113af14f92..90a46937842 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); >-- >2.17.1 > > >From b4a7a5db548c5fe6eabb7c0869db809d2e2faf53 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 9/9] 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 def71585d38..03d417d8104 100644 >--- a/lib/util/asn1.c >+++ b/lib/util/asn1.c >@@ -1152,3 +1152,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 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
gary
:
ci-passed+
Actions:
View
Attachments on
bug 14334
:
15889
|
15893
|
15894
|
15895
|
15896
|
15906
|
15907
|
15910
|
15914
|
15915
|
15916
|
15917
|
15918
|
15920
|
15922
|
15923