From edc1f6e252d0f151c9611f8c5c27d843c18e1d0e Mon Sep 17 00:00:00 2001 From: eaglegai Date: Fri, 29 Oct 2021 10:38:59 +0800 Subject: [PATCH] backport fo fix fuzz error: idl: drsuapi_DsaAddressListItem_V1 limit recursion idl: limit recurion on recursive-elements lib: ldb Limit depth of ldb_parse_tree librpc: ndr add recursion check macros librpc: ndr Heap-buffer-overflow in lzxpress_decompress librpc: ndr NDR_PULL_ALIGN check for unsigned overflow lzxpress: add bounds checking to lzxpress decompress lzxpress: avoid technically undefined shift pidl: Add recursive depth checks utils: asn1 avoid undefined behaviour witness: idl fix length calculation for witness_IPaddrInfoList --- ...saAddressListItem_V1-limit-recursion.patch | 35 ++ ...limit-recurion-on-recursive-elements.patch | 126 ++++++++ ...ib-ldb-Limit-depth-of-ldb_parse_tree.patch | 300 ++++++++++++++++++ ...ffer-overflow-in-lzxpress_decompress.patch | 208 ++++++++++++ ...LL_ALIGN-check-for-unsigned-overflow.patch | 40 +++ ...ibrpc-ndr-add-recursion-check-macros.patch | 277 ++++++++++++++++ ...unds-checking-to-lzxpress_decompress.patch | 110 +++++++ ...ss-avoid-technically-undefined-shift.patch | 35 ++ ...port-pidl-Add-recursive-depth-checks.patch | 52 +++ ...utils-asn1-avoid-undefined-behaviour.patch | 38 +++ ...lculation-for-witness_IPaddrInfoList.patch | 50 +++ samba.spec | 30 +- 12 files changed, 1300 insertions(+), 1 deletion(-) create mode 100644 backport-idl-drsuapi_DsaAddressListItem_V1-limit-recursion.patch create mode 100644 backport-idl-limit-recurion-on-recursive-elements.patch create mode 100644 backport-lib-ldb-Limit-depth-of-ldb_parse_tree.patch create mode 100644 backport-librpc-ndr-Heap-buffer-overflow-in-lzxpress_decompress.patch create mode 100644 backport-librpc-ndr-NDR_PULL_ALIGN-check-for-unsigned-overflow.patch create mode 100644 backport-librpc-ndr-add-recursion-check-macros.patch create mode 100644 backport-lzxpress-add-bounds-checking-to-lzxpress_decompress.patch create mode 100644 backport-lzxpress-avoid-technically-undefined-shift.patch create mode 100644 backport-pidl-Add-recursive-depth-checks.patch create mode 100644 backport-utils-asn1-avoid-undefined-behaviour.patch create mode 100644 backport-witness-idl-fix-length-calculation-for-witness_IPaddrInfoList.patch diff --git a/backport-idl-drsuapi_DsaAddressListItem_V1-limit-recursion.patch b/backport-idl-drsuapi_DsaAddressListItem_V1-limit-recursion.patch new file mode 100644 index 0000000..c44b4d4 --- /dev/null +++ b/backport-idl-drsuapi_DsaAddressListItem_V1-limit-recursion.patch @@ -0,0 +1,35 @@ +From 2f8c3b62266b729b47d5ba25f1966786c1af0e5f Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Thu, 30 Jan 2020 08:52:34 +1300 +Subject: [PATCH] idl: drsuapi_DsaAddressListItem_V1 limit recursion + +Limit number of drsuapi_DsaAddressListItem_V1 elements to 1024 + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19820 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14254 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + librpc/idl/drsuapi.idl | 2 +- + 1 files changed, 1 insertion(+), 1 deletions(-) + delete mode 100644 selftest/knownfail.d/bug-14254 + +diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl +index 2aaae8dce59..04725276121 100644 +--- a/librpc/idl/drsuapi.idl ++++ b/librpc/idl/drsuapi.idl +@@ -1452,7 +1452,7 @@ interface drsuapi + /* list of network names of the DCs + * to which the referral is directed */ + typedef struct { +- drsuapi_DsaAddressListItem_V1 *next; ++ [max_recursion(1024)] drsuapi_DsaAddressListItem_V1 *next; + lsa_String *address; + } drsuapi_DsaAddressListItem_V1; + +-- +GitLab + diff --git a/backport-idl-limit-recurion-on-recursive-elements.patch b/backport-idl-limit-recurion-on-recursive-elements.patch new file mode 100644 index 0000000..150db31 --- /dev/null +++ b/backport-idl-limit-recurion-on-recursive-elements.patch @@ -0,0 +1,126 @@ +From 575d39048e3b4f619d65d65303ac809c40c5d495 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Fri, 7 Feb 2020 15:18:45 +1300 +Subject: [PATCH] idl: limit recurion on recursive elements + +Limit the max_recursion on self recursive definitions in the idl to +20,000. This value is hopefully large eneough to not impact normal +operation, but small eneough to prevent stack over flow issues. + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19820 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14254 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett + +Autobuild-User(master): Andrew Bartlett +Autobuild-Date(master): Thu Feb 27 02:29:21 UTC 2020 on sn-devel-184 +--- + librpc/idl/drsblobs.idl | 2 +- + librpc/idl/drsuapi.idl | 12 ++++++++---- + librpc/idl/ioctl.idl | 2 +- + source3/librpc/idl/secrets.idl | 2 +- + source3/librpc/idl/smbXsrv.idl | 2 +- + 5 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/librpc/idl/drsblobs.idl b/librpc/idl/drsblobs.idl +index 072546a4369..b096b671c80 100644 +--- a/librpc/idl/drsblobs.idl ++++ b/librpc/idl/drsblobs.idl +@@ -579,7 +579,7 @@ interface drsblobs { + } ExtendedErrorParam; + + typedef [public] struct { +- ExtendedErrorInfo *next; ++ [max_recursion(20000)] ExtendedErrorInfo *next; + ExtendedErrorComputerName computer_name; + hyper pid; + NTTIME time; +diff --git a/librpc/idl/drsuapi.idl b/librpc/idl/drsuapi.idl +index 04725276121..db00eb8639e 100644 +--- a/librpc/idl/drsuapi.idl ++++ b/librpc/idl/drsuapi.idl +@@ -690,7 +690,8 @@ interface drsuapi + } drsuapi_DsReplicaMetaDataCtr; + + typedef [public,noprint] struct { +- drsuapi_DsReplicaObjectListItemEx *next_object; ++ [max_recursion(20000)] ++ drsuapi_DsReplicaObjectListItemEx *next_object; + drsuapi_DsReplicaObject object; + boolean32 is_nc_prefix; + GUID *parent_object_guid; +@@ -1308,7 +1309,8 @@ interface drsuapi + /*****************/ + /* Function 0x11 */ + typedef [public,noprint] struct { +- drsuapi_DsReplicaObjectListItem *next_object; ++ [max_recursion(20000)] ++ drsuapi_DsReplicaObjectListItem *next_object; + drsuapi_DsReplicaObject object; + } drsuapi_DsReplicaObjectListItem; + +@@ -1408,7 +1410,8 @@ interface drsuapi + } drsuapi_DsAddEntry_AttrErr_V1; + + typedef [noprint] struct { +- drsuapi_DsAddEntry_AttrErrListItem_V1 *next; ++ [max_recursion(20000)] ++ drsuapi_DsAddEntry_AttrErrListItem_V1 *next; + drsuapi_DsAddEntry_AttrErr_V1 err_data; + } drsuapi_DsAddEntry_AttrErrListItem_V1; + +@@ -1464,7 +1467,8 @@ interface drsuapi + drsuapi_DsAddEntry_RefType ref_type; + uint16 addr_list_count; + drsuapi_DsaAddressListItem_V1 *addr_list; +- drsuapi_DsAddEntry_RefErrListItem_V1 *next; ++ [max_recursion(20000)] ++ drsuapi_DsAddEntry_RefErrListItem_V1 *next; + boolean32 is_choice_set; + drsuapi_DsAddEntry_ChoiceType choice; + } drsuapi_DsAddEntry_RefErrListItem_V1; +diff --git a/librpc/idl/ioctl.idl b/librpc/idl/ioctl.idl +index ba68fbcb8f6..390e8562f69 100644 +--- a/librpc/idl/ioctl.idl ++++ b/librpc/idl/ioctl.idl +@@ -151,7 +151,7 @@ interface netinterface + } fsctl_sockaddr_storage; + + typedef [public,relative_base,noprint] struct { +- [relative] fsctl_net_iface_info *next; ++ [relative,max_recursion(20000)] fsctl_net_iface_info *next; + uint32 ifindex; + fsctl_net_iface_capability capability; + [value(0)] uint32 reserved; +diff --git a/source3/librpc/idl/secrets.idl b/source3/librpc/idl/secrets.idl +index 2c06fa6990d..186d925e45e 100644 +--- a/source3/librpc/idl/secrets.idl ++++ b/source3/librpc/idl/secrets.idl +@@ -100,7 +100,7 @@ import "misc.idl", "samr.idl", "lsa.idl", "netlogon.idl", "security.idl"; + + NTTIME password_last_change; + hyper password_changes; +- secrets_domain_info1_change *next_change; ++ [max_recursion(20000)] secrets_domain_info1_change *next_change; + + [ref] secrets_domain_info1_password *password; + secrets_domain_info1_password *old_password; +diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl +index c6ce9c48789..4d9249fb3bb 100644 +--- a/source3/librpc/idl/smbXsrv.idl ++++ b/source3/librpc/idl/smbXsrv.idl +@@ -267,7 +267,7 @@ interface smbXsrv + + typedef struct { + [ignore] smbXsrv_session_auth0 *prev; +- smbXsrv_session_auth0 *next; ++ [max_recursion(20000)] smbXsrv_session_auth0 *next; + [ignore] smbXsrv_session *session; + [ignore] smbXsrv_connection *connection; + [ignore] gensec_security *gensec; +-- +GitLab + diff --git a/backport-lib-ldb-Limit-depth-of-ldb_parse_tree.patch b/backport-lib-ldb-Limit-depth-of-ldb_parse_tree.patch new file mode 100644 index 0000000..f202693 --- /dev/null +++ b/backport-lib-ldb-Limit-depth-of-ldb_parse_tree.patch @@ -0,0 +1,300 @@ +From a699256f438527455aaff6c73c88ee87ac7083ef Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Tue, 21 Apr 2020 15:37:40 +1200 +Subject: [PATCH] lib ldb: Limit depth of ldb_parse_tree + +Limit the number of nested conditionals allowed by ldb_parse tree to +128, to avoid potential stack overflow issues. + +Credit Oss-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19508 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett + +Autobuild-User(master): Gary Lockyer +Autobuild-Date(master): Sun May 10 23:21:08 UTC 2020 on sn-devel-184 +--- + lib/ldb/common/ldb_parse.c | 72 +++++++++++++++++++++++------ + lib/ldb/tests/ldb_parse_test.c | 83 +++++++++++++++++++++++++++++++++- + 2 files changed, 140 insertions(+), 15 deletions(-) + +diff --git a/lib/ldb/common/ldb_parse.c b/lib/ldb/common/ldb_parse.c +index 452c5830ed5..7e15206b168 100644 +--- a/lib/ldb/common/ldb_parse.c ++++ b/lib/ldb/common/ldb_parse.c +@@ -43,6 +43,16 @@ + #include "ldb_private.h" + #include "system/locale.h" + ++/* ++ * Maximum depth of the filter parse tree, the value chosen is small enough to ++ * avoid triggering ASAN stack overflow checks. But large enough to be useful. ++ * ++ * On Windows clients the maximum number of levels of recursion allowed is 100. ++ * In the LDAP server, Windows restricts clients to 512 nested ++ * (eg) OR statements. ++ */ ++#define LDB_MAX_PARSE_TREE_DEPTH 128 ++ + static int ldb_parse_hex2char(const char *x) + { + if (isxdigit(x[0]) && isxdigit(x[1])) { +@@ -231,7 +241,11 @@ static struct ldb_val **ldb_wildcard_decode(TALLOC_CTX *mem_ctx, const char *str + return ret; + } + +-static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s); ++static struct ldb_parse_tree *ldb_parse_filter( ++ TALLOC_CTX *mem_ctx, ++ const char **s, ++ unsigned depth, ++ unsigned max_depth); + + + /* +@@ -498,7 +512,11 @@ static struct ldb_parse_tree *ldb_parse_simple(TALLOC_CTX *mem_ctx, const char * + ::= '|' + ::= | + */ +-static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const char **s) ++static struct ldb_parse_tree *ldb_parse_filterlist( ++ TALLOC_CTX *mem_ctx, ++ const char **s, ++ unsigned depth, ++ unsigned max_depth) + { + struct ldb_parse_tree *ret, *next; + enum ldb_parse_op op; +@@ -533,7 +551,8 @@ static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const ch + return NULL; + } + +- ret->u.list.elements[0] = ldb_parse_filter(ret->u.list.elements, &p); ++ ret->u.list.elements[0] = ++ ldb_parse_filter(ret->u.list.elements, &p, depth, max_depth); + if (!ret->u.list.elements[0]) { + talloc_free(ret); + return NULL; +@@ -547,7 +566,8 @@ static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const ch + break; + } + +- next = ldb_parse_filter(ret->u.list.elements, &p); ++ next = ldb_parse_filter( ++ ret->u.list.elements, &p, depth, max_depth); + if (next == NULL) { + /* an invalid filter element */ + talloc_free(ret); +@@ -576,7 +596,11 @@ static struct ldb_parse_tree *ldb_parse_filterlist(TALLOC_CTX *mem_ctx, const ch + /* + ::= '!' + */ +-static struct ldb_parse_tree *ldb_parse_not(TALLOC_CTX *mem_ctx, const char **s) ++static struct ldb_parse_tree *ldb_parse_not( ++ TALLOC_CTX *mem_ctx, ++ const char **s, ++ unsigned depth, ++ unsigned max_depth) + { + struct ldb_parse_tree *ret; + const char *p = *s; +@@ -593,7 +617,7 @@ static struct ldb_parse_tree *ldb_parse_not(TALLOC_CTX *mem_ctx, const char **s) + } + + ret->operation = LDB_OP_NOT; +- ret->u.isnot.child = ldb_parse_filter(ret, &p); ++ ret->u.isnot.child = ldb_parse_filter(ret, &p, depth, max_depth); + if (!ret->u.isnot.child) { + talloc_free(ret); + return NULL; +@@ -608,7 +632,11 @@ static struct ldb_parse_tree *ldb_parse_not(TALLOC_CTX *mem_ctx, const char **s) + parse a filtercomp + ::= | | | + */ +-static struct ldb_parse_tree *ldb_parse_filtercomp(TALLOC_CTX *mem_ctx, const char **s) ++static struct ldb_parse_tree *ldb_parse_filtercomp( ++ TALLOC_CTX *mem_ctx, ++ const char **s, ++ unsigned depth, ++ unsigned max_depth) + { + struct ldb_parse_tree *ret; + const char *p = *s; +@@ -617,15 +645,15 @@ static struct ldb_parse_tree *ldb_parse_filtercomp(TALLOC_CTX *mem_ctx, const ch + + switch (*p) { + case '&': +- ret = ldb_parse_filterlist(mem_ctx, &p); ++ ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth); + break; + + case '|': +- ret = ldb_parse_filterlist(mem_ctx, &p); ++ ret = ldb_parse_filterlist(mem_ctx, &p, depth, max_depth); + break; + + case '!': +- ret = ldb_parse_not(mem_ctx, &p); ++ ret = ldb_parse_not(mem_ctx, &p, depth, max_depth); + break; + + case '(': +@@ -641,21 +669,34 @@ static struct ldb_parse_tree *ldb_parse_filtercomp(TALLOC_CTX *mem_ctx, const ch + return ret; + } + +- + /* + ::= '(' ')' + */ +-static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char **s) ++static struct ldb_parse_tree *ldb_parse_filter( ++ TALLOC_CTX *mem_ctx, ++ const char **s, ++ unsigned depth, ++ unsigned max_depth) + { + struct ldb_parse_tree *ret; + const char *p = *s; + ++ /* ++ * Check the depth of the parse tree, and reject the input if ++ * max_depth exceeded. This avoids stack overflow ++ * issues. ++ */ ++ if (depth > max_depth) { ++ return NULL; ++ } ++ depth++; ++ + if (*p != '(') { + return NULL; + } + p++; + +- ret = ldb_parse_filtercomp(mem_ctx, &p); ++ ret = ldb_parse_filtercomp(mem_ctx, &p, depth, max_depth); + + if (*p != ')') { + return NULL; +@@ -679,6 +720,8 @@ static struct ldb_parse_tree *ldb_parse_filter(TALLOC_CTX *mem_ctx, const char * + */ + struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s) + { ++ unsigned depth = 0; ++ + while (s && isspace((unsigned char)*s)) s++; + + if (s == NULL || *s == 0) { +@@ -686,7 +729,8 @@ struct ldb_parse_tree *ldb_parse_tree(TALLOC_CTX *mem_ctx, const char *s) + } + + if (*s == '(') { +- return ldb_parse_filter(mem_ctx, &s); ++ return ldb_parse_filter( ++ mem_ctx, &s, depth, LDB_MAX_PARSE_TREE_DEPTH); + } + + return ldb_parse_simple(mem_ctx, &s); +diff --git a/lib/ldb/tests/ldb_parse_test.c b/lib/ldb/tests/ldb_parse_test.c +index a739d7795d1..d7442b954ea 100644 +--- a/lib/ldb/tests/ldb_parse_test.c ++++ b/lib/ldb/tests/ldb_parse_test.c +@@ -81,10 +81,91 @@ static void test_parse_filtertype(void **state) + test_roundtrip(ctx, " ", "(|(objectClass=*)(distinguishedName=*))"); + } + ++/* ++ * Test that a nested query with 128 levels of nesting is accepted ++ */ ++static void test_nested_filter_eq_limit(void **state) ++{ ++ struct test_ctx *ctx = ++ talloc_get_type_abort(*state, struct test_ctx); ++ ++ /* ++ * 128 nested clauses ++ */ ++ const char *nested_query = "" ++ "(|(!(|(&(|(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(&(|(|(|(|(|(|(!(|(!(|(|(|" ++ "(|(!(|(&(|(|(&(|(|(|(|(|(!(!(!(|" ++ "(|(!(|(&(|(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(&(|(|(|(!(|(|(&(|(|(|(|(|" ++ "(|(!(|(&(|(|(&(|(|(|(|(|(&(&(|(|" ++ "(|(!(|(&(|(|(|(|(|(|(!(|(|(|(|(|" ++ "(|(!(|(&(|(|(!(|(|(|(|(|(|(|(|(|" ++ "(a=b)" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))"; ++ ++ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, nested_query); ++ ++ assert_non_null(tree); ++ /* ++ * Check that we get the same query back ++ */ ++ test_roundtrip(ctx, nested_query, nested_query); ++} ++ ++/* ++ * Test that a nested query with 129 levels of nesting is rejected. ++ */ ++static void test_nested_filter_gt_limit(void **state) ++{ ++ struct test_ctx *ctx = ++ talloc_get_type_abort(*state, struct test_ctx); ++ ++ /* ++ * 129 nested clauses ++ */ ++ const char *nested_query = "" ++ "(|(!(|(|(&(|(|(|(|(&(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(!(|(|(|(|(!(|(|(|" ++ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(|(!(&(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(|(|(|(|(|(|(|(|(|" ++ "(|(!(|(|(&(|(|(|(|(|(|(|(|(&(|(|" ++ "(|" ++ "(a=b)" ++ ")" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))" ++ "))))))))))))))))"; ++ ++ struct ldb_parse_tree *tree = ldb_parse_tree(ctx, nested_query); ++ ++ assert_null(tree); ++} ++ + int main(int argc, const char **argv) + { + const struct CMUnitTest tests[] = { +- cmocka_unit_test_setup_teardown(test_parse_filtertype, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_parse_filtertype, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_nested_filter_eq_limit, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_nested_filter_gt_limit, setup, teardown), + }; + + cmocka_set_message_output(CM_OUTPUT_SUBUNIT); +-- +GitLab + diff --git a/backport-librpc-ndr-Heap-buffer-overflow-in-lzxpress_decompress.patch b/backport-librpc-ndr-Heap-buffer-overflow-in-lzxpress_decompress.patch new file mode 100644 index 0000000..18c2509 --- /dev/null +++ b/backport-librpc-ndr-Heap-buffer-overflow-in-lzxpress_decompress.patch @@ -0,0 +1,208 @@ +From ae6927e4f08dcea89729d8e54363e98effab6624 Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Fri, 24 Jan 2020 10:41:35 +1300 +Subject: [PATCH] librpc ndr: Heap-buffer-overflow in lzxpress_decompress + +Reproducer for oss-fuzz Issue 20083 + +Project: samba +Fuzzing Engine: libFuzzer +Fuzz Target: fuzz_ndr_drsuapi_TYPE_OUT +Job Type: libfuzzer_asan_samba +Platform Id: linux + +Crash Type: Heap-buffer-overflow READ 1 +Crash Address: 0x6040000002fd +Crash State: + lzxpress_decompress + ndr_pull_compression_xpress_chunk + ndr_pull_compression_start + +Sanitizer: address (ASAN) + +Recommended Security Severity: Medium + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20083 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14236 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + librpc/ndr/libndr.h | 5 +- + librpc/tests/test_ndr.c | 84 ++++++++++++++++++++++++++ + librpc/wscript_build | 8 +++ + python/samba/tests/blackbox/ndrdump.py | 13 ++++ + selftest/knownfail.d/bug-14236 | 1 + + source4/selftest/tests.py | 2 + + 6 files changed, 112 insertions(+), 1 deletion(-) + create mode 100644 librpc/tests/test_ndr.c + create mode 100644 selftest/knownfail.d/bug-14236 + +diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h +index 58ef517d363..b7cccf3dfc5 100644 +--- a/librpc/ndr/libndr.h ++++ b/librpc/ndr/libndr.h +@@ -309,7 +309,10 @@ enum ndr_compression_alg { + } while (0) + + #define NDR_PULL_NEED_BYTES(ndr, n) do { \ +- if (unlikely((n) > ndr->data_size || ndr->offset + (n) > ndr->data_size)) { \ ++ if (unlikely(\ ++ (n) > ndr->data_size || \ ++ ndr->offset + (n) > ndr->data_size || \ ++ ndr->offset + (n) < ndr->offset)) { \ + if (ndr->flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) { \ + uint32_t _available = ndr->data_size - ndr->offset; \ + uint32_t _missing = n - _available; \ +diff --git a/librpc/tests/test_ndr.c b/librpc/tests/test_ndr.c +new file mode 100644 +index 00000000000..1c074d71023 +--- /dev/null ++++ b/librpc/tests/test_ndr.c +@@ -0,0 +1,84 @@ ++/* ++ * Tests for librpc ndr functions ++ * ++ * 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 . ++ * ++ */ ++ ++/* ++ * from cmocka.c: ++ * These headers or their equivalents should be included prior to ++ * including ++ * this header file. ++ * ++ * #include ++ * #include ++ * #include ++ * ++ * This allows test applications to use custom definitions of C standard ++ * library functions and types. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "librpc/ndr/libndr.h" ++ ++/* ++ * Test NDR_PULL_NEED_BYTES integer overflow handling. ++ */ ++static enum ndr_err_code wrap_NDR_PULL_NEED_BYTES( ++ struct ndr_pull *ndr, ++ uint32_t bytes) { ++ ++ NDR_PULL_NEED_BYTES(ndr, bytes); ++ return NDR_ERR_SUCCESS; ++} ++ ++static void test_NDR_PULL_NEED_BYTES(void **state) ++{ ++ struct ndr_pull ndr = {0}; ++ enum ndr_err_code err; ++ ++ ndr.data_size = UINT32_MAX; ++ ndr.offset = UINT32_MAX -1; ++ ++ /* ++ * This will not cause an overflow ++ */ ++ err = wrap_NDR_PULL_NEED_BYTES(&ndr, 1); ++ assert_int_equal(NDR_ERR_SUCCESS, err); ++ ++ /* ++ * This will cause an overflow ++ * and (offset + n) will be less than data_size ++ */ ++ err = wrap_NDR_PULL_NEED_BYTES(&ndr, 2); ++ assert_int_equal(NDR_ERR_BUFSIZE, err); ++} ++ ++int main(int argc, const char **argv) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_NDR_PULL_NEED_BYTES), ++ }; ++ ++ cmocka_set_message_output(CM_OUTPUT_SUBUNIT); ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +diff --git a/librpc/wscript_build b/librpc/wscript_build +index 5eb78e6010a8..ec8697fbcc58 100644 +--- a/librpc/wscript_build ++++ b/librpc/wscript_build +@@ -698,3 +698,11 @@ bld.SAMBA_BINARY('test_ndr_string', + ndr_nbt + ''', + for_selftest=True) ++ ++bld.SAMBA_BINARY('test_ndr', ++ source='tests/test_ndr.c', ++ deps=''' ++ cmocka ++ ndr ++ ''', ++ for_selftest=True) +diff --git a/python/samba/tests/blackbox/ndrdump.py b/python/samba/tests/blackbox/ndrdump.py +index b3c837819b15..205519c3f8a6 100644 +--- a/python/samba/tests/blackbox/ndrdump.py ++++ b/python/samba/tests/blackbox/ndrdump.py +@@ -437,3 +437,16 @@ def test_fuzzed_drsuapi_DsGetNCChanges(self): + except BlackboxProcessError as e: + self.fail(e) + self.assertEqual(actual, expected) ++ ++ def test_ndrdump_fuzzed_ndr_compression(self): ++ expected = 'pull returned Buffer Size Error' ++ command = ( ++ "ndrdump drsuapi 3 out --base64-input " ++ "--input BwAAAAcAAAAGAAAAAwAgICAgICAJAAAAICAgIAkAAAAgIAAA//////8=") ++ try: ++ actual = self.check_exit_code(command, 2) ++ except BlackboxProcessError as e: ++ self.fail(e) ++ # check_output will return bytes ++ # convert expected to bytes for python 3 ++ self.assertRegex(actual.decode('utf8'), expected + '$') +diff --git a/selftest/knownfail.d/bug-14236 b/selftest/knownfail.d/bug-14236 +new file mode 100644 +index 00000000000..64b956997a6 +--- /dev/null ++++ b/selftest/knownfail.d/bug-14236 +@@ -0,0 +1 @@ ++^samba.tests.blackbox.ndrdump.samba.tests.blackbox.ndrdump.NdrDumpTests.test_ndrdump_fuzzed_ndr_compression +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index f570d35dfba..ab2c4f69da0 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -1334,6 +1334,8 @@ plantestsuite("libcli.drsuapi.repl_decrypt", "none", + [os.path.join(bindir(), "test_ldap_message")]) + plantestsuite("librpc.ndr.ndr_macros", "none", + [os.path.join(bindir(), "test_ndr_macros")]) ++plantestsuite("librpc.ndr.ndr", "none", ++ [os.path.join(bindir(), "test_ndr")]) + + # process restart and limit tests, these break the environment so need to run + # in their own specific environment +-- +GitLab + diff --git a/backport-librpc-ndr-NDR_PULL_ALIGN-check-for-unsigned-overflow.patch b/backport-librpc-ndr-NDR_PULL_ALIGN-check-for-unsigned-overflow.patch new file mode 100644 index 0000000..3b737a1 --- /dev/null +++ b/backport-librpc-ndr-NDR_PULL_ALIGN-check-for-unsigned-overflow.patch @@ -0,0 +1,40 @@ +From 6d05fb3ea772c3642624ec6e0fb4e8d099bcdb8e Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Wed, 22 Jan 2020 14:16:02 +1300 +Subject: [PATCH] librpc ndr: NDR_PULL_ALIGN check for unsigned overflow + +Handle uint32 overflow in NDR_PULL_ALIGN + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20083 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14236 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + librpc/ndr/libndr.h | 7 +++++++ + selftest/knownfail.d/bug-14236 | 1 - + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h +index b7cccf3dfc5..c2c7e263049 100644 +--- a/librpc/ndr/libndr.h ++++ b/librpc/ndr/libndr.h +@@ -331,6 +331,13 @@ enum ndr_compression_alg { + if (unlikely(ndr->flags & LIBNDR_FLAG_PAD_CHECK)) { \ + ndr_check_padding(ndr, n); \ + } \ ++ if(unlikely( \ ++ ((ndr->offset + (n-1)) & (~(n-1))) < ndr->offset)) {\ ++ return ndr_pull_error( \ ++ ndr, \ ++ NDR_ERR_BUFSIZE, \ ++ "Pull align (overflow) %u", (unsigned)n); \ ++ } \ + ndr->offset = (ndr->offset + (n-1)) & ~(n-1); \ + } \ + if (unlikely(ndr->offset > ndr->data_size)) { \ +-- +GitLab + diff --git a/backport-librpc-ndr-add-recursion-check-macros.patch b/backport-librpc-ndr-add-recursion-check-macros.patch new file mode 100644 index 0000000..e65a3f2 --- /dev/null +++ b/backport-librpc-ndr-add-recursion-check-macros.patch @@ -0,0 +1,277 @@ +From ba518a1debbe2dd8231ba2fb9bbb07eef743d86f Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Thu, 30 Jan 2020 08:49:07 +1300 +Subject: [PATCH] librpc ndr: add recursion check macros + +Add macros to check the recursion depth. + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19280 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14254 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + librpc/ndr/libndr.h | 37 ++++++++- + librpc/ndr/ndr.c | 2 + + librpc/tests/test_ndr_macros.c | 138 +++++++++++++++++++++++++++++++++ + librpc/wscript_build | 9 +++ + source4/selftest/tests.py | 2 + + 5 files changed, 187 insertions(+), 1 deletion(-) + create mode 100644 librpc/tests/test_ndr_macros.c + +diff --git a/librpc/ndr/libndr.h b/librpc/ndr/libndr.h +index 8d407c40e43..fd87db928ed 100644 +--- a/librpc/ndr/libndr.h ++++ b/librpc/ndr/libndr.h +@@ -79,6 +79,14 @@ struct ndr_pull { + /* this is used to ensure we generate unique reference IDs + between request and reply */ + uint32_t ptr_count; ++ uint32_t recursion_depth; ++ /* ++ * The global maximum depth for recursion. When set it overrides the ++ * value supplied by the max_recursion idl attribute. This is needed ++ * for fuzzing as ASAN uses a low threshold for stack depth to check ++ * for stack overflow. ++ */ ++ uint32_t global_max_recursion; + }; + + /* structure passed to functions that generate NDR formatted data */ +@@ -249,7 +257,9 @@ enum ndr_err_code { + NDR_ERR_UNREAD_BYTES, + NDR_ERR_NDR64, + NDR_ERR_FLAGS, +- NDR_ERR_INCOMPLETE_BUFFER ++ NDR_ERR_INCOMPLETE_BUFFER, ++ NDR_ERR_MAX_RECURSION_EXCEEDED, ++ NDR_ERR_UNDERFLOW + }; + + #define NDR_ERR_CODE_IS_SUCCESS(x) (x == NDR_ERR_SUCCESS) +@@ -357,6 +367,31 @@ enum ndr_compression_alg { + } \ + } while(0) + ++#define NDR_RECURSION_CHECK(ndr, d) do { \ ++ uint32_t _ndr_min_ = (d); \ ++ if (ndr->global_max_recursion && ndr->global_max_recursion < (d)) { \ ++ _ndr_min_ = ndr->global_max_recursion; \ ++ } \ ++ ndr->recursion_depth++; \ ++ if (unlikely(ndr->recursion_depth > _ndr_min_)) { \ ++ return ndr_pull_error( \ ++ ndr, \ ++ NDR_ERR_MAX_RECURSION_EXCEEDED, \ ++ "Depth of recursion exceeds (%u)", \ ++ (unsigned) d); \ ++ } \ ++} while (0) ++ ++#define NDR_RECURSION_UNWIND(ndr) do { \ ++ if (unlikely(ndr->recursion_depth == 0)) { \ ++ return ndr_pull_error( \ ++ ndr, \ ++ NDR_ERR_UNDERFLOW, \ ++ "ndr_pull.recursion_depth is 0"); \ ++ } \ ++ ndr->recursion_depth--; \ ++} while (0) ++ + /* these are used to make the error checking on each element in libndr + less tedious, hopefully making the code more readable */ + #define NDR_CHECK(call) do { \ +diff --git a/librpc/ndr/ndr.c b/librpc/ndr/ndr.c +index f96a0bca08b..afe22a28602 100644 +--- a/librpc/ndr/ndr.c ++++ b/librpc/ndr/ndr.c +@@ -1950,6 +1950,8 @@ static const struct { + { NDR_ERR_UNREAD_BYTES, "Unread Bytes" }, + { NDR_ERR_NDR64, "NDR64 assertion error" }, + { NDR_ERR_INCOMPLETE_BUFFER, "Incomplete Buffer" }, ++ { NDR_ERR_MAX_RECURSION_EXCEEDED, "Maximum Recursion Exceeded" }, ++ { NDR_ERR_UNDERFLOW, "Underflow" }, + { 0, NULL } + }; + +diff --git a/librpc/tests/test_ndr_macros.c b/librpc/tests/test_ndr_macros.c +new file mode 100644 +index 00000000000..0cd20d3e8f3 +--- /dev/null ++++ b/librpc/tests/test_ndr_macros.c +@@ -0,0 +1,138 @@ ++/* ++ * Tests for librpc ndr functions ++ * ++ * 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 . ++ * ++ */ ++ ++/* ++ * from cmocka.c: ++ * These headers or their equivalents should be included prior to ++ * including ++ * this header file. ++ * ++ * #include ++ * #include ++ * #include ++ * ++ * This allows test applications to use custom definitions of C standard ++ * library functions and types. ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++ ++#include "librpc/ndr/libndr.h" ++ ++/* ++ * Test NDR_RECURSION_CHECK. ++ */ ++static enum ndr_err_code wrap_NDR_RECURSION_CHECK( ++ struct ndr_pull *ndr, ++ uint32_t bytes) { ++ ++ NDR_RECURSION_CHECK(ndr, bytes); ++ return NDR_ERR_SUCCESS; ++} ++ ++static void test_NDR_RECURSION_CHECK(void **state) ++{ ++ struct ndr_pull ndr = {0}; ++ enum ndr_err_code err; ++ ++ ++ ndr.global_max_recursion = 0; ++ ndr.recursion_depth = 42; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 43); ++ assert_int_equal(NDR_ERR_SUCCESS, err); ++ assert_int_equal(43, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 0; ++ ndr.recursion_depth = 43; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 43); ++ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err); ++ assert_int_equal(44, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 0; ++ ndr.recursion_depth = 44; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 43); ++ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err); ++ assert_int_equal(45, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 5; ++ ndr.recursion_depth = 5; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 20); ++ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err); ++ assert_int_equal(6, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 5; ++ ndr.recursion_depth = 4; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 20); ++ assert_int_equal(NDR_ERR_SUCCESS, err); ++ assert_int_equal(5, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 20; ++ ndr.recursion_depth = 5; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 5); ++ assert_int_equal(NDR_ERR_MAX_RECURSION_EXCEEDED, err); ++ assert_int_equal(6, ndr.recursion_depth); ++ ++ ndr.global_max_recursion = 20; ++ ndr.recursion_depth = 4; ++ err = wrap_NDR_RECURSION_CHECK(&ndr, 5); ++ assert_int_equal(NDR_ERR_SUCCESS, err); ++ assert_int_equal(5, ndr.recursion_depth); ++} ++ ++/* ++ * Test NDR_RECURSION_RETURN. ++ */ ++static enum ndr_err_code wrap_NDR_RECURSION_UNWIND( ++ struct ndr_pull *ndr) { ++ ++ NDR_RECURSION_UNWIND(ndr); ++ return NDR_ERR_SUCCESS; ++} ++ ++static void test_NDR_RECURSION_UNWIND(void **state) ++{ ++ struct ndr_pull ndr = {0}; ++ enum ndr_err_code err; ++ ++ ndr.recursion_depth = 5; ++ err = wrap_NDR_RECURSION_UNWIND(&ndr); ++ assert_int_equal(NDR_ERR_SUCCESS, err); ++ assert_int_equal(4, ndr.recursion_depth); ++ ++ ndr.recursion_depth = 0; ++ err = wrap_NDR_RECURSION_UNWIND(&ndr); ++ assert_int_equal(NDR_ERR_UNDERFLOW, err); ++ assert_int_equal(0, ndr.recursion_depth); ++ ++} ++int main(int argc, const char **argv) ++{ ++ const struct CMUnitTest tests[] = { ++ cmocka_unit_test(test_NDR_RECURSION_CHECK), ++ cmocka_unit_test(test_NDR_RECURSION_UNWIND), ++ }; ++ ++ cmocka_set_message_output(CM_OUTPUT_SUBUNIT); ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +diff --git a/librpc/wscript_build b/librpc/wscript_build +index ec8697fbcc5..f0bf7f7785e 100644 +--- a/librpc/wscript_build ++++ b/librpc/wscript_build +@@ -690,6 +690,14 @@ bld.SAMBA_SUBSYSTEM('NDR_FSRVP_STATE', + # + # Cmocka tests + # ++bld.SAMBA_BINARY('test_ndr_macros', ++ source='tests/test_ndr_macros.c', ++ deps=''' ++ cmocka ++ ndr ++ ''', ++ for_selftest=True) ++ + bld.SAMBA_BINARY('test_ndr_string', + source='tests/test_ndr_string.c', + deps=''' +diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py +index 5cdb3d27b77..389a142db7d 100755 +--- a/source4/selftest/tests.py ++++ b/source4/selftest/tests.py +@@ -1346,6 +1346,8 @@ plantestsuite("librpc.ndr.ndr_string", "none", + [os.path.join(bindir(), "test_ndr_dns_nbt")]) + plantestsuite("libcli.ldap.ldap_message", "none", + [os.path.join(bindir(), "test_ldap_message")]) ++plantestsuite("librpc.ndr.ndr_macros", "none", ++ [os.path.join(bindir(), "test_ndr_macros")]) + + # process restart and limit tests, these break the environment so need to run + # in their own specific environment +-- +GitLab + diff --git a/backport-lzxpress-add-bounds-checking-to-lzxpress_decompress.patch b/backport-lzxpress-add-bounds-checking-to-lzxpress_decompress.patch new file mode 100644 index 0000000..92dbaac --- /dev/null +++ b/backport-lzxpress-add-bounds-checking-to-lzxpress_decompress.patch @@ -0,0 +1,110 @@ +From a97c78fb221a2f1aaca2effdb44c51e4f78ddd93 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Thu, 7 Nov 2019 10:03:36 +0100 +Subject: [PATCH] lzxpress: add bounds checking to lzxpress_decompress() + +lzxpress_decompress() would wander past the end of the array in +numerous locations. + +Credit to OSS-Fuzz. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14190 +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19382 +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=20083 +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22485 +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22667 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Douglas Bagnall + +Autobuild-User(master): Douglas Bagnall +Autobuild-Date(master): Sun Aug 9 00:30:26 UTC 2020 on sn-devel-184 +--- + lib/compression/lzxpress.c | 32 ++++++++++++++++++++++++++++++-- + 1 file changed, 30 insertions(+), 2 deletions(-) + +diff --git a/lib/compression/lzxpress.c b/lib/compression/lzxpress.c +index 024aba4c2ce..d8326304455 100644 +--- a/lib/compression/lzxpress.c ++++ b/lib/compression/lzxpress.c +@@ -252,8 +252,24 @@ ssize_t lzxpress_decompress(const uint8_t *input, + offset = 0; + nibble_index = 0; + ++#define __CHECK_BYTES(__size, __index, __needed) do { \ ++ if (unlikely(__index >= __size)) { \ ++ return -1; \ ++ } else { \ ++ uint32_t __avail = __size - __index; \ ++ if (unlikely(__needed > __avail)) { \ ++ return -1; \ ++ } \ ++ } \ ++} while(0) ++#define CHECK_INPUT_BYTES(__needed) \ ++ __CHECK_BYTES(input_size, input_index, __needed) ++#define CHECK_OUTPUT_BYTES(__needed) \ ++ __CHECK_BYTES(max_output_size, output_index, __needed) ++ + do { + if (indicator_bit == 0) { ++ CHECK_INPUT_BYTES(4); + indicator = PULL_LE_UINT32(input, input_index); + input_index += sizeof(uint32_t); + indicator_bit = 32; +@@ -266,10 +282,13 @@ ssize_t lzxpress_decompress(const uint8_t *input, + * check whether the 4th bit of the value in indicator is set + */ + if (((indicator >> indicator_bit) & 1) == 0) { ++ CHECK_INPUT_BYTES(1); ++ CHECK_OUTPUT_BYTES(1); + output[output_index] = input[input_index]; + input_index += sizeof(uint8_t); + output_index += sizeof(uint8_t); + } else { ++ CHECK_INPUT_BYTES(2); + length = PULL_LE_UINT16(input, input_index); + input_index += sizeof(uint16_t); + offset = length / 8; +@@ -277,6 +296,7 @@ ssize_t lzxpress_decompress(const uint8_t *input, + + if (length == 7) { + if (nibble_index == 0) { ++ CHECK_INPUT_BYTES(1); + nibble_index = input_index; + length = input[input_index] % 16; + input_index += sizeof(uint8_t); +@@ -286,9 +306,11 @@ ssize_t lzxpress_decompress(const uint8_t *input, + } + + if (length == 15) { ++ CHECK_INPUT_BYTES(1); + length = input[input_index]; + input_index += sizeof(uint8_t); + if (length == 255) { ++ CHECK_INPUT_BYTES(2); + length = PULL_LE_UINT16(input, input_index); + input_index += sizeof(uint16_t); + length -= (15 + 7); +@@ -299,10 +321,16 @@ ssize_t lzxpress_decompress(const uint8_t *input, + } + + length += 3; ++ if (length == 0) { ++ return -1; ++ } + +- do { +- if ((output_index >= max_output_size) || ((offset + 1) > output_index)) break; ++ if (offset >= output_index) { ++ return -1; ++ } ++ CHECK_OUTPUT_BYTES(length); + ++ do { + output[output_index] = output[output_index - offset - 1]; + + output_index += sizeof(uint8_t); +-- +GitLab + diff --git a/backport-lzxpress-avoid-technically-undefined-shift.patch b/backport-lzxpress-avoid-technically-undefined-shift.patch new file mode 100644 index 0000000..4446971 --- /dev/null +++ b/backport-lzxpress-avoid-technically-undefined-shift.patch @@ -0,0 +1,35 @@ +From 0c461f3bd589764c496b530f698e313df50667e6 Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Thu, 6 Aug 2020 17:17:01 +1200 +Subject: [PATCH] lzxpress: avoid technically undefined shift + +UBSAN: + + runtime error: left shift of 1 by 31 places cannot be represented in type 'int' + +Credit to OSS-fuzz. + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22283 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Gary Lockyer + +Autobuild-User(master): Jeremy Allison +Autobuild-Date(master): Mon Aug 31 22:31:13 UTC 2020 on sn-devel-184 +--- + lib/compression/lzxpress.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/compression/lzxpress.c b/lib/compression/lzxpress.c +index d8326304455c..3453dd36f2aa 100644 +--- a/lib/compression/lzxpress.c ++++ b/lib/compression/lzxpress.c +@@ -180,7 +180,7 @@ ssize_t lzxpress_compress(const uint8_t *uncompressed, + } + } + +- indic |= 1 << (32 - ((indic_bit % 32) + 1)); ++ indic |= 1U << (32 - ((indic_bit % 32) + 1)); + + if (best_len > 9) { + if (nibble_index == 0) { diff --git a/backport-pidl-Add-recursive-depth-checks.patch b/backport-pidl-Add-recursive-depth-checks.patch new file mode 100644 index 0000000..0007965 --- /dev/null +++ b/backport-pidl-Add-recursive-depth-checks.patch @@ -0,0 +1,52 @@ +From 5d323f2a2e36c23a007d93394f25df0f3d30942d Mon Sep 17 00:00:00 2001 +From: Gary Lockyer +Date: Thu, 30 Jan 2020 08:51:47 +1300 +Subject: [PATCH] pidl: Add recursive depth checks. + +Add new parameter to elements "max_recursion" and modify pidl to call +NDR_RECURSION_CHECK and NDR_RECURSION_UNWIND for element tagged with +that attribute. + +Credit to OSS-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=19820 +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14254 + +Signed-off-by: Gary Lockyer +Reviewed-by: Andrew Bartlett +--- + pidl/lib/Parse/Pidl/NDR.pm | 1 + + pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm | 7 +++++++ + 2 files changed, 8 insertions(+) + +diff --git a/pidl/lib/Parse/Pidl/NDR.pm b/pidl/lib/Parse/Pidl/NDR.pm +index 44338a1298d8..d17d0b404ed0 100644 +--- a/pidl/lib/Parse/Pidl/NDR.pm ++++ b/pidl/lib/Parse/Pidl/NDR.pm +@@ -1101,6 +1101,7 @@ my %property_list = ( + "gensize" => ["TYPEDEF", "STRUCT", "UNION"], + "value" => ["ELEMENT"], + "flag" => ["ELEMENT", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"], ++ "max_recursion" => ["ELEMENT"], + + # generic + "public" => ["FUNCTION", "TYPEDEF", "STRUCT", "UNION", "ENUM", "BITMAP", "PIPE"], +diff --git a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm +index 0d58cb5f03d5..119590f66969 100644 +--- a/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm ++++ b/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm +@@ -993,7 +993,14 @@ sub ParseDataPull($$$$$$$) + + $var_name = get_pointer_to($var_name); + ++ if (my $depth = has_property($e, "max_recursion")) { ++ my $d = parse_int($depth); ++ $self->pidl("NDR_RECURSION_CHECK($ndr, $d);"); ++ } + $self->pidl("NDR_CHECK(".TypeFunctionName("ndr_pull", $l->{DATA_TYPE})."($ndr, $ndr_flags, $var_name));"); ++ if (has_property($e, "max_recursion")) { ++ $self->pidl("NDR_RECURSION_UNWIND($ndr);"); ++ } + + my $pl = GetPrevLevel($e, $l); + diff --git a/backport-utils-asn1-avoid-undefined-behaviour.patch b/backport-utils-asn1-avoid-undefined-behaviour.patch new file mode 100644 index 0000000..5f2278b --- /dev/null +++ b/backport-utils-asn1-avoid-undefined-behaviour.patch @@ -0,0 +1,38 @@ +From ed9abf94b3167a1a61b5da163e9b07b06c8a457b Mon Sep 17 00:00:00 2001 +From: Douglas Bagnall +Date: Sun, 6 Sep 2020 09:35:49 +1200 +Subject: [PATCH] utils/asn1: avoid undefined behaviour warning + +UBSAN does not like an int >= 1<<24 being shifted left. +We check the overflow in the very next line. + +Credit to OSS-Fuzz. + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=25436 + +Signed-off-by: Douglas Bagnall +Reviewed-by: Andrew Bartlett + +Autobuild-User(master): Andrew Bartlett +Autobuild-Date(master): Fri Sep 11 05:05:59 UTC 2020 on sn-devel-184 +--- + lib/util/asn1.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/lib/util/asn1.c b/lib/util/asn1.c +index 6b1b4bc2877f..9ab9e1b08449 100644 +--- a/lib/util/asn1.c ++++ b/lib/util/asn1.c +@@ -1071,7 +1071,11 @@ bool asn1_read_enumerated(struct asn1_data *data, int *v) + if (!asn1_read_uint8(data, &b)) { + return false; + } +- *v = (*v << 8) + b; ++ /* ++ * To please/fool the Undefined Behaviour Sanitizer we cast to ++ * unsigned for the left shift. ++ */ ++ *v = ((unsigned int)*v << 8) + b; + } + return asn1_end_tag(data); + } diff --git a/backport-witness-idl-fix-length-calculation-for-witness_IPaddrInfoList.patch b/backport-witness-idl-fix-length-calculation-for-witness_IPaddrInfoList.patch new file mode 100644 index 0000000..d3eb512 --- /dev/null +++ b/backport-witness-idl-fix-length-calculation-for-witness_IPaddrInfoList.patch @@ -0,0 +1,50 @@ +From 8cce23acb9f9bdde8bff3c3a7ffa83361e3a64a6 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Fri, 31 Jul 2020 11:27:25 +0200 +Subject: [PATCH] witness.idl: fix length calculation for + witness_IPaddrInfoList + +If r->num is 0, we should not dereference r->addr. + +Using ndr_size_witness_IPaddrInfoList() also make this much simpler +and avoids the magic 12. + +Credit Oss-Fuzz + +REF: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=22175 +REF: https://oss-fuzz.com/testcase-detail/5686294157197312 + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=14452 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Samuel Cabrero +--- + librpc/idl/witness.idl | 6 +++--- + source4/torture/ndr/witness.c | 24 ------------------------ + 2 files changed, 3 insertions(+), 27 deletions(-) + +diff --git a/librpc/idl/witness.idl b/librpc/idl/witness.idl +index e230a5ea709..652c0e9cb65 100644 +--- a/librpc/idl/witness.idl ++++ b/librpc/idl/witness.idl +@@ -98,14 +98,14 @@ interface witness + WITNESS_IPADDR_OFFLINE = 0x10 + } witness_IPaddrInfo_flags; + +- typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN),gensize] struct { ++ typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct { + witness_IPaddrInfo_flags flags; + [flag(NDR_BIG_ENDIAN)] ipv4address ipv4; + [flag(NDR_BIG_ENDIAN)] ipv6address ipv6; + } witness_IPaddrInfo; + +- typedef [flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN)] struct { +- [value(12+(r->num*ndr_size_witness_IPaddrInfo(r->addr, ndr->flags)))] uint32 length; ++ typedef [public,flag(NDR_NOALIGN|NDR_LITTLE_ENDIAN),gensize] struct { ++ [value(ndr_size_witness_IPaddrInfoList(r, ndr->flags))] uint32 length; + [value(0)] uint32 reserved; + uint32 num; + witness_IPaddrInfo addr[num]; +-- +GitLab + diff --git a/samba.spec b/samba.spec index 4e7c5e1..6c0551d 100644 --- a/samba.spec +++ b/samba.spec @@ -49,7 +49,7 @@ Name: samba Version: 4.12.5 -Release: 7 +Release: 8 Summary: A suite for Linux to interoperate with Windows License: GPLv3+ and LGPLv3+ @@ -75,6 +75,17 @@ Patch5: CVE-2021-20277.patch Patch6: CVE-2020-27840.patch Patch7: CVE-2021-20254.patch Patch8: backport-CVE-2021-3671.patch +Patch9: backport-lzxpress-add-bounds-checking-to-lzxpress_decompress.patch +Patch10: backport-librpc-ndr-NDR_PULL_ALIGN-check-for-unsigned-overflow.patch +Patch11: backport-librpc-ndr-add-recursion-check-macros.patch +Patch12: backport-librpc-ndr-Heap-buffer-overflow-in-lzxpress_decompress.patch +Patch13: backport-pidl-Add-recursive-depth-checks.patch +Patch14: backport-idl-drsuapi_DsaAddressListItem_V1-limit-recursion.patch +Patch15: backport-idl-limit-recurion-on-recursive-elements.patch +Patch16: backport-lib-ldb-Limit-depth-of-ldb_parse_tree.patch +Patch17: backport-witness-idl-fix-length-calculation-for-witness_IPaddrInfoList.patch +Patch18: backport-lzxpress-avoid-technically-undefined-shift.patch +Patch19: backport-utils-asn1-avoid-undefined-behaviour.patch BuildRequires: avahi-devel bison cups-devel dbus-devel docbook-style-xsl e2fsprogs-devel flex gawk gnupg2 gnutls-devel >= 3.4.7 gpgme-devel BuildRequires: jansson-devel krb5-devel >= %{required_mit_krb5} libacl-devel libaio-devel libarchive-devel libattr-devel @@ -3209,6 +3220,23 @@ fi %endif %changelog +* Fri Oct 29 2021 gaihuiying - 4.12.5-8 +- Type:bugfix +- ID:NA +- SUG:NA +- DESC:fix fuzz error: + idl: drsuapi_DsaAddressListItem_V1 limit recursion + idl: limit recurion on recursive-elements + lib: ldb Limit depth of ldb_parse_tree + librpc: ndr add recursion check macros + librpc: ndr Heap-buffer-overflow in lzxpress_decompress + librpc: ndr NDR_PULL_ALIGN check for unsigned overflow + lzxpress: add bounds checking to lzxpress decompress + lzxpress: avoid technically undefined shift + pidl: Add recursive depth checks + utils: asn1 avoid undefined behaviour + witness: idl fix length calculation for witness_IPaddrInfoList + * Mon Oct 25 2021 gaihuiying - 4.12.5-7 - Type:cves - ID:CVE-2021-3671