The branch, v4-12-test has been updated via af4d2a38fcb VERSION: Bump version up to 4.12.3. via 11620a07a89 Merge tag 'samba-4.12.2' into v4-12-test via ee9600d8a8f VERSION: Disable GIT_SNAPSHOT for the 4.12.2 release. via 51b4bf0c873 WHATSNEW: Add release notes for Samba 4.12.2. via 71b92c9554d CVE-2020-10704 libcli ldap: Check search request lengths. via db78f2667eb CVE-2020-10704: libcli ldap_message: Add search size limits to ldap_decode via 8729c05b1cd CVE-2020-10704: S4 ldap server: Limit request sizes via 48a3bdd7703 CVE-2020-10704: smb.conf: Add max ldap request sizes via 4aeb07ef49e CVE-2020-10704: ldapserver tests: Limit search request sizes via 16da9c6e3d8 CVE-2020-10704: lib util asn1: Check parse tree depth via 74986c179ea CVE-2020-10704: libcli ldap: test recursion depth in ldap_decode_filter_tree via 109b128ec1d CVE-2020-10704: lib util asn1: Add ASN.1 max tree depth via fecb05c8980 CVE-2020-10700: ldb: Bump version up to 2.1.2. via fb3e51020ab CVE-2020-10700: dsdb: Do not permit the ASQ control for the GUID search in paged_results via b824444544f CVE-2020-10700: ldb: Always use ldb_next_request() in ASQ module via 8e597aa1b9b CVE-2020-10700: dsdb: Add test for ASQ and ASQ in combination with paged_results via feb24fc1e51 VERSION: Bump version up to 4.12.2... from 21f64af155b ctdb: Fix a memleak
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-12-test - Log ----------------------------------------------------------------- commit af4d2a38fcb92ae58e4310acbfe43ab9548d1fa5 Author: Karolin Seeger <ksee...@samba.org> Date: Tue Apr 28 13:48:51 2020 +0200 VERSION: Bump version up to 4.12.3. Signed-off-by: Karolin Seeger <ksee...@samba.org> commit 11620a07a898146384f1473206791ebcfe09dfa5 Merge: 21f64af155b ee9600d8a8f Author: Karolin Seeger <ksee...@samba.org> Date: Tue Apr 28 13:48:23 2020 +0200 Merge tag 'samba-4.12.2' into v4-12-test samba: tag release samba-4.12.2 ----------------------------------------------------------------------- Summary of changes: VERSION | 2 +- WHATSNEW.txt | 65 ++++- auth/gensec/gensec_util.c | 2 +- docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml | 18 ++ docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml | 18 ++ docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml | 18 ++ lib/fuzzing/fuzz_ldap_decode.c | 15 +- lib/ldb/ABI/{ldb-2.0.5.sigs => ldb-2.1.2.sigs} | 0 ...pyldb-util-2.1.0.sigs => pyldb-util-2.1.2.sigs} | 0 lib/ldb/modules/asq.c | 12 +- lib/ldb/wscript | 2 +- lib/param/loadparm.c | 7 + lib/util/asn1.c | 37 ++- lib/util/asn1.h | 10 +- lib/util/tests/asn1_tests.c | 2 +- libcli/auth/spnego_parse.c | 6 +- libcli/cldap/cldap.c | 20 +- libcli/ldap/ldap_message.c | 7 +- libcli/ldap/ldap_message.h | 5 + 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 | 287 +++++++++++++++++++++ libcli/ldap/wscript_build | 15 ++ python/samba/tests/ldap_raw.py | 234 +++++++++++++++++ source3/lib/tldap.c | 4 +- source3/lib/tldap_util.c | 4 +- source3/libsmb/clispnego.c | 4 +- source3/param/loadparm.c | 4 + source3/torture/torture.c | 2 +- source4/auth/gensec/gensec_krb5.c | 4 +- source4/dsdb/samdb/ldb_modules/paged_results.c | 18 +- source4/dsdb/tests/python/asq.py | 171 ++++++++++++ source4/ldap_server/ldap_server.c | 108 +++++++- source4/libcli/ldap/ldap_client.c | 5 +- source4/libcli/ldap/ldap_controls.c | 48 ++-- source4/selftest/tests.py | 8 + 36 files changed, 1091 insertions(+), 71 deletions(-) create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxanonrequest.xml create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxauthrequest.xml create mode 100644 docs-xml/smbdotconf/ldap/ldapmaxsearchrequest.xml copy lib/ldb/ABI/{ldb-2.0.5.sigs => ldb-2.1.2.sigs} (100%) copy lib/ldb/ABI/{pyldb-util-2.1.0.sigs => pyldb-util-2.1.2.sigs} (100%) 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 python/samba/tests/ldap_raw.py create mode 100644 source4/dsdb/tests/python/asq.py Changeset truncated at 500 lines: diff --git a/VERSION b/VERSION index e651d0ad94b..2a84f16e464 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=12 -SAMBA_VERSION_RELEASE=2 +SAMBA_VERSION_RELEASE=3 ######################################################## # If a official release has a serious bug # diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 621fb63bac8..57498cdc8ed 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,3 +1,64 @@ + ============================== + Release Notes for Samba 4.12.2 + April 28, 2020 + ============================== + + +This is a security release in order to address the following defects: + +o CVE-2020-10700: Use-after-free in Samba AD DC LDAP Server with ASQ +o CVE-2020-10704: LDAP Denial of Service (stack overflow) in Samba AD DC + + +======= +Details +======= + +o CVE-2020-10700: + A client combining the 'ASQ' and 'Paged Results' LDAP controls can cause a + use-after-free in Samba's AD DC LDAP server. +o CVE-2020-10704: + A deeply nested filter in an un-authenticated LDAP search can exhaust the + LDAP server's stack memory causing a SIGSEGV. + +For more details, please refer to the security advisories. + + +Changes since 4.12.1 +-------------------- + +o Andrew Bartlett <abart...@samba.org> + * BUG 14331: CVE-2020-10700: Fix use-after-free in AD DC LDAP server when + ASQ and paged_results combined. + +o Gary Lockyer <g...@catalyst.net.nz> + * BUG 20454: CVE-2020-10704: Fix LDAP Denial of Service (stack overflow) in + Samba AD DC. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the Samba 4.1 and newer product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + ============================== Release Notes for Samba 4.12.1 April 07, 2020 @@ -70,8 +131,8 @@ database (https://bugzilla.samba.org/). ====================================================================== -Release notes for older releases follow: ----------------------------------------- +---------------------------------------------------------------------- + ============================== Release Notes for Samba 4.12.0 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/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/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 659169aca96..e3bcf7b9d0a 100644 --- a/lib/fuzzing/fuzz_ldap_decode.c +++ b/lib/fuzzing/fuzz_ldap_decode.c @@ -32,9 +32,19 @@ 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; - asn1 = asn1_init(mem_ctx); + /* + * Need to limit the max parse tree depth to 250 to prevent + * ASAN detecting stack overflows. + */ + asn1 = asn1_init(mem_ctx, 250); if (!asn1) { goto out; } @@ -46,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/ldb/ABI/ldb-2.0.5.sigs b/lib/ldb/ABI/ldb-2.1.2.sigs similarity index 100% copy from lib/ldb/ABI/ldb-2.0.5.sigs copy to lib/ldb/ABI/ldb-2.1.2.sigs diff --git a/lib/ldb/ABI/pyldb-util-2.1.0.sigs b/lib/ldb/ABI/pyldb-util-2.1.2.sigs similarity index 100% copy from lib/ldb/ABI/pyldb-util-2.1.0.sigs copy to lib/ldb/ABI/pyldb-util-2.1.2.sigs diff --git a/lib/ldb/modules/asq.c b/lib/ldb/modules/asq.c index 7482de826f0..4eba941ae0b 100644 --- a/lib/ldb/modules/asq.c +++ b/lib/ldb/modules/asq.c @@ -311,12 +311,9 @@ static int asq_build_multiple_requests(struct asq_context *ac, bool *terminated) static int asq_search_continue(struct asq_context *ac) { - struct ldb_context *ldb; bool terminated = false; int ret; - ldb = ldb_module_get_ctx(ac->module); - switch (ac->step) { case ASQ_SEARCH_BASE: @@ -328,7 +325,7 @@ static int asq_search_continue(struct asq_context *ac) ac->step = ASQ_SEARCH_MULTI; - return ldb_request(ldb, ac->reqs[ac->cur_req]); + return ldb_next_request(ac->module, ac->reqs[ac->cur_req]); case ASQ_SEARCH_MULTI: @@ -339,7 +336,7 @@ static int asq_search_continue(struct asq_context *ac) return asq_search_terminate(ac); } - return ldb_request(ldb, ac->reqs[ac->cur_req]); + return ldb_next_request(ac->module, ac->reqs[ac->cur_req]); } return LDB_ERR_OPERATIONS_ERROR; @@ -347,14 +344,11 @@ static int asq_search_continue(struct asq_context *ac) static int asq_search(struct ldb_module *module, struct ldb_request *req) { - struct ldb_context *ldb; struct ldb_request *base_req; struct ldb_control *control; struct asq_context *ac; int ret; - ldb = ldb_module_get_ctx(module); - /* check if there's an ASQ control */ control = ldb_request_get_control(req, LDB_CONTROL_ASQ_OID); if (control == NULL) { @@ -385,7 +379,7 @@ static int asq_search(struct ldb_module *module, struct ldb_request *req) ac->step = ASQ_SEARCH_BASE; - return ldb_request(ldb, base_req); + return ldb_next_request(ac->module, base_req); } static int asq_init(struct ldb_module *module) diff --git a/lib/ldb/wscript b/lib/ldb/wscript index 06c8922aa8d..17ec69bc194 100644 --- a/lib/ldb/wscript +++ b/lib/ldb/wscript @@ -1,7 +1,7 @@ #!/usr/bin/env python APPNAME = 'ldb' -VERSION = '2.1.1' +VERSION = '2.1.2' import sys, os diff --git a/lib/param/loadparm.c b/lib/param/loadparm.c index 611c1b240af..63291283905 100644 --- a/lib/param/loadparm.c +++ b/lib/param/loadparm.c @@ -3041,6 +3041,13 @@ struct loadparm_context *loadparm_init(TALLOC_CTX *mem_ctx) lpcfg_do_global_parameter(lp_ctx, "spotlight backend", "noindex"); + lpcfg_do_global_parameter( + 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)) { lp_ctx->flags[i] |= FLAG_DEFAULT; diff --git a/lib/util/asn1.c b/lib/util/asn1.c index 51da5424956..32d7981d28f 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; } @@ -480,6 +484,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) { @@ -487,6 +496,7 @@ bool asn1_load(struct asn1_data *data, DATA_BLOB blob) return false; } data->length = blob.length; + data->max_depth = max_depth; return true; } @@ -637,6 +647,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; @@ -693,6 +713,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; @@ -1103,9 +1126,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) @@ -1131,3 +1159,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 ddd69863574..de92a767f14 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); @@ -99,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/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 f609bf278e4..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,12 +233,15 @@ static bool cldap_socket_recv_dgram(struct cldap_socket *c, void *p; struct cldap_search_state *search; NTSTATUS status; -- Samba Shared Repository