Version in base suite: 4.13.13+dfsg-1~deb11u5 Base version: samba_4.13.13+dfsg-1~deb11u5 Target version: samba_4.13.13+dfsg-1~deb11u6 Base file: /srv/ftp-master.debian.org/ftp/pool/main/s/samba/samba_4.13.13+dfsg-1~deb11u5.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/s/samba/samba_4.13.13+dfsg-1~deb11u6.dsc changelog | 13 patches/0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch | 135 patches/0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch | 172 + patches/0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch | 90 patches/0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch | 186 + patches/0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch | 73 patches/0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch | 120 patches/0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch | 34 patches/0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch | 49 patches/0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch | 60 patches/0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch | 86 patches/0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch | 77 patches/0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch | 53 patches/0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch | 42 patches/0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch | 57 patches/0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch | 456 +++ patches/0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch | 501 +++ patches/0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch | 213 + patches/CVE-2022-2127-1.patch | 61 patches/CVE-2022-2127-2.patch | 73 patches/CVE-2022-2127-3.patch | 36 patches/CVE-2022-3437-des3-overflow-v4a-4.12-1.patch | 1470 ++++++++++ patches/CVE-2022-3437-des3-overflow-v4a-4.12-2.patch | 89 patches/CVE-2022-3437-des3-overflow-v4a-4.12-3.patch | 13 patches/CVE-2022-3437-des3-overflow-v4a-4.12-4.patch | 72 patches/CVE-2022-3437-des3-overflow-v4a-4.12-5.patch | 8 patches/CVE-2022-3437-des3-overflow-v4a-4.12-6.patch | 40 patches/CVE-2022-3437-des3-overflow-v4a-4.12-7.patch | 8 patches/CVE-2022-3437-des3-overflow-v4a-4.12-8.patch | 25 patches/CVE-2023-34968-pre.patch | 83 patches/series | 29 31 files changed, 4424 insertions(+) diff -Nru samba-4.13.13+dfsg/debian/changelog samba-4.13.13+dfsg/debian/changelog --- samba-4.13.13+dfsg/debian/changelog 2022-08-09 21:19:38.000000000 +0000 +++ samba-4.13.13+dfsg/debian/changelog 2024-03-19 21:00:18.000000000 +0000 @@ -1,3 +1,16 @@ +samba (2:4.13.13+dfsg-1~deb11u6) bullseye-security; urgency=medium + + * CVE-2022-2127: Out-of-bounds read in winbind AUTH_CRAP + * CVE-2022-3437: Heimdal des/des3 heap-based buffer overflow + * CVE-2023-4091: Client can truncate files even with read-only permissions + * CVE-2023-34966: Spotlight mdssvc RPC Request Infinite Loop + Denial-of-Service Vulnerability + * CVE-2023-34967: Spotlight mdssvc RPC Request Type Confusion + Denial-of-Service Vulnerability + * CVE-2023-34968: Spotlight server-side Share Path Disclosure + + -- Santiago Ruano Rincón Tue, 19 Mar 2024 18:00:18 -0300 + samba (2:4.13.13+dfsg-1~deb11u5) bullseye-security; urgency=medium * 3 patches: diff -Nru samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch --- samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,135 @@ +From 01cf3cf7a83f0f3fcdf1f4026327c84e4c17f853 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 31 May 2023 15:34:26 +0200 +Subject: [PATCH 1/2] CVE-2023-34966: CI: test for sl_unpack_loop() + +Send a maliciously crafted packet where a nil type has a subcount of 0. This +triggers an endless loop in mdssvc sl_unpack_loop(). + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15340 + +Signed-off-by: Ralph Boehme +--- + source4/torture/rpc/mdssvc.c | 100 +++++++++++++++++++++++++++++++++++ + 1 file changed, 100 insertions(+) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index 8f16af66476..d0a2d33cf9e 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -569,6 +569,102 @@ done: + return ok; + } + ++static uint8_t test_sl_unpack_loop_buf[] = { ++ 0x34, 0x33, 0x32, 0x31, 0x33, 0x30, 0x64, 0x6d, ++ 0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x00, ++ 0x06, 0x00, 0x00, 0x07, 0x04, 0x00, 0x00, 0x00, ++ 0x66, 0x65, 0x74, 0x63, 0x68, 0x41, 0x74, 0x74, ++ 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x3a, ++ 0x66, 0x6f, 0x72, 0x4f, 0x49, 0x44, 0x41, 0x72, ++ 0x72, 0x61, 0x79, 0x3a, 0x63, 0x6f, 0x6e, 0x74, ++ 0x65, 0x78, 0x74, 0x3a, 0x00, 0x00, 0x00, 0xea, ++ 0x02, 0x00, 0x00, 0x84, 0x02, 0x00, 0x00, 0x00, ++ 0x0a, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 0x00, ++ 0x6b, 0x4d, 0x44, 0x49, 0x74, 0x65, 0x6d, 0x50, ++ 0x61, 0x74, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x87, 0x08, 0x00, 0x00, 0x00, ++ 0x01, 0x00, 0xdd, 0x0a, 0x20, 0x00, 0x00, 0x6b, ++ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x07, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, ++ 0x02, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, ++ 0x03, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, ++ 0x04, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x00, ++ 0x0e, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, ++ 0x0f, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x00, ++ 0x13, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, ++ 0x00, 0x00, 0x00, 0x00 ++}; ++ ++static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx, ++ void *data) ++{ ++ struct torture_mdsscv_state *state = talloc_get_type_abort( ++ data, struct torture_mdsscv_state); ++ struct dcerpc_binding_handle *b = state->p->binding_handle; ++ struct mdssvc_blob request_blob; ++ struct mdssvc_blob response_blob; ++ uint32_t device_id; ++ uint32_t unkn2; ++ uint32_t unkn9; ++ uint32_t fragment; ++ uint32_t flags; ++ NTSTATUS status; ++ bool ok = true; ++ ++ device_id = UINT32_C(0x2f000045); ++ unkn2 = 23; ++ unkn9 = 0; ++ fragment = 0; ++ flags = UINT32_C(0x6b000001); ++ ++ request_blob.spotlight_blob = test_sl_unpack_loop_buf; ++ request_blob.size = sizeof(test_sl_unpack_loop_buf); ++ request_blob.length = sizeof(test_sl_unpack_loop_buf); ++ ++ response_blob.spotlight_blob = talloc_array(state, ++ uint8_t, ++ 0); ++ torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, ++ ok, done, "dalloc_zero failed\n"); ++ response_blob.size = 0; ++ ++ status = dcerpc_mdssvc_cmd(b, ++ state, ++ &state->ph, ++ 0, ++ device_id, ++ unkn2, ++ 0, ++ flags, ++ request_blob, ++ 0, ++ 64 * 1024, ++ 1, ++ 64 * 1024, ++ 0, ++ 0, ++ &fragment, ++ &response_blob, ++ &unkn9); ++ torture_assert_ntstatus_ok_goto( ++ tctx, status, ok, done, ++ "dcerpc_mdssvc_unknown1 failed\n"); ++ ++done: ++ return ok; ++} ++ + static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx, + void *data) + { +@@ -840,5 +936,9 @@ struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx) + "fetch_unknown_cnid", + test_mdssvc_fetch_attr_unknown_cnid); + ++ torture_tcase_add_simple_test(tcase, ++ "mdssvc_sl_unpack_loop", ++ test_mdssvc_sl_unpack_loop); ++ + return suite; + } +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch --- samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,172 @@ +From 92d014bc44b32478aa597f38bf11687f1fc95ff1 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Wed, 31 May 2023 16:26:14 +0200 +Subject: [PATCH 1/2] CVE-2023-34967: CI: add a test for type checking of + dalloc_value_for_key() + +Sends a maliciously crafted packet where the value in a key/value style +dictionary for the "scope" key is a simple string object whereas the server +expects an array. As the server doesn't perform type validation on the value, it +crashes when trying to use the "simple" object as a "complex" one. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15341 + +Signed-off-by: Ralph Boehme +--- + source4/torture/rpc/mdssvc.c | 134 +++++++++++++++++++++++++++++++++++ + 1 file changed, 134 insertions(+) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index d0a2d33cf9e..3689692f7de 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -665,6 +665,136 @@ done: + return ok; + } + ++static bool test_sl_dict_type_safety(struct torture_context *tctx, ++ void *data) ++{ ++ struct torture_mdsscv_state *state = talloc_get_type_abort( ++ data, struct torture_mdsscv_state); ++ struct dcerpc_binding_handle *b = state->p->binding_handle; ++ struct mdssvc_blob request_blob; ++ struct mdssvc_blob response_blob; ++ uint64_t ctx1 = 0xdeadbeef; ++ uint64_t ctx2 = 0xcafebabe; ++ uint32_t device_id; ++ uint32_t unkn2; ++ uint32_t unkn9; ++ uint32_t fragment; ++ uint32_t flags; ++ DALLOC_CTX *d = NULL; ++ sl_array_t *array1 = NULL, *array2 = NULL; ++ sl_dict_t *arg = NULL; ++ int result; ++ NTSTATUS status; ++ bool ok = true; ++ ++ device_id = UINT32_C(0x2f000045); ++ unkn2 = 23; ++ unkn9 = 0; ++ fragment = 0; ++ flags = UINT32_C(0x6b000001); ++ ++ d = dalloc_new(tctx); ++ torture_assert_not_null_goto(tctx, d, ++ ok, done, "dalloc_new failed\n"); ++ ++ array1 = dalloc_zero(d, sl_array_t); ++ torture_assert_not_null_goto(tctx, array1, ++ ok, done, "dalloc_zero failed\n"); ++ ++ array2 = dalloc_zero(d, sl_array_t); ++ torture_assert_not_null_goto(tctx, array2, ++ ok, done, "dalloc_new failed\n"); ++ ++ result = dalloc_stradd(array2, "openQueryWithParams:forContext:"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add_copy(array2, &ctx1, uint64_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add_copy(array2, &ctx2, uint64_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ arg = dalloc_zero(array1, sl_dict_t); ++ torture_assert_not_null_goto(tctx, d, ++ ok, done, "dalloc_zero failed\n"); ++ ++ result = dalloc_stradd(arg, "kMDQueryString"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "*"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "kMDScopeArray"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_stradd(arg, "AAAABBBB"); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_stradd failed\n"); ++ ++ result = dalloc_add(array1, array2, sl_array_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ result = dalloc_add(array1, arg, sl_dict_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ result = dalloc_add(d, array1, sl_array_t); ++ torture_assert_goto(tctx, result == 0, ++ ok, done, "dalloc_add failed\n"); ++ ++ torture_comment(tctx, "%s", dalloc_dump(d, 0)); ++ ++ request_blob.spotlight_blob = talloc_array(tctx, ++ uint8_t, ++ 64 * 1024); ++ torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, ++ ok, done, "dalloc_new failed\n"); ++ request_blob.size = 64 * 1024; ++ ++ request_blob.length = sl_pack(d, ++ (char *)request_blob.spotlight_blob, ++ request_blob.size); ++ torture_assert_goto(tctx, request_blob.length > 0, ++ ok, done, "sl_pack failed\n"); ++ ++ response_blob.spotlight_blob = talloc_array(state, uint8_t, 0); ++ torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, ++ ok, done, "dalloc_zero failed\n"); ++ response_blob.size = 0; ++ ++ status = dcerpc_mdssvc_cmd(b, ++ state, ++ &state->ph, ++ 0, ++ device_id, ++ unkn2, ++ 0, ++ flags, ++ request_blob, ++ 0, ++ 64 * 1024, ++ 1, ++ 64 * 1024, ++ 0, ++ 0, ++ &fragment, ++ &response_blob, ++ &unkn9); ++ torture_assert_ntstatus_ok_goto( ++ tctx, status, ok, done, ++ "dcerpc_mdssvc_cmd failed\n"); ++ ++done: ++ return ok; ++} ++ + static bool test_mdssvc_invalid_ph_close(struct torture_context *tctx, + void *data) + { +@@ -940,5 +1070,9 @@ struct torture_suite *torture_rpc_mdssvc(TALLOC_CTX *mem_ctx) + "mdssvc_sl_unpack_loop", + test_mdssvc_sl_unpack_loop); + ++ torture_tcase_add_simple_test(tcase, ++ "sl_dict_type_safety", ++ test_sl_dict_type_safety); ++ + return suite; + } +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch --- samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,90 @@ +From b09e22cfc79845ef751acc9b5ecf479cb56b135f Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 6 Jun 2023 15:17:26 +0200 +Subject: [PATCH 01/11] CVE-2023-34968: mdssvc: cache and reuse stat info in + struct sl_inode_path_map + +Prepare for the "path" being a fake path and not the real server-side +path where we won't be able to vfs_stat_fsp() this fake path. Luckily we already +got stat info for the object in mds_add_result() so we can just pass stat info +from there. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_server/mdssvc/mdssvc.c | 32 +++++++----------------------- + source3/rpc_server/mdssvc/mdssvc.h | 1 + + 2 files changed, 8 insertions(+), 25 deletions(-) + +Index: samba/source3/rpc_server/mdssvc/mdssvc.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.c ++++ samba/source3/rpc_server/mdssvc/mdssvc.c +@@ -445,7 +445,10 @@ static int ino_path_map_destr_cb(struct + * entries by calling talloc_free() on the query slq handles. + **/ + +-static bool inode_map_add(struct sl_query *slq, uint64_t ino, const char *path) ++static bool inode_map_add(struct sl_query *slq, ++ uint64_t ino, ++ const char *path, ++ struct stat_ex *st) + { + NTSTATUS status; + struct sl_inode_path_map *entry; +@@ -492,6 +495,7 @@ static bool inode_map_add(struct sl_quer + + entry->ino = ino; + entry->mds_ctx = slq->mds_ctx; ++ entry->st = *st; + entry->path = talloc_strdup(entry, path); + if (entry->path == NULL) { + DEBUG(1, ("talloc failed\n")); +@@ -633,7 +637,7 @@ bool mds_add_result(struct sl_query *slq + return false; + } + +- ok = inode_map_add(slq, ino64, path); ++ ok = inode_map_add(slq, ino64, path, &sb); + if (!ok) { + DEBUG(1, ("inode_map_add error\n")); + slq->state = SLQ_STATE_ERROR; +@@ -1350,23 +1354,7 @@ static bool slrpc_fetch_attributes(struc + elem = talloc_get_type_abort(p, struct sl_inode_path_map); + path = elem->path; + +- smb_fname = synthetic_smb_fname(talloc_tos(), +- path, +- NULL, +- NULL, +- 0, +- 0); +- if (smb_fname == NULL) { +- DBG_ERR("synthetic_smb_fname() failed\n"); +- goto error; +- } +- +- result = SMB_VFS_STAT(mds_ctx->conn, smb_fname); +- if (result != 0) { +- goto error; +- } +- +- sp = &smb_fname->st; ++ sp = &elem->st; + } + + ok = add_filemeta(mds_ctx, reqinfo, fm_array, path, sp); +Index: samba/source3/rpc_server/mdssvc/mdssvc.h +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.h ++++ samba/source3/rpc_server/mdssvc/mdssvc.h +@@ -105,6 +105,7 @@ struct sl_inode_path_map { + struct mds_ctx *mds_ctx; + uint64_t ino; + char *path; ++ struct stat_ex st; + }; + + /* Per process state */ diff -Nru samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch --- samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,186 @@ +From b08a60160e6ab8d982d31844bcbf7ab67ff3a8de Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 1 Aug 2023 12:30:00 +0200 +Subject: [PATCH 1/2] CVE-2023-4091: smbtorture: test overwrite dispositions on + read-only file + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15439 + +Signed-off-by: Ralph Boehme +--- + selftest/knownfail.d/samba3.smb2.acls | 1 + + source4/torture/smb2/acls.c | 143 ++++++++++++++++++++++++++ + 2 files changed, 144 insertions(+) + create mode 100644 selftest/knownfail.d/samba3.smb2.acls + +diff --git a/selftest/knownfail.d/samba3.smb2.acls b/selftest/knownfail.d/samba3.smb2.acls +new file mode 100644 +index 00000000000..18df260c0e5 +--- /dev/null ++++ b/selftest/knownfail.d/samba3.smb2.acls +@@ -0,0 +1 @@ ++^samba3.smb2.acls.OVERWRITE_READ_ONLY_FILE +diff --git a/source4/torture/smb2/acls.c b/source4/torture/smb2/acls.c +index a27d4e079e6..5a892d004ea 100644 +--- a/source4/torture/smb2/acls.c ++++ b/source4/torture/smb2/acls.c +@@ -2989,6 +2989,148 @@ done: + return ret; + } + ++static bool test_overwrite_read_only_file(struct torture_context *tctx, ++ struct smb2_tree *tree) ++{ ++ NTSTATUS status; ++ struct smb2_create c; ++ const char *fname = BASEDIR "\\test_overwrite_read_only_file.txt"; ++ struct smb2_handle handle = {{0}}; ++ union smb_fileinfo q; ++ union smb_setfileinfo set; ++ struct security_descriptor *sd = NULL, *sd_orig = NULL; ++ const char *owner_sid = NULL; ++ int i; ++ bool ret = true; ++ ++ struct tcase { ++ int disposition; ++ const char *disposition_string; ++ NTSTATUS expected_status; ++ } tcases[] = { ++#define TCASE(d, s) { \ ++ .disposition = d, \ ++ .disposition_string = #d, \ ++ .expected_status = s, \ ++ } ++ TCASE(NTCREATEX_DISP_OPEN, NT_STATUS_OK), ++ TCASE(NTCREATEX_DISP_SUPERSEDE, NT_STATUS_ACCESS_DENIED), ++ TCASE(NTCREATEX_DISP_OVERWRITE, NT_STATUS_ACCESS_DENIED), ++ TCASE(NTCREATEX_DISP_OVERWRITE_IF, NT_STATUS_ACCESS_DENIED), ++ }; ++#undef TCASE ++ ++ ret = smb2_util_setup_dir(tctx, tree, BASEDIR); ++ torture_assert_goto(tctx, ret, ret, done, "smb2_util_setup_dir not ok"); ++ ++ c = (struct smb2_create) { ++ .in.desired_access = SEC_STD_READ_CONTROL | ++ SEC_STD_WRITE_DAC | ++ SEC_STD_WRITE_OWNER, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_READ | ++ NTCREATEX_SHARE_ACCESS_WRITE, ++ .in.create_disposition = NTCREATEX_DISP_OPEN_IF, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_create failed\n"); ++ handle = c.out.file.handle; ++ ++ torture_comment(tctx, "get the original sd\n"); ++ ++ ZERO_STRUCT(q); ++ q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; ++ q.query_secdesc.in.file.handle = handle; ++ q.query_secdesc.in.secinfo_flags = SECINFO_DACL | SECINFO_OWNER; ++ ++ status = smb2_getinfo_file(tree, tctx, &q); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_getinfo_file failed\n"); ++ sd_orig = q.query_secdesc.out.sd; ++ ++ owner_sid = dom_sid_string(tctx, sd_orig->owner_sid); ++ ++ sd = security_descriptor_dacl_create(tctx, ++ 0, NULL, NULL, ++ owner_sid, ++ SEC_ACE_TYPE_ACCESS_ALLOWED, ++ SEC_FILE_READ_DATA, ++ 0, ++ NULL); ++ ++ ZERO_STRUCT(set); ++ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; ++ set.set_secdesc.in.file.handle = handle; ++ set.set_secdesc.in.secinfo_flags = SECINFO_DACL; ++ set.set_secdesc.in.sd = sd; ++ ++ status = smb2_setinfo_file(tree, &set); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_setinfo_file failed\n"); ++ ++ smb2_util_close(tree, handle); ++ ZERO_STRUCT(handle); ++ ++ for (i = 0; i < ARRAY_SIZE(tcases); i++) { ++ torture_comment(tctx, "Verify open with %s dispostion\n", ++ tcases[i].disposition_string); ++ ++ c = (struct smb2_create) { ++ .in.create_disposition = tcases[i].disposition, ++ .in.desired_access = SEC_FILE_READ_DATA, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ smb2_util_close(tree, c.out.file.handle); ++ torture_assert_ntstatus_equal_goto( ++ tctx, status, tcases[i].expected_status, ret, done, ++ "smb2_create failed\n"); ++ }; ++ ++ torture_comment(tctx, "put back original sd\n"); ++ ++ c = (struct smb2_create) { ++ .in.desired_access = SEC_STD_WRITE_DAC, ++ .in.file_attributes = FILE_ATTRIBUTE_NORMAL, ++ .in.share_access = NTCREATEX_SHARE_ACCESS_MASK, ++ .in.create_disposition = NTCREATEX_DISP_OPEN_IF, ++ .in.impersonation_level = NTCREATEX_IMPERSONATION_ANONYMOUS, ++ .in.fname = fname, ++ }; ++ ++ status = smb2_create(tree, tctx, &c); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_create failed\n"); ++ handle = c.out.file.handle; ++ ++ ZERO_STRUCT(set); ++ set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; ++ set.set_secdesc.in.file.handle = handle; ++ set.set_secdesc.in.secinfo_flags = SECINFO_DACL; ++ set.set_secdesc.in.sd = sd_orig; ++ ++ status = smb2_setinfo_file(tree, &set); ++ torture_assert_ntstatus_ok_goto(tctx, status, ret, done, ++ "smb2_setinfo_file failed\n"); ++ ++ smb2_util_close(tree, handle); ++ ZERO_STRUCT(handle); ++ ++done: ++ smb2_util_close(tree, handle); ++ smb2_util_unlink(tree, fname); ++ smb2_deltree(tree, BASEDIR); ++ return ret; ++} ++ + /* + basic testing of SMB2 ACLs + */ +@@ -3017,6 +3159,7 @@ struct torture_suite *torture_smb2_acls_init(TALLOC_CTX *ctx) + test_deny1); + torture_suite_add_1smb2_test(suite, "MXAC-NOT-GRANTED", + test_mxac_not_granted); ++ torture_suite_add_1smb2_test(suite, "OVERWRITE_READ_ONLY_FILE", test_overwrite_read_only_file); + + suite->description = talloc_strdup(suite, "SMB2-ACLS tests"); + +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch --- samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,73 @@ +From cb6f3e2202473eeccf81e34ebcdb4bc4f726548a Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 26 May 2023 13:06:19 +0200 +Subject: [PATCH 2/2] CVE-2023-34966: mdssvc: harden sl_unpack_loop() + +A malicious client could send a packet where subcount is zero, leading to a busy +loop because + + count -= subcount +=> count -= 0 +=> while (count > 0) + +loops forever. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15340 + +Signed-off-by: Ralph Boehme +--- + source3/rpc_server/mdssvc/marshalling.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/marshalling.c b/source3/rpc_server/mdssvc/marshalling.c +index 1aa750413cd..441d41160f1 100644 +--- a/source3/rpc_server/mdssvc/marshalling.c ++++ b/source3/rpc_server/mdssvc/marshalling.c +@@ -1119,7 +1119,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + sl_nil_t nil = 0; + + subcount = tag.count; +- if (subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + for (i = 0; i < subcount; i++) { +@@ -1147,7 +1147,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_INT64: + subcount = sl_unpack_ints(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1156,7 +1156,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_UUID: + subcount = sl_unpack_uuid(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1165,7 +1165,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_FLOAT: + subcount = sl_unpack_floats(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +@@ -1174,7 +1174,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX *query, + + case SQ_TYPE_DATE: + subcount = sl_unpack_date(query, buf, offset, bufsize, encoding); +- if (subcount == -1 || subcount > count) { ++ if (subcount < 1 || subcount > count) { + return -1; + } + offset += tag.size; +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch --- samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,120 @@ +From 5b4353cc60b75610f0aa12b1cced36d35a4d04d4 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 26 May 2023 15:06:38 +0200 +Subject: [PATCH 2/2] CVE-2023-34967: mdssvc: add type checking to + dalloc_value_for_key() + +Change the dalloc_value_for_key() function to require an additional final +argument which denotes the expected type of the value associated with a key. If +the types don't match, return NULL. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15341 + +Signed-off-by: Ralph Boehme +--- + source3/rpc_server/mdssvc/dalloc.c | 14 ++++++++++---- + source3/rpc_server/mdssvc/mdssvc.c | 17 +++++++++++++---- + 2 files changed, 23 insertions(+), 8 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/dalloc.c b/source3/rpc_server/mdssvc/dalloc.c +index 007702d4540..8b79b41fd97 100644 +--- a/source3/rpc_server/mdssvc/dalloc.c ++++ b/source3/rpc_server/mdssvc/dalloc.c +@@ -159,7 +159,7 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + int result = 0; + void *p = NULL; + va_list args; +- const char *type; ++ const char *type = NULL; + int elem; + size_t array_len; + +@@ -170,7 +170,6 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + array_len = talloc_array_length(d->dd_talloc_array); + elem = va_arg(args, int); + if (elem >= array_len) { +- va_end(args); + result = -1; + goto done; + } +@@ -178,8 +177,6 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + type = va_arg(args, const char *); + } + +- va_end(args); +- + array_len = talloc_array_length(d->dd_talloc_array); + + for (elem = 0; elem + 1 < array_len; elem += 2) { +@@ -192,8 +189,17 @@ void *dalloc_value_for_key(const DALLOC_CTX *d, ...) + break; + } + } ++ if (p == NULL) { ++ goto done; ++ } ++ ++ type = va_arg(args, const char *); ++ if (strcmp(talloc_get_name(p), type) != 0) { ++ p = NULL; ++ } + + done: ++ va_end(args); + if (result != 0) { + p = NULL; + } +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 4f1629b2b4d..02c42211694 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -885,7 +885,8 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + + querystring = dalloc_value_for_key(query, "DALLOC_CTX", 0, + "DALLOC_CTX", 1, +- "kMDQueryString"); ++ "kMDQueryString", ++ "char *"); + if (querystring == NULL) { + DEBUG(1, ("missing kMDQueryString\n")); + goto error; +@@ -925,8 +926,11 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + slq->ctx2 = *uint64p; + + path_scope = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDScopeArray"); ++ "DALLOC_CTX", 1, ++ "kMDScopeArray", ++ "sl_array_t"); + if (path_scope == NULL) { ++ DBG_ERR("missing kMDScopeArray\n"); + goto error; + } + +@@ -947,8 +951,11 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + } + + reqinfo = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDAttributeArray"); ++ "DALLOC_CTX", 1, ++ "kMDAttributeArray", ++ "sl_array_t"); + if (reqinfo == NULL) { ++ DBG_ERR("missing kMDAttributeArray\n"); + goto error; + } + +@@ -956,7 +963,9 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx, + DEBUG(10, ("requested attributes: %s", dalloc_dump(reqinfo, 0))); + + cnids = dalloc_value_for_key(query, "DALLOC_CTX", 0, +- "DALLOC_CTX", 1, "kMDQueryItemArray"); ++ "DALLOC_CTX", 1, ++ "kMDQueryItemArray", ++ "sl_array_t"); + if (cnids) { + ok = sort_cnids(slq, cnids->ca_cnids); + if (!ok) { +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch --- samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,34 @@ +From 8c95f7ae6b3f30ccdc5ce4f0c44b3f8c1fc6a5c8 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Sat, 17 Jun 2023 13:39:55 +0200 +Subject: [PATCH 02/11] CVE-2023-34968: mdssvc: add missing + "kMDSStoreMetaScopes" dict key in slrpc_fetch_properties() + +We were adding the value, but not the key. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_server/mdssvc/mdssvc.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 3af0a71a28e..72936a99289 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -743,6 +743,10 @@ static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx, + } + + /* kMDSStoreMetaScopes array */ ++ result = dalloc_stradd(dict, "kMDSStoreMetaScopes"); ++ if (result != 0) { ++ return false; ++ } + array = dalloc_zero(dict, sl_array_t); + if (array == NULL) { + return NULL; +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch --- samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,49 @@ +From 8b26f634372f11edcbea33dfd68a3d57889dfcc5 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 1 Aug 2023 13:04:36 +0200 +Subject: [PATCH 2/2] CVE-2023-4091: smbd: use open_access_mask for access + check in open_file() + +If the client requested FILE_OVERWRITE[_IF], we're implicitly adding +FILE_WRITE_DATA to the open_access_mask in open_file_ntcreate(), but for the +access check we're using access_mask which doesn't contain the additional +right, which means we can end up truncating a file for which the user has +only read-only access via an SD. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15439 + +Signed-off-by: Ralph Boehme +--- + selftest/knownfail.d/samba3.smb2.acls | 1 - + source3/smbd/open.c | 4 ++-- + 2 files changed, 2 insertions(+), 3 deletions(-) + delete mode 100644 selftest/knownfail.d/samba3.smb2.acls + +Index: samba/selftest/knownfail.d/samba3.smb2.acls +=================================================================== +--- samba.orig/selftest/knownfail.d/samba3.smb2.acls ++++ /dev/null +@@ -1 +0,0 @@ +-^samba3.smb2.acls.OVERWRITE_READ_ONLY_FILE +Index: samba/source3/smbd/open.c +=================================================================== +--- samba.orig/source3/smbd/open.c ++++ samba/source3/smbd/open.c +@@ -1320,7 +1320,7 @@ static NTSTATUS open_file(files_struct * + conn->cwd_fsp, + smb_fname, + false, +- access_mask); ++ open_access_mask); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("open_file: " +@@ -1467,7 +1467,7 @@ static NTSTATUS open_file(files_struct * + conn->cwd_fsp, + smb_fname, + false, +- access_mask); ++ open_access_mask); + + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && + (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) && diff -Nru samba-4.13.13+dfsg/debian/patches/0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch samba-4.13.13+dfsg/debian/patches/0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch --- samba-4.13.13+dfsg/debian/patches/0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,60 @@ +From 3636b54616ee63e17d8571af610a0e21d667b592 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 17:14:38 +0200 +Subject: [PATCH 03/11] CVE-2023-34968: mdscli: use correct TALLOC memory + context when allocating spotlight_blob + +d is talloc_free()d at the end of the functions and the buffer was later used +after beeing freed in the DCERPC layer when sending the packet. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_client/cli_mdssvc_util.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c +index fe5092c3790..892a844e71a 100644 +--- a/source3/rpc_client/cli_mdssvc_util.c ++++ b/source3/rpc_client/cli_mdssvc_util.c +@@ -209,7 +209,7 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -293,7 +293,7 @@ NTSTATUS mdscli_blob_get_results(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -426,7 +426,7 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +@@ -510,7 +510,7 @@ NTSTATUS mdscli_blob_close_search(TALLOC_CTX *mem_ctx, + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(d, ++ blob->spotlight_blob = talloc_array(mem_ctx, + uint8_t, + ctx->max_fragment_size); + if (blob->spotlight_blob == NULL) { +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch samba-4.13.13+dfsg/debian/patches/0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch --- samba-4.13.13+dfsg/debian/patches/0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,86 @@ +From 82cc2a422db8d4402378c2e6f1e138ff385b0f15 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 18:28:41 +0200 +Subject: [PATCH 04/11] CVE-2023-34968: mdscli: remove response blob allocation + +This is handled by the NDR code transparently. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_client/cli_mdssvc.c | 36 --------------------------------- + 1 file changed, 36 deletions(-) + +diff --git a/source3/rpc_client/cli_mdssvc.c b/source3/rpc_client/cli_mdssvc.c +index 82d14372fe4..07c19b51dd4 100644 +--- a/source3/rpc_client/cli_mdssvc.c ++++ b/source3/rpc_client/cli_mdssvc.c +@@ -276,15 +276,6 @@ struct tevent_req *mdscli_search_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -457,15 +448,6 @@ struct tevent_req *mdscli_get_results_send( + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -681,15 +663,6 @@ struct tevent_req *mdscli_get_path_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +@@ -852,15 +825,6 @@ struct tevent_req *mdscli_close_search_send(TALLOC_CTX *mem_ctx, + return tevent_req_post(req, ev); + } + +- state->response_blob.spotlight_blob = talloc_array( +- state, +- uint8_t, +- mdscli_ctx->max_fragment_size); +- if (tevent_req_nomem(state->response_blob.spotlight_blob, req)) { +- return tevent_req_post(req, ev); +- } +- state->response_blob.size = mdscli_ctx->max_fragment_size; +- + subreq = dcerpc_mdssvc_cmd_send(state, + ev, + mdscli_ctx->bh, +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch samba-4.13.13+dfsg/debian/patches/0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch --- samba-4.13.13+dfsg/debian/patches/0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,77 @@ +From 7bbaa191be6a1b389604eff75aba9913b0e75d98 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:28:47 +0200 +Subject: [PATCH 05/11] CVE-2023-34968: smbtorture: remove response blob + allocation in mdssvc.c + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source4/torture/rpc/mdssvc.c | 26 -------------------------- + 1 file changed, 26 deletions(-) + +diff --git a/source4/torture/rpc/mdssvc.c b/source4/torture/rpc/mdssvc.c +index 3689692f7de..a16bd5b47e3 100644 +--- a/source4/torture/rpc/mdssvc.c ++++ b/source4/torture/rpc/mdssvc.c +@@ -536,13 +536,6 @@ static bool test_mdssvc_invalid_ph_cmd(struct torture_context *tctx, + request_blob.length = 0; + request_blob.size = 0; + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &ph, +@@ -632,13 +625,6 @@ static bool test_mdssvc_sl_unpack_loop(struct torture_context *tctx, + request_blob.size = sizeof(test_sl_unpack_loop_buf); + request_blob.length = sizeof(test_sl_unpack_loop_buf); + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, +@@ -764,11 +750,6 @@ static bool test_sl_dict_type_safety(struct torture_context *tctx, + torture_assert_goto(tctx, request_blob.length > 0, + ok, done, "sl_pack failed\n"); + +- response_blob.spotlight_blob = talloc_array(state, uint8_t, 0); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ok, done, "dalloc_zero failed\n"); +- response_blob.size = 0; +- + status = dcerpc_mdssvc_cmd(b, + state, + &state->ph, +@@ -926,13 +907,6 @@ static bool test_mdssvc_fetch_attr_unknown_cnid(struct torture_context *tctx, + ret, done, "dalloc_zero failed\n"); + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- max_fragment_size); +- torture_assert_not_null_goto(tctx, response_blob.spotlight_blob, +- ret, done, "dalloc_zero failed\n"); +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + torture_assert_goto(tctx, len != -1, ret, done, "sl_pack failed\n"); + +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch samba-4.13.13+dfsg/debian/patches/0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch --- samba-4.13.13+dfsg/debian/patches/0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,53 @@ +From 739f72a07032da15b3a74a8b96959300d555e836 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:35:41 +0200 +Subject: [PATCH 06/11] CVE-2023-34968: rpcclient: remove response blob + allocation + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpcclient/cmd_spotlight.c | 16 ---------------- + 1 file changed, 16 deletions(-) + +diff --git a/source3/rpcclient/cmd_spotlight.c b/source3/rpcclient/cmd_spotlight.c +index 24db9893df6..64fe321089c 100644 +--- a/source3/rpcclient/cmd_spotlight.c ++++ b/source3/rpcclient/cmd_spotlight.c +@@ -144,13 +144,6 @@ static NTSTATUS cmd_mdssvc_fetch_properties( + } + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(mem_ctx, uint8_t, max_fragment_size); +- if (response_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + if (len == -1) { + status = NT_STATUS_INTERNAL_ERROR; +@@ -368,15 +361,6 @@ static NTSTATUS cmd_mdssvc_fetch_attributes( + } + request_blob.size = max_fragment_size; + +- response_blob.spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- max_fragment_size); +- if (response_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- response_blob.size = max_fragment_size; +- + len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); + if (len == -1) { + status = NT_STATUS_INTERNAL_ERROR; +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch samba-4.13.13+dfsg/debian/patches/0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch --- samba-4.13.13+dfsg/debian/patches/0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,42 @@ +From 34f9f1b37ec07a4f233fe90a0e97ce504e0cdffb Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:42:10 +0200 +Subject: [PATCH 07/11] CVE-2023-34968: mdssvc: remove response blob allocation + +This is alreay done by NDR for us. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 9 --------- + 1 file changed, 9 deletions(-) + +Index: samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -208,7 +208,6 @@ void _mdssvc_unknown1(struct pipes_struc + void _mdssvc_cmd(struct pipes_struct *p, struct mdssvc_cmd *r) + { + bool ok; +- char *rbuf; + struct mds_ctx *mds_ctx; + NTSTATUS status; + +@@ -265,14 +264,6 @@ void _mdssvc_cmd(struct pipes_struct *p, + return; + } + +- rbuf = talloc_zero_array(p->mem_ctx, char, r->in.max_fragment_size1); +- if (rbuf == NULL) { +- p->fault_state = DCERPC_FAULT_CANT_PERFORM; +- return; +- } +- r->out.response_blob->spotlight_blob = (uint8_t *)rbuf; +- r->out.response_blob->size = r->in.max_fragment_size1; +- + /* We currently don't use fragmentation at the mdssvc RPC layer */ + *r->out.fragment = 0; + diff -Nru samba-4.13.13+dfsg/debian/patches/0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch samba-4.13.13+dfsg/debian/patches/0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch --- samba-4.13.13+dfsg/debian/patches/0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,57 @@ +From 0fdfc85f28a21f66aa2f1d7e337fe9184368e972 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Tue, 20 Jun 2023 11:05:22 +0200 +Subject: [PATCH 08/11] CVE-2023-34968: mdssvc: switch to doing an early return + +Just reduce indentation of the code handling the success case. No change in +behaviour. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_server/mdssvc/mdssvc.c | 26 ++++++++++++++------------ + 1 file changed, 14 insertions(+), 12 deletions(-) + +diff --git a/source3/rpc_server/mdssvc/mdssvc.c b/source3/rpc_server/mdssvc/mdssvc.c +index 72936a99289..92afa9e5fd4 100644 +--- a/source3/rpc_server/mdssvc/mdssvc.c ++++ b/source3/rpc_server/mdssvc/mdssvc.c +@@ -1817,19 +1817,21 @@ bool mds_dispatch(struct mds_ctx *mds_ctx, + } + + ok = slcmd->function(mds_ctx, query, reply); +- if (ok) { +- DBG_DEBUG("%s", dalloc_dump(reply, 0)); +- +- len = sl_pack(reply, +- (char *)response_blob->spotlight_blob, +- response_blob->size); +- if (len == -1) { +- DBG_ERR("error packing Spotlight RPC reply\n"); +- ok = false; +- goto cleanup; +- } +- response_blob->length = len; ++ if (!ok) { ++ goto cleanup; ++ } ++ ++ DBG_DEBUG("%s", dalloc_dump(reply, 0)); ++ ++ len = sl_pack(reply, ++ (char *)response_blob->spotlight_blob, ++ response_blob->size); ++ if (len == -1) { ++ DBG_ERR("error packing Spotlight RPC reply\n"); ++ ok = false; ++ goto cleanup; + } ++ response_blob->length = len; + + cleanup: + talloc_free(query); +-- +2.43.0 + diff -Nru samba-4.13.13+dfsg/debian/patches/0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch samba-4.13.13+dfsg/debian/patches/0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch --- samba-4.13.13+dfsg/debian/patches/0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,456 @@ +From d6b9c5234ffc6bf415156c693aac3256d17e259c Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 19 Jun 2023 18:16:57 +0200 +Subject: [PATCH 09/11] CVE-2023-34968: mdssvc: introduce an allocating wrapper + to sl_pack() + +sl_pack_alloc() does the buffer allocation that previously all callers of +sl_pack() did themselves. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_client/cli_mdssvc_util.c | 80 +++++------------------ + source3/rpc_server/mdssvc/marshalling.c | 35 ++++++++-- + source3/rpc_server/mdssvc/marshalling.h | 9 ++- + source3/rpc_server/mdssvc/mdssvc.c | 18 ++--- + source3/rpc_server/mdssvc/mdssvc.h | 5 +- + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 5 +- + source3/rpcclient/cmd_spotlight.c | 32 ++------- + source4/torture/rpc/mdssvc.c | 24 ++----- + 8 files changed, 80 insertions(+), 128 deletions(-) + +Index: samba/source3/rpc_client/cli_mdssvc_util.c +=================================================================== +--- samba.orig/source3/rpc_client/cli_mdssvc_util.c ++++ samba/source3/rpc_client/cli_mdssvc_util.c +@@ -42,7 +42,7 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX * + sl_array_t *scope_array = NULL; + double dval; + uint64_t uint64val; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -209,23 +209,11 @@ NTSTATUS mdscli_blob_search(TALLOC_CTX * + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -238,7 +226,7 @@ NTSTATUS mdscli_blob_get_results(TALLOC_ + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -293,23 +281,11 @@ NTSTATUS mdscli_blob_get_results(TALLOC_ + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -325,7 +301,7 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX + sl_array_t *cmd_array = NULL; + sl_array_t *attr_array = NULL; + sl_cnids_t *cnids = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -426,23 +402,11 @@ NTSTATUS mdscli_blob_get_path(TALLOC_CTX + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } + +@@ -455,7 +419,7 @@ NTSTATUS mdscli_blob_close_search(TALLOC + uint64_t *uint64p = NULL; + sl_array_t *array = NULL; + sl_array_t *cmd_array = NULL; +- ssize_t len; ++ NTSTATUS status; + int ret; + + d = dalloc_new(mem_ctx); +@@ -510,22 +474,10 @@ NTSTATUS mdscli_blob_close_search(TALLOC + return NT_STATUS_NO_MEMORY; + } + +- blob->spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- ctx->max_fragment_size); +- if (blob->spotlight_blob == NULL) { +- TALLOC_FREE(d); +- return NT_STATUS_NO_MEMORY; +- } +- blob->size = ctx->max_fragment_size; +- +- len = sl_pack(d, (char *)blob->spotlight_blob, blob->size); ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); + TALLOC_FREE(d); +- if (len == -1) { +- return NT_STATUS_NO_MEMORY; ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; + } +- +- blob->length = len; +- blob->size = len; + return NT_STATUS_OK; + } +Index: samba/source3/rpc_server/mdssvc/marshalling.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/marshalling.c ++++ samba/source3/rpc_server/mdssvc/marshalling.c +@@ -78,6 +78,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX + ssize_t offset, size_t bufsize, + int count, ssize_t toc_offset, + int encoding); ++static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize); + + /****************************************************************************** + * Wrapper functions for the *VAL macros with bound checking +@@ -1190,11 +1191,7 @@ static ssize_t sl_unpack_loop(DALLOC_CTX + return offset; + } + +-/****************************************************************************** +- * Global functions for packing und unpacking +- ******************************************************************************/ +- +-ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize) ++static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize) + { + ssize_t result; + char *toc_buf; +@@ -1274,6 +1271,34 @@ ssize_t sl_pack(DALLOC_CTX *query, char + return len; + } + ++/****************************************************************************** ++ * Global functions for packing und unpacking ++ ******************************************************************************/ ++ ++NTSTATUS sl_pack_alloc(TALLOC_CTX *mem_ctx, ++ DALLOC_CTX *d, ++ struct mdssvc_blob *b, ++ size_t max_fragment_size) ++{ ++ ssize_t len; ++ ++ b->spotlight_blob = talloc_zero_array(mem_ctx, ++ uint8_t, ++ max_fragment_size); ++ if (b->spotlight_blob == NULL) { ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ len = sl_pack(d, (char *)b->spotlight_blob, max_fragment_size); ++ if (len == -1) { ++ return NT_STATUS_DATA_ERROR; ++ } ++ ++ b->length = len; ++ b->size = len; ++ return NT_STATUS_OK; ++} ++ + bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize) + { + ssize_t result; +Index: samba/source3/rpc_server/mdssvc/marshalling.h +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/marshalling.h ++++ samba/source3/rpc_server/mdssvc/marshalling.h +@@ -22,6 +22,9 @@ + #define _MDSSVC_MARSHALLING_H + + #include "dalloc.h" ++#include "libcli/util/ntstatus.h" ++#include "lib/util/data_blob.h" ++#include "librpc/gen_ndr/mdssvc.h" + + #define MAX_SL_FRAGMENT_SIZE 0xFFFFF + +@@ -49,7 +52,11 @@ typedef struct { + * Function declarations + ******************************************************************************/ + +-extern ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize); ++extern NTSTATUS sl_pack_alloc(TALLOC_CTX *mem_ctx, ++ DALLOC_CTX *d, ++ struct mdssvc_blob *b, ++ size_t max_fragment_size); ++ + extern bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize); + + #endif +Index: samba/source3/rpc_server/mdssvc/mdssvc.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.c ++++ samba/source3/rpc_server/mdssvc/mdssvc.c +@@ -1730,11 +1730,11 @@ error: + **/ + bool mds_dispatch(struct mds_ctx *mds_ctx, + struct mdssvc_blob *request_blob, +- struct mdssvc_blob *response_blob) ++ struct mdssvc_blob *response_blob, ++ size_t max_fragment_size) + { + bool ok; + int ret; +- ssize_t len; + DALLOC_CTX *query = NULL; + DALLOC_CTX *reply = NULL; + char *rpccmd; +@@ -1742,6 +1742,7 @@ bool mds_dispatch(struct mds_ctx *mds_ct + const struct smb_filename conn_basedir = { + .base_name = mds_ctx->conn->connectpath, + }; ++ NTSTATUS status; + + if (CHECK_DEBUGLVL(10)) { + const struct sl_query *slq; +@@ -1808,15 +1809,14 @@ bool mds_dispatch(struct mds_ctx *mds_ct + + DBG_DEBUG("%s", dalloc_dump(reply, 0)); + +- len = sl_pack(reply, +- (char *)response_blob->spotlight_blob, +- response_blob->size); +- if (len == -1) { +- DBG_ERR("error packing Spotlight RPC reply\n"); +- ok = false; ++ status = sl_pack_alloc(response_blob, ++ reply, ++ response_blob, ++ max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { ++ DBG_ERR("sl_pack_alloc() failed\n"); + goto cleanup; + } +- response_blob->length = len; + + cleanup: + talloc_free(query); +Index: samba/source3/rpc_server/mdssvc/mdssvc.h +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.h ++++ samba/source3/rpc_server/mdssvc/mdssvc.h +@@ -157,9 +157,10 @@ struct mds_ctx *mds_init_ctx(TALLOC_CTX + int snum, + const char *sharename, + const char *path); +-extern bool mds_dispatch(struct mds_ctx *query_ctx, ++extern bool mds_dispatch(struct mds_ctx *mds_ctx, + struct mdssvc_blob *request_blob, +- struct mdssvc_blob *response_blob); ++ struct mdssvc_blob *response_blob, ++ size_t max_fragment_size); + bool mds_add_result(struct sl_query *slq, const char *path); + + #endif /* _MDSSVC_H */ +Index: samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -267,7 +267,10 @@ void _mdssvc_cmd(struct pipes_struct *p, + /* We currently don't use fragmentation at the mdssvc RPC layer */ + *r->out.fragment = 0; + +- ok = mds_dispatch(mds_ctx, &r->in.request_blob, r->out.response_blob); ++ ok = mds_dispatch(mds_ctx, ++ &r->in.request_blob, ++ r->out.response_blob, ++ r->in.max_fragment_size1); + if (ok) { + *r->out.unkn9 = 0; + } else { +Index: samba/source3/rpcclient/cmd_spotlight.c +=================================================================== +--- samba.orig/source3/rpcclient/cmd_spotlight.c ++++ samba/source3/rpcclient/cmd_spotlight.c +@@ -43,7 +43,6 @@ static NTSTATUS cmd_mdssvc_fetch_propert + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +- ssize_t len; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; +@@ -137,20 +136,10 @@ static NTSTATUS cmd_mdssvc_fetch_propert + goto done; + } + +- request_blob.spotlight_blob = talloc_array(mem_ctx, uint8_t, max_fragment_size); +- if (request_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- if (len == -1) { +- status = NT_STATUS_INTERNAL_ERROR; ++ status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- request_blob.length = len; +- request_blob.size = len; + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, +@@ -204,7 +193,6 @@ static NTSTATUS cmd_mdssvc_fetch_attribu + uint32_t unkn3; /* server always returns 0 ? */ + struct mdssvc_blob request_blob; + struct mdssvc_blob response_blob; +- ssize_t len; + uint32_t max_fragment_size = 64 * 1024; + DALLOC_CTX *d, *mds_reply; + uint64_t *uint64var; +@@ -352,22 +340,10 @@ static NTSTATUS cmd_mdssvc_fetch_attribu + goto done; + } + +- request_blob.spotlight_blob = talloc_array(mem_ctx, +- uint8_t, +- max_fragment_size); +- if (request_blob.spotlight_blob == NULL) { +- status = NT_STATUS_INTERNAL_ERROR; +- goto done; +- } +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- if (len == -1) { +- status = NT_STATUS_INTERNAL_ERROR; ++ status = sl_pack_alloc(mem_ctx, d, &request_blob, max_fragment_size); ++ if (!NT_STATUS_IS_OK(status)) { + goto done; + } +- request_blob.length = len; +- request_blob.size = len; + + status = dcerpc_mdssvc_cmd(b, mem_ctx, + &share_handle, +Index: samba/source4/torture/rpc/mdssvc.c +=================================================================== +--- samba.orig/source4/torture/rpc/mdssvc.c ++++ samba/source4/torture/rpc/mdssvc.c +@@ -745,11 +745,9 @@ static bool test_sl_dict_type_safety(str + ok, done, "dalloc_new failed\n"); + request_blob.size = 64 * 1024; + +- request_blob.length = sl_pack(d, +- (char *)request_blob.spotlight_blob, +- request_blob.size); +- torture_assert_goto(tctx, request_blob.length > 0, +- ok, done, "sl_pack failed\n"); ++ status = sl_pack_alloc(tctx, d, &request_blob, 64 * 1024); ++ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, ++ "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, +@@ -836,7 +834,6 @@ static bool test_mdssvc_fetch_attr_unkno + const char *path_type = NULL; + uint64_t ino64; + NTSTATUS status; +- ssize_t len; + int ret; + bool ok = true; + +@@ -901,18 +898,9 @@ static bool test_mdssvc_fetch_attr_unkno + ret = dalloc_add(array, cnids, sl_cnids_t); + torture_assert_goto(tctx, ret == 0, ret, done, "dalloc_add failed\n"); + +- request_blob.spotlight_blob = talloc_array(state, +- uint8_t, +- max_fragment_size); +- torture_assert_not_null_goto(tctx, request_blob.spotlight_blob, +- ret, done, "dalloc_zero failed\n"); +- request_blob.size = max_fragment_size; +- +- len = sl_pack(d, (char *)request_blob.spotlight_blob, request_blob.size); +- torture_assert_goto(tctx, len != -1, ret, done, "sl_pack failed\n"); +- +- request_blob.length = len; +- request_blob.size = len; ++ status = sl_pack_alloc(tctx, d, &request_blob, max_fragment_size); ++ torture_assert_ntstatus_ok_goto(tctx, status, ok, done, ++ "sl_pack_alloc() failed\n"); + + status = dcerpc_mdssvc_cmd(b, + state, diff -Nru samba-4.13.13+dfsg/debian/patches/0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch samba-4.13.13+dfsg/debian/patches/0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch --- samba-4.13.13+dfsg/debian/patches/0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,501 @@ +From cecd415a0abd857831a33d1f0719b870d85e7966 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Sat, 17 Jun 2023 13:53:27 +0200 +Subject: [PATCH 10/11] CVE-2023-34968: mdscli: return share relative paths +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The next commit will change the Samba Spotlight server to return absolute paths +that start with the sharename as "/SHARENAME/..." followed by the share path +relative appended. + +So given a share + + [spotlight] + path = /foo/bar + spotlight = yes + +and a file inside this share with a full path of + + /foo/bar/dir/file + +previously a search that matched this file would returns the absolute +server-side pato of the file, ie + + /foo/bar/dir/file + +This will be change to + + /spotlight/dir/file + +As currently the mdscli library and hence the mdsearch tool print out these +paths returned from the server, we have to change the output to accomodate these +fake paths. The only way to do this sensibly is by makeing the paths relative to +the containing share, so just + + dir/file + +in the example above. + +The client learns about the share root path prefix – real server-side of fake in +the future – in an initial handshake in the "share_path" out argument of the +mdssvc_open() RPC call, so the client can use this path to convert the absolute +path to relative. + +There is however an additional twist: the macOS Spotlight server prefixes this +absolute path with another prefix, typically "/System/Volumes/Data", so in the +example above the full path for the same search would be + + /System/Volumes/Data/foo/bar/dir/file + +So macOS does return the full server-side path too, just prefixed with an +additional path. This path prefixed can be queried by the client in the +mdssvc_cmd() RPC call with an Spotlight command of "fetchPropertiesForContext:" +and the path is returned in a dictionary with key "kMDSStorePathScopes". Samba +just returns "/" for this. + +Currently the mdscli library doesn't issue this Spotlight RPC +request (fetchPropertiesForContext), so this is added in this commit. In the +end, all search result paths are stripped of the combined prefix + + kMDSStorePathScopes + share_path (from mdssvc_open). + +eg + + kMDSStorePathScopes = /System/Volumes/Data + share_path = /foo/bar + search result = /System/Volumes/Data/foo/bar/dir/file + relative path returned by mdscli = dir/file + +Makes sense? :) + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + python/samba/tests/blackbox/mdsearch.py | 8 +- + python/samba/tests/dcerpc/mdssvc.py | 26 ++-- + source3/rpc_client/cli_mdssvc.c | 155 +++++++++++++++++++++++- + source3/rpc_client/cli_mdssvc_private.h | 4 + + source3/rpc_client/cli_mdssvc_util.c | 68 +++++++++++ + source3/rpc_client/cli_mdssvc_util.h | 4 + + 6 files changed, 245 insertions(+), 20 deletions(-) + +Index: samba/python/samba/tests/blackbox/mdsearch.py +=================================================================== +--- samba.orig/python/samba/tests/blackbox/mdsearch.py ++++ samba/python/samba/tests/blackbox/mdsearch.py +@@ -76,10 +76,7 @@ class MdfindBlackboxTests(BlackboxTestCa + self.t.start() + time.sleep(1) + +- pipe = mdssvc.mdssvc('ncacn_np:fileserver[/pipe/mdssvc]', self.get_loadparm()) +- conn = mdscli.conn(pipe, 'spotlight', '/foo') +- self.sharepath = conn.sharepath() +- conn.disconnect(pipe) ++ self.sharepath = os.environ["LOCAL_PATH"] + + for file in testfiles: + f = open("%s/%s" % (self.sharepath, file), "w") +@@ -126,5 +123,4 @@ class MdfindBlackboxTests(BlackboxTestCa + output = self.check_output("mdsearch -s %s -U %s%%%s fileserver spotlight '*==\"samba*\"'" % (config, username, password)) + + actual = output.decode('utf-8').splitlines() +- expected = ["%s/%s" % (self.sharepath, file) for file in testfiles] +- self.assertEqual(expected, actual) ++ self.assertEqual(testfiles, actual) +Index: samba/python/samba/tests/dcerpc/mdssvc.py +=================================================================== +--- samba.orig/python/samba/tests/dcerpc/mdssvc.py ++++ samba/python/samba/tests/dcerpc/mdssvc.py +@@ -84,10 +84,11 @@ class MdssvcTests(RpcInterfaceTestCase): + self.t = threading.Thread(target=MdssvcTests.http_server, args=(self,)) + self.t.setDaemon(True) + self.t.start() ++ self.sharepath = os.environ["LOCAL_PATH"] + time.sleep(1) + + conn = mdscli.conn(self.pipe, 'spotlight', '/foo') +- self.sharepath = conn.sharepath() ++ self.fakepath = conn.sharepath() + conn.disconnect(self.pipe) + + for file in testfiles: +@@ -105,12 +106,11 @@ class MdssvcTests(RpcInterfaceTestCase): + self.server.serve_forever() + + def run_test(self, query, expect, json_in, json_out): +- expect = [s.replace("%BASEPATH%", self.sharepath) for s in expect] + self.server.json_in = json_in.replace("%BASEPATH%", self.sharepath) + self.server.json_out = json_out.replace("%BASEPATH%", self.sharepath) + + self.conn = mdscli.conn(self.pipe, 'spotlight', '/foo') +- search = self.conn.search(self.pipe, query, self.sharepath) ++ search = self.conn.search(self.pipe, query, self.fakepath) + + # Give it some time, the get_results() below returns immediately + # what's available, so if we ask to soon, we might get back no results +@@ -141,7 +141,7 @@ class MdssvcTests(RpcInterfaceTestCase): + ] + } + }''' +- exp_results = ["%BASEPATH%/foo", "%BASEPATH%/bar"] ++ exp_results = ["foo", "bar"] + self.run_test('*=="samba*"', exp_results, exp_json_query, fake_json_response) + + def test_mdscli_search_escapes(self): +@@ -181,14 +181,14 @@ class MdssvcTests(RpcInterfaceTestCase): + } + }''' + exp_results = [ +- r"%BASEPATH%/x+x", +- r"%BASEPATH%/x*x", +- r"%BASEPATH%/x=x", +- r"%BASEPATH%/x'x", +- r"%BASEPATH%/x?x", +- r"%BASEPATH%/x x", +- r"%BASEPATH%/x(x", +- "%BASEPATH%/x\"x", +- r"%BASEPATH%/x\x", ++ r"x+x", ++ r"x*x", ++ r"x=x", ++ r"x'x", ++ r"x?x", ++ r"x x", ++ r"x(x", ++ "x\"x", ++ r"x\x", + ] + self.run_test(sl_query, exp_results, exp_json_query, fake_json_response) +Index: samba/source3/rpc_client/cli_mdssvc.c +=================================================================== +--- samba.orig/source3/rpc_client/cli_mdssvc.c ++++ samba/source3/rpc_client/cli_mdssvc.c +@@ -43,10 +43,12 @@ char *mdscli_get_basepath(TALLOC_CTX *me + struct mdscli_connect_state { + struct tevent_context *ev; + struct mdscli_ctx *mdscli_ctx; ++ struct mdssvc_blob response_blob; + }; + + static void mdscli_connect_open_done(struct tevent_req *subreq); + static void mdscli_connect_unknown1_done(struct tevent_req *subreq); ++static void mdscli_connect_fetch_props_done(struct tevent_req *subreq); + + struct tevent_req *mdscli_connect_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, +@@ -111,6 +113,7 @@ static void mdscli_connect_open_done(str + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); + struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ size_t share_path_len; + NTSTATUS status; + + status = dcerpc_mdssvc_open_recv(subreq, state); +@@ -120,6 +123,18 @@ static void mdscli_connect_open_done(str + return; + } + ++ share_path_len = strlen(mdscli_ctx->mdscmd_open.share_path); ++ if (share_path_len < 1 || share_path_len > UINT16_MAX) { ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ mdscli_ctx->mdscmd_open.share_path_len = share_path_len; ++ ++ if (mdscli_ctx->mdscmd_open.share_path[share_path_len-1] == '/') { ++ mdscli_ctx->mdscmd_open.share_path[share_path_len-1] = '\0'; ++ mdscli_ctx->mdscmd_open.share_path_len--; ++ } ++ + subreq = dcerpc_mdssvc_unknown1_send( + state, + state->ev, +@@ -146,6 +161,8 @@ static void mdscli_connect_unknown1_done + subreq, struct tevent_req); + struct mdscli_connect_state *state = tevent_req_data( + req, struct mdscli_connect_state); ++ struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ struct mdssvc_blob request_blob; + NTSTATUS status; + + status = dcerpc_mdssvc_unknown1_recv(subreq, state); +@@ -154,6 +171,108 @@ static void mdscli_connect_unknown1_done + return; + } + ++ status = mdscli_blob_fetch_props(state, ++ state->mdscli_ctx, ++ &request_blob); ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ ++ subreq = dcerpc_mdssvc_cmd_send(state, ++ state->ev, ++ mdscli_ctx->bh, ++ &mdscli_ctx->ph, ++ 0, ++ mdscli_ctx->dev, ++ mdscli_ctx->mdscmd_open.unkn2, ++ 0, ++ mdscli_ctx->flags, ++ request_blob, ++ 0, ++ mdscli_ctx->max_fragment_size, ++ 1, ++ mdscli_ctx->max_fragment_size, ++ 0, ++ 0, ++ &mdscli_ctx->mdscmd_cmd.fragment, ++ &state->response_blob, ++ &mdscli_ctx->mdscmd_cmd.unkn9); ++ if (tevent_req_nomem(subreq, req)) { ++ return; ++ } ++ tevent_req_set_callback(subreq, mdscli_connect_fetch_props_done, req); ++ mdscli_ctx->async_pending++; ++ return; ++} ++ ++static void mdscli_connect_fetch_props_done(struct tevent_req *subreq) ++{ ++ struct tevent_req *req = tevent_req_callback_data( ++ subreq, struct tevent_req); ++ struct mdscli_connect_state *state = tevent_req_data( ++ req, struct mdscli_connect_state); ++ struct mdscli_ctx *mdscli_ctx = state->mdscli_ctx; ++ DALLOC_CTX *d = NULL; ++ sl_array_t *path_scope_array = NULL; ++ char *path_scope = NULL; ++ NTSTATUS status; ++ bool ok; ++ ++ status = dcerpc_mdssvc_cmd_recv(subreq, state); ++ TALLOC_FREE(subreq); ++ state->mdscli_ctx->async_pending--; ++ if (tevent_req_nterror(req, status)) { ++ return; ++ } ++ ++ d = dalloc_new(state); ++ if (tevent_req_nomem(d, req)) { ++ return; ++ } ++ ++ ok = sl_unpack(d, ++ (char *)state->response_blob.spotlight_blob, ++ state->response_blob.length); ++ if (!ok) { ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ path_scope_array = dalloc_value_for_key(d, ++ "DALLOC_CTX", 0, ++ "kMDSStorePathScopes", ++ "sl_array_t"); ++ if (path_scope_array == NULL) { ++ DBG_ERR("Missing kMDSStorePathScopes\n"); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ path_scope = dalloc_get(path_scope_array, "char *", 0); ++ if (path_scope == NULL) { ++ DBG_ERR("Missing path in kMDSStorePathScopes\n"); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ ++ mdscli_ctx->path_scope_len = strlen(path_scope); ++ if (mdscli_ctx->path_scope_len < 1 || ++ mdscli_ctx->path_scope_len > UINT16_MAX) ++ { ++ DBG_ERR("Bad path_scope: %s\n", path_scope); ++ tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); ++ return; ++ } ++ mdscli_ctx->path_scope = talloc_strdup(mdscli_ctx, path_scope); ++ if (tevent_req_nomem(mdscli_ctx->path_scope, req)) { ++ return; ++ } ++ ++ if (mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] == '/') { ++ mdscli_ctx->path_scope[mdscli_ctx->path_scope_len-1] = '\0'; ++ mdscli_ctx->path_scope_len--; ++ } ++ + tevent_req_done(req); + } + +@@ -697,7 +816,10 @@ static void mdscli_get_path_done(struct + struct mdscli_get_path_state *state = tevent_req_data( + req, struct mdscli_get_path_state); + DALLOC_CTX *d = NULL; ++ size_t pathlen; ++ size_t prefixlen; + char *path = NULL; ++ const char *p = NULL; + NTSTATUS status; + bool ok; + +@@ -732,7 +854,38 @@ static void mdscli_get_path_done(struct + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } +- state->path = talloc_move(state, &path); ++ ++ /* Path is prefixed by /PATHSCOPE/SHARENAME/, strip it */ ++ pathlen = strlen(path); ++ ++ /* ++ * path_scope_len and share_path_len are already checked to be smaller ++ * then UINT16_MAX so this can't overflow ++ */ ++ prefixlen = state->mdscli_ctx->path_scope_len ++ + state->mdscli_ctx->mdscmd_open.share_path_len; ++ ++ if (pathlen < prefixlen) { ++ DBG_DEBUG("Bad path: %s\n", path); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return; ++ } ++ ++ p = path + prefixlen; ++ while (*p == '/') { ++ p++; ++ } ++ if (*p == '\0') { ++ DBG_DEBUG("Bad path: %s\n", path); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return; ++ } ++ ++ state->path = talloc_strdup(state, p); ++ if (state->path == NULL) { ++ tevent_req_nterror(req, NT_STATUS_NO_MEMORY); ++ return; ++ } + DBG_DEBUG("path: %s\n", state->path); + + tevent_req_done(req); +Index: samba/source3/rpc_client/cli_mdssvc_private.h +=================================================================== +--- samba.orig/source3/rpc_client/cli_mdssvc_private.h ++++ samba/source3/rpc_client/cli_mdssvc_private.h +@@ -42,6 +42,7 @@ struct mdscli_ctx { + /* cmd specific or unknown fields */ + struct { + char share_path[1025]; ++ size_t share_path_len; + uint32_t unkn2; + uint32_t unkn3; + } mdscmd_open; +@@ -56,6 +57,9 @@ struct mdscli_ctx { + struct { + uint32_t status; + } mdscmd_close; ++ ++ char *path_scope; ++ size_t path_scope_len; + }; + + struct mdscli_search_ctx { +Index: samba/source3/rpc_client/cli_mdssvc_util.c +=================================================================== +--- samba.orig/source3/rpc_client/cli_mdssvc_util.c ++++ samba/source3/rpc_client/cli_mdssvc_util.c +@@ -28,6 +28,74 @@ + #include "rpc_server/mdssvc/dalloc.h" + #include "rpc_server/mdssvc/marshalling.h" + ++NTSTATUS mdscli_blob_fetch_props(TALLOC_CTX *mem_ctx, ++ struct mdscli_ctx *ctx, ++ struct mdssvc_blob *blob) ++{ ++ DALLOC_CTX *d = NULL; ++ uint64_t *uint64p = NULL; ++ sl_array_t *array = NULL; ++ sl_array_t *cmd_array = NULL; ++ NTSTATUS status; ++ int ret; ++ ++ d = dalloc_new(mem_ctx); ++ if (d == NULL) { ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ array = dalloc_zero(d, sl_array_t); ++ if (array == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_add(d, array, sl_array_t); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ cmd_array = dalloc_zero(d, sl_array_t); ++ if (cmd_array == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_add(array, cmd_array, sl_array_t); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ ret = dalloc_stradd(cmd_array, "fetchPropertiesForContext:"); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ uint64p = talloc_zero_array(cmd_array, uint64_t, 2); ++ if (uint64p == NULL) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ talloc_set_name(uint64p, "uint64_t *"); ++ ++ ret = dalloc_add(cmd_array, uint64p, uint64_t *); ++ if (ret != 0) { ++ TALLOC_FREE(d); ++ return NT_STATUS_NO_MEMORY; ++ } ++ ++ status = sl_pack_alloc(mem_ctx, d, blob, ctx->max_fragment_size); ++ TALLOC_FREE(d); ++ if (!NT_STATUS_IS_OK(status)) { ++ return status; ++ } ++ return NT_STATUS_OK; ++} ++ + NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob) +Index: samba/source3/rpc_client/cli_mdssvc_util.h +=================================================================== +--- samba.orig/source3/rpc_client/cli_mdssvc_util.h ++++ samba/source3/rpc_client/cli_mdssvc_util.h +@@ -21,6 +21,10 @@ + #ifndef _MDSCLI_UTIL_H_ + #define _MDSCLI_UTIL_H_ + ++NTSTATUS mdscli_blob_fetch_props(TALLOC_CTX *mem_ctx, ++ struct mdscli_ctx *ctx, ++ struct mdssvc_blob *blob); ++ + NTSTATUS mdscli_blob_search(TALLOC_CTX *mem_ctx, + struct mdscli_search_ctx *search, + struct mdssvc_blob *blob); diff -Nru samba-4.13.13+dfsg/debian/patches/0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch samba-4.13.13+dfsg/debian/patches/0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch --- samba-4.13.13+dfsg/debian/patches/0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,213 @@ +From 1809843614bbd407db221ace2c90faf9259065b0 Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Mon, 5 Jun 2023 18:02:20 +0200 +Subject: [PATCH 11/11] CVE-2023-34968: mdssvc: return a fake share path + +Instead of returning the real server-side absolute path of shares and search +results, return a fake absolute path replacing the path of the share with the +share name, iow for a share "test" with a server-side path of "/foo/bar", we +previously returned + + /foo/bar and + /foo/bar/search/result + +and now return + + /test and + /test/search/result + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15388 + +Signed-off-by: Ralph Boehme +Reviewed-by: Stefan Metzmacher +--- + source3/rpc_server/mdssvc/mdssvc.c | 61 +++++++++++++++++++++-- + source3/rpc_server/mdssvc/mdssvc.h | 1 + + source3/rpc_server/mdssvc/srv_mdssvc_nt.c | 18 +++++-- + 3 files changed, 73 insertions(+), 7 deletions(-) + +Index: samba/source3/rpc_server/mdssvc/mdssvc.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.c ++++ samba/source3/rpc_server/mdssvc/mdssvc.c +@@ -519,11 +519,14 @@ static bool inode_map_add(struct sl_quer + bool mds_add_result(struct sl_query *slq, const char *path) + { + struct smb_filename *smb_fname = NULL; ++ const char *relative = NULL; ++ char *fake_path = NULL; + struct stat_ex sb; + uint32_t attr; + uint64_t ino64; + int result; + NTSTATUS status; ++ bool sub; + bool ok; + + smb_fname = synthetic_smb_fname(talloc_tos(), +@@ -614,6 +617,17 @@ bool mds_add_result(struct sl_query *slq + } + } + ++ sub = subdir_of(slq->mds_ctx->spath, ++ slq->mds_ctx->spath_len, ++ path, ++ &relative); ++ if (!sub) { ++ DBG_ERR("[%s] is not inside [%s]\n", ++ path, slq->mds_ctx->spath); ++ slq->state = SLQ_STATE_ERROR; ++ return false; ++ } ++ + /* + * Add inode number and filemeta to result set, this is what + * we return as part of the result set of a query +@@ -626,18 +640,30 @@ bool mds_add_result(struct sl_query *slq + slq->state = SLQ_STATE_ERROR; + return false; + } ++ ++ fake_path = talloc_asprintf(slq, ++ "/%s/%s", ++ slq->mds_ctx->sharename, ++ relative); ++ if (fake_path == NULL) { ++ slq->state = SLQ_STATE_ERROR; ++ return false; ++ } ++ + ok = add_filemeta(slq->mds_ctx, + slq->reqinfo, + slq->query_results->fm_array, +- path, ++ fake_path, + &sb); + if (!ok) { + DBG_ERR("add_filemeta error\n"); ++ TALLOC_FREE(fake_path); + slq->state = SLQ_STATE_ERROR; + return false; + } + +- ok = inode_map_add(slq, ino64, path, &sb); ++ ok = inode_map_add(slq, ino64, fake_path, &sb); ++ TALLOC_FREE(fake_path); + if (!ok) { + DEBUG(1, ("inode_map_add error\n")); + slq->state = SLQ_STATE_ERROR; +@@ -845,6 +871,32 @@ static void slq_close_timer(struct teven + } + + /** ++ * Translate a fake scope from the client like /sharename/dir ++ * to the real server-side path, replacing the "/sharename" part ++ * with the absolute server-side path of the share. ++ **/ ++static bool mdssvc_real_scope(struct sl_query *slq, const char *fake_scope) ++{ ++ size_t sname_len = strlen(slq->mds_ctx->sharename); ++ size_t fake_scope_len = strlen(fake_scope); ++ ++ if (fake_scope_len < sname_len + 1) { ++ DBG_ERR("Short scope [%s] for share [%s]\n", ++ fake_scope, slq->mds_ctx->sharename); ++ return false; ++ } ++ ++ slq->path_scope = talloc_asprintf(slq, ++ "%s%s", ++ slq->mds_ctx->spath, ++ fake_scope + sname_len + 1); ++ if (slq->path_scope == NULL) { ++ return false; ++ } ++ return true; ++} ++ ++/** + * Begin a search query + **/ + static bool slrpc_open_query(struct mds_ctx *mds_ctx, +@@ -950,8 +1002,8 @@ static bool slrpc_open_query(struct mds_ + goto error; + } + +- slq->path_scope = talloc_strdup(slq, scope); +- if (slq->path_scope == NULL) { ++ ok = mdssvc_real_scope(slq, scope); ++ if (!ok) { + goto error; + } + +@@ -1665,6 +1717,7 @@ struct mds_ctx *mds_init_ctx(TALLOC_CTX + if (mds_ctx->spath == NULL) { + goto error; + } ++ mds_ctx->spath_len = strlen(path); + + mds_ctx->snum = snum; + mds_ctx->pipe_session_info = session_info; +Index: samba/source3/rpc_server/mdssvc/mdssvc.h +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/mdssvc.h ++++ samba/source3/rpc_server/mdssvc/mdssvc.h +@@ -127,6 +127,7 @@ struct mds_ctx { + int snum; + const char *sharename; + const char *spath; ++ size_t spath_len; + struct connection_struct *conn; + struct sl_query *query_list; /* list of active queries */ + struct db_context *ino_path_map; /* dbwrap rbt for storing inode->path mappings */ +Index: samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +=================================================================== +--- samba.orig/source3/rpc_server/mdssvc/srv_mdssvc_nt.c ++++ samba/source3/rpc_server/mdssvc/srv_mdssvc_nt.c +@@ -120,6 +120,7 @@ void _mdssvc_open(struct pipes_struct *p + loadparm_s3_global_substitution(); + int snum; + char *outpath = discard_const_p(char, r->out.share_path); ++ char *fake_path = NULL; + char *path; + NTSTATUS status; + +@@ -137,12 +138,21 @@ void _mdssvc_open(struct pipes_struct *p + + path = lp_path(talloc_tos(), lp_sub, snum); + if (path == NULL) { +- DBG_ERR("Couldn't create policy handle for %s\n", ++ DBG_ERR("Couldn't create path for %s\n", + r->in.share_name); + p->fault_state = DCERPC_FAULT_CANT_PERFORM; + return; + } + ++ fake_path = talloc_asprintf(p->mem_ctx, "/%s", r->in.share_name); ++ if (fake_path == NULL) { ++ DBG_ERR("Couldn't create fake share path for %s\n", ++ r->in.share_name); ++ talloc_free(path); ++ p->fault_state = DCERPC_FAULT_CANT_PERFORM; ++ return; ++ } ++ + status = create_mdssvc_policy_handle(p->mem_ctx, p, + snum, + r->in.share_name, +@@ -152,12 +162,13 @@ void _mdssvc_open(struct pipes_struct *p + DBG_ERR("Couldn't create policy handle for %s\n", + r->in.share_name); + talloc_free(path); ++ talloc_free(fake_path); + p->fault_state = DCERPC_FAULT_CANT_PERFORM; + return; + } + +- strlcpy(outpath, path, 1024); +- talloc_free(path); ++ strlcpy(outpath, fake_path, 1024); ++ talloc_free(fake_path); + return; + } + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-1.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-1.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-1.patch 2024-03-18 12:28:21.000000000 +0000 @@ -0,0 +1,61 @@ +From 914b19c9511d55183d97d18ae6e0648e0766738d Mon Sep 17 00:00:00 2001 +From: Samuel Cabrero +Date: Thu, 24 Feb 2022 17:48:27 +0100 +Origin: ubuntu, https://git.launchpad.net/ubuntu/+source/samba/tree/debian/patches?h=import/2%254.15.13%2bdfsg-0ubuntu0.20.04.7 +Subject: [PATCH 1/3] CVE-2022-2127: s3:winbind: Move big NTLMv2 blob checks to + parent process + +The winbindd_dual_pam_auth_crap() function will be converted to a local +RPC call handler and it won't receive a winbindd_cli_state struct. Move +the checks accessing this struct to the parent. + +Signed-off-by: Samuel Cabrero +Reviewed-by: Jeremy Allison +(cherry picked from commit 74a511a8eab72cc82940738a1e20e63e12b81374) +--- + source3/winbindd/winbindd_pam.c | 12 ------------ + source3/winbindd/winbindd_pam_auth_crap.c | 12 ++++++++++++ + 2 files changed, 12 insertions(+), 12 deletions(-) + +--- a/source3/winbindd/winbindd_pam.c ++++ b/source3/winbindd/winbindd_pam.c +@@ -2606,18 +2606,6 @@ enum winbindd_result winbindd_dual_pam_a + DEBUG(3, ("[%5lu]: pam auth crap domain: %s user: %s\n", (unsigned long)state->pid, + name_domain, name_user)); + +- if (state->request->data.auth_crap.lm_resp_len > sizeof(state->request->data.auth_crap.lm_resp) +- || state->request->data.auth_crap.nt_resp_len > sizeof(state->request->data.auth_crap.nt_resp)) { +- if (!(state->request->flags & WBFLAG_BIG_NTLMV2_BLOB) || +- state->request->extra_len != state->request->data.auth_crap.nt_resp_len) { +- DEBUG(0, ("winbindd_pam_auth_crap: invalid password length %u/%u\n", +- state->request->data.auth_crap.lm_resp_len, +- state->request->data.auth_crap.nt_resp_len)); +- result = NT_STATUS_INVALID_PARAMETER; +- goto done; +- } +- } +- + lm_resp = data_blob_talloc(state->mem_ctx, state->request->data.auth_crap.lm_resp, + state->request->data.auth_crap.lm_resp_len); + +--- a/source3/winbindd/winbindd_pam_auth_crap.c ++++ b/source3/winbindd/winbindd_pam_auth_crap.c +@@ -140,6 +140,18 @@ struct tevent_req *winbindd_pam_auth_cra + fstrcpy(request->data.auth_crap.workstation, lp_netbios_name()); + } + ++ if (request->data.auth_crap.lm_resp_len > sizeof(request->data.auth_crap.lm_resp) ++ || request->data.auth_crap.nt_resp_len > sizeof(request->data.auth_crap.nt_resp)) { ++ if (!(request->flags & WBFLAG_BIG_NTLMV2_BLOB) || ++ request->extra_len != request->data.auth_crap.nt_resp_len) { ++ DBG_ERR("Invalid password length %u/%u\n", ++ request->data.auth_crap.lm_resp_len, ++ request->data.auth_crap.nt_resp_len); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return tevent_req_post(req, ev); ++ } ++ } ++ + subreq = wb_domain_request_send(state, global_event_context(), domain, + request); + if (tevent_req_nomem(subreq, req)) { diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-2.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-2.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-2.patch 2024-03-18 12:28:21.000000000 +0000 @@ -0,0 +1,73 @@ +From c49caa7a8d4abf4185ec1a07ebfeb57d0bdc5754 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 20 May 2022 10:55:23 +0200 +Subject: [PATCH 2/3] CVE-2022-2127: winbindd: Fix WINBINDD_PAM_AUTH_CRAP + length checks +Origin: ubuntu, https://git.launchpad.net/ubuntu/+source/samba/tree/debian/patches?h=import/2%254.15.13%2bdfsg-0ubuntu0.20.04.7 + +With WBFLAG_BIG_NTLMV2_BLOB being set plus lm_resp_len too large you +can crash winbind. We don't independently check lm_resp_len +sufficiently. + +Discovered via Coverity ID 1504444 Out-of-bounds access + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15072 + +Signed-off-by: Volker Lendecke +--- + source3/winbindd/winbindd_pam_auth_crap.c | 31 +++++++++++++++-------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/source3/winbindd/winbindd_pam_auth_crap.c b/source3/winbindd/winbindd_pam_auth_crap.c +index fdb8120a6fe7..651d54b01d33 100644 +--- a/source3/winbindd/winbindd_pam_auth_crap.c ++++ b/source3/winbindd/winbindd_pam_auth_crap.c +@@ -42,6 +42,9 @@ struct tevent_req *winbindd_pam_auth_crap_send( + struct winbindd_pam_auth_crap_state *state; + struct winbindd_domain *domain; + const char *auth_domain = NULL; ++ bool lmlength_ok = false; ++ bool ntlength_ok = false; ++ bool pwlength_ok = false; + + req = tevent_req_create(mem_ctx, &state, + struct winbindd_pam_auth_crap_state); +@@ -140,16 +143,24 @@ struct tevent_req *winbindd_pam_auth_crap_send( + fstrcpy(request->data.auth_crap.workstation, lp_netbios_name()); + } + +- if (request->data.auth_crap.lm_resp_len > sizeof(request->data.auth_crap.lm_resp) +- || request->data.auth_crap.nt_resp_len > sizeof(request->data.auth_crap.nt_resp)) { +- if (!(request->flags & WBFLAG_BIG_NTLMV2_BLOB) || +- request->extra_len != request->data.auth_crap.nt_resp_len) { +- DBG_ERR("Invalid password length %u/%u\n", +- request->data.auth_crap.lm_resp_len, +- request->data.auth_crap.nt_resp_len); +- tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); +- return tevent_req_post(req, ev); +- } ++ lmlength_ok = (request->data.auth_crap.lm_resp_len <= ++ sizeof(request->data.auth_crap.lm_resp)); ++ ++ ntlength_ok = (request->data.auth_crap.nt_resp_len <= ++ sizeof(request->data.auth_crap.nt_resp)); ++ ++ ntlength_ok |= ++ ((request->flags & WBFLAG_BIG_NTLMV2_BLOB) && ++ (request->extra_len == request->data.auth_crap.nt_resp_len)); ++ ++ pwlength_ok = lmlength_ok && ntlength_ok; ++ ++ if (!pwlength_ok) { ++ DBG_ERR("Invalid password length %u/%u\n", ++ request->data.auth_crap.lm_resp_len, ++ request->data.auth_crap.nt_resp_len); ++ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); ++ return tevent_req_post(req, ev); + } + + subreq = wb_domain_request_send(state, global_event_context(), domain, +-- +2.41.0 + + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-3.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-3.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-2127-3.patch 2024-03-18 12:28:21.000000000 +0000 @@ -0,0 +1,36 @@ +From c056d948646f5b7a4fbeb607872ee64fa2d1a26e Mon Sep 17 00:00:00 2001 +From: Ralph Boehme +Date: Fri, 16 Jun 2023 12:28:47 +0200 +Subject: [PATCH 3/3] CVE-2022-2127: ntlm_auth: cap lanman response length + value +Origin: ubuntu, https://git.launchpad.net/ubuntu/+source/samba/tree/debian/patches?h=import/2%254.15.13%2bdfsg-0ubuntu0.20.04.7 + +We already copy at most sizeof(request.data.auth_crap.lm_resp) bytes to the +lm_resp buffer, but we don't cap the length indicator. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15072 + +Signed-off-by: Ralph Boehme +--- + source3/utils/ntlm_auth.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/source3/utils/ntlm_auth.c ++++ b/source3/utils/ntlm_auth.c +@@ -574,10 +574,14 @@ NTSTATUS contact_winbind_auth_crap(const + memcpy(request.data.auth_crap.chal, challenge->data, MIN(challenge->length, 8)); + + if (lm_response && lm_response->length) { ++ size_t capped_lm_response_len = MIN( ++ lm_response->length, ++ sizeof(request.data.auth_crap.lm_resp)); ++ + memcpy(request.data.auth_crap.lm_resp, + lm_response->data, +- MIN(lm_response->length, sizeof(request.data.auth_crap.lm_resp))); +- request.data.auth_crap.lm_resp_len = lm_response->length; ++ capped_lm_response_len); ++ request.data.auth_crap.lm_resp_len = capped_lm_response_len; + } + + if (nt_response && nt_response->length) { diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-1.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-1.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-1.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-1.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,1470 @@ +Index: samba/source4/heimdal/lib/krb5/krb5_locl.h +=================================================================== +--- samba.orig/source4/heimdal/lib/krb5/krb5_locl.h ++++ samba/source4/heimdal/lib/krb5/krb5_locl.h +@@ -188,10 +188,6 @@ struct _krb5_krb_auth_data; + #define ALLOC(X, N) (X) = calloc((N), sizeof(*(X))) + #define ALLOC_SEQ(X, N) do { (X)->len = (N); ALLOC((X)->val, (N)); } while(0) + +-#ifndef __func__ +-#define __func__ "unknown-function" +-#endif +- + #define krb5_einval(context, argnum) _krb5_einval((context), __func__, (argnum)) + + #ifndef PATH_SEP +Index: samba/source4/heimdal_build/wscript_build +=================================================================== +--- samba.orig/source4/heimdal_build/wscript_build ++++ samba/source4/heimdal_build/wscript_build +@@ -556,8 +556,8 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSA + HEIMDAL_AUTOPROTO_PRIVATE('lib/gssapi/krb5/gsskrb5-private.h', + HEIMDAL_GSSAPI_KRB5_SOURCE) + +- HEIMDAL_LIBRARY('gssapi', +- HEIMDAL_GSSAPI_SPNEGO_SOURCE + HEIMDAL_GSSAPI_KRB5_SOURCE + ''' ++ HEIMDAL_SUBSYSTEM('gssapi-subsystem', ++ HEIMDAL_GSSAPI_SPNEGO_SOURCE + HEIMDAL_GSSAPI_KRB5_SOURCE + ''' + lib/gssapi/mech/context.c lib/gssapi/mech/gss_krb5.c lib/gssapi/mech/gss_mech_switch.c + lib/gssapi/mech/gss_process_context_token.c lib/gssapi/mech/gss_buffer_set.c + lib/gssapi/mech/gss_aeap.c lib/gssapi/mech/gss_add_cred.c lib/gssapi/mech/gss_cred.c +@@ -582,10 +582,16 @@ if not bld.CONFIG_SET("USING_SYSTEM_GSSA + lib/gssapi/mech/gss_set_cred_option.c lib/gssapi/mech/gss_pseudo_random.c ../heimdal_build/gssapi-glue.c''', + includes='../heimdal/lib/gssapi ../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech', + deps='hcrypto asn1 HEIMDAL_SPNEGO_ASN1 HEIMDAL_GSSAPI_ASN1 roken krb5 com_err wind', +- vnum='2.0.0', +- version_script='lib/gssapi/version-script.map', + ) + ++ HEIMDAL_LIBRARY('gssapi', ++ '', ++ includes='../heimdal/lib/gssapi ../heimdal/lib/gssapi/gssapi ../heimdal/lib/gssapi/spnego ../heimdal/lib/gssapi/krb5 ../heimdal/lib/gssapi/mech', ++ deps='gssapi-subsystem', ++ vnum='2.0.0', ++ version_script='lib/gssapi/version-script.map', ++ ) ++ + if not bld.CONFIG_SET("USING_SYSTEM_KRB5"): + # expand_path.c needs some of the install paths + HEIMDAL_SUBSYSTEM('HEIMDAL_CONFIG', +Index: samba/selftest/knownfail.d/heimdal-des-overflow +=================================================================== +--- /dev/null ++++ samba/selftest/knownfail.d/heimdal-des-overflow +@@ -0,0 +1,9 @@ ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_missing_payload.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_with_seal_missing_payload.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_1.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none ++^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none +Index: samba/selftest/tests.py +=================================================================== +--- samba.orig/selftest/tests.py ++++ samba/selftest/tests.py +@@ -47,6 +47,8 @@ with_pam = ("WITH_PAM" in config_hash) + with_elasticsearch_backend = ("HAVE_SPOTLIGHT_BACKEND_ES" in config_hash) + pam_wrapper_so_path = config_hash["LIBPAM_WRAPPER_SO_PATH"] + pam_set_items_so_path = config_hash["PAM_SET_ITEMS_SO_PATH"] ++have_heimdal_support = "SAMBA4_USES_HEIMDAL" in config_hash ++using_system_gssapi = "USING_SYSTEM_GSSAPI" in config_hash + + planpythontestsuite("none", "samba.tests.source") + if have_man_pages_support: +@@ -414,6 +416,9 @@ plantestsuite("samba.unittests.test_regi + [os.path.join(bindir(), "default/source3/test_registry_regfio")]) + plantestsuite("samba.unittests.test_oLschema2ldif", "none", + [os.path.join(bindir(), "default/source4/utils/oLschema2ldif/test_oLschema2ldif")]) ++if have_heimdal_support and not using_system_gssapi: ++ plantestsuite("samba.unittests.auth.heimdal_gensec_unwrap_des", "none", ++ [valgrindify(os.path.join(bindir(), "test_heimdal_gensec_unwrap_des"))]) + if with_elasticsearch_backend: + plantestsuite("samba.unittests.mdsparser_es", "none", + [os.path.join(bindir(), "default/source3/test_mdsparser_es")] + [configuration]) +Index: samba/source4/auth/tests/heimdal_unwrap_des.c +=================================================================== +--- /dev/null ++++ samba/source4/auth/tests/heimdal_unwrap_des.c +@@ -0,0 +1,1247 @@ ++/* ++ * Unit tests for source4/heimdal/lib/gssapi/krb5/unwrap.c ++ * ++ * Copyright (C) Catalyst.NET Ltd 2022 ++ * ++ * 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 "includes.h" ++#include "replace.h" ++ ++#define HEIMDAL_NORETURN_ATTRIBUTE _NORETURN_ ++#define HEIMDAL_PRINTF_ATTRIBUTE(x) FORMAT_ATTRIBUTE(x) ++ ++#include "../../../source4/heimdal/lib/gssapi/gssapi/gssapi.h" ++#include "gsskrb5_locl.h" ++ ++/****************************************************************************** ++ * Helper functions ++ ******************************************************************************/ ++ ++const uint8_t *valid_range_begin; ++const uint8_t *valid_range_end; ++const uint8_t *invalid_range_end; ++ ++/* ++ * 'array_len' is the size of the passed in array. 'buffer_len' is the size to ++ * report in the resulting buffer. ++ */ ++static const gss_buffer_desc get_input_buffer(TALLOC_CTX *mem_ctx, ++ const uint8_t array[], ++ const size_t array_len, ++ const size_t buffer_len) ++{ ++ gss_buffer_desc buf; ++ ++ /* Add some padding to catch invalid memory accesses. */ ++ const size_t padding = 0x100; ++ const size_t padded_len = array_len + padding; ++ ++ uint8_t *data = talloc_size(mem_ctx, padded_len); ++ assert_non_null(data); ++ ++ memcpy(data, array, array_len); ++ memset(data + array_len, 0, padding); ++ ++ assert_in_range(buffer_len, 0, array_len); ++ ++ buf.value = data; ++ buf.length = buffer_len; ++ ++ valid_range_begin = buf.value; ++ valid_range_end = valid_range_begin + buf.length; ++ invalid_range_end = valid_range_begin + padded_len; ++ ++ return buf; ++} ++ ++static void assert_mem_in_valid_range(const uint8_t *ptr, const size_t len) ++{ ++ /* Ensure we've set up the range pointers properly. */ ++ assert_non_null(valid_range_begin); ++ assert_non_null(valid_range_end); ++ assert_non_null(invalid_range_end); ++ ++ /* ++ * Ensure the length isn't excessively large (a symptom of integer ++ * underflow). ++ */ ++ assert_in_range(len, 0, 0x1000); ++ ++ /* Ensure the memory is in our valid range. */ ++ assert_in_range(ptr, valid_range_begin, valid_range_end); ++ assert_in_range(ptr + len, valid_range_begin, valid_range_end); ++} ++ ++/* ++ * This function takes a pointer to volatile to allow it to be called from the ++ * ct_memcmp() wrapper. ++ */ ++static void assert_mem_outside_invalid_range(const volatile uint8_t *ptr, ++ const size_t len) ++{ ++ const LargestIntegralType _valid_range_end ++ = cast_ptr_to_largest_integral_type(valid_range_end); ++ const LargestIntegralType _invalid_range_end ++ = cast_ptr_to_largest_integral_type(invalid_range_end); ++ const LargestIntegralType _ptr = cast_ptr_to_largest_integral_type(ptr); ++ const LargestIntegralType _len = cast_to_largest_integral_type(len); ++ ++ /* Ensure we've set up the range pointers properly. */ ++ assert_non_null(valid_range_begin); ++ assert_non_null(valid_range_end); ++ assert_non_null(invalid_range_end); ++ ++ /* ++ * Ensure the length isn't excessively large (a symptom of integer ++ * underflow). ++ */ ++ assert_in_range(len, 0, 0x1000); ++ ++ /* Ensure the memory is outside the invalid range. */ ++ if (_ptr < _invalid_range_end && _ptr + _len > _valid_range_end) { ++ fail(); ++ } ++} ++ ++/***************************************************************************** ++ * wrapped functions ++ *****************************************************************************/ ++ ++krb5_keyblock dummy_key; ++ ++krb5_error_code __wrap_krb5_auth_con_getlocalsubkey(krb5_context context, ++ krb5_auth_context auth_context, ++ krb5_keyblock **keyblock); ++krb5_error_code __wrap_krb5_auth_con_getlocalsubkey(krb5_context context, ++ krb5_auth_context auth_context, ++ krb5_keyblock **keyblock) ++{ ++ *keyblock = &dummy_key; ++ return 0; ++} ++ ++void __wrap_krb5_free_keyblock(krb5_context context, ++ krb5_keyblock *keyblock); ++void __wrap_krb5_free_keyblock(krb5_context context, ++ krb5_keyblock *keyblock) ++{ ++ assert_ptr_equal(&dummy_key, keyblock); ++} ++ ++struct krb5_crypto_data dummy_crypto; ++ ++krb5_error_code __wrap_krb5_crypto_init(krb5_context context, ++ const krb5_keyblock *key, ++ krb5_enctype etype, ++ krb5_crypto *crypto); ++krb5_error_code __wrap_krb5_crypto_init(krb5_context context, ++ const krb5_keyblock *key, ++ krb5_enctype etype, ++ krb5_crypto *crypto) ++{ ++ static const LargestIntegralType etypes[] = {ETYPE_DES3_CBC_NONE, 0}; ++ ++ assert_ptr_equal(&dummy_key, key); ++ assert_in_set(etype, etypes, ARRAY_SIZE(etypes)); ++ ++ *crypto = &dummy_crypto; ++ ++ return 0; ++} ++ ++krb5_error_code __wrap_krb5_decrypt(krb5_context context, ++ krb5_crypto crypto, ++ unsigned usage, ++ void *data, ++ size_t len, ++ krb5_data *result); ++krb5_error_code __wrap_krb5_decrypt(krb5_context context, ++ krb5_crypto crypto, ++ unsigned usage, ++ void *data, ++ size_t len, ++ krb5_data *result) ++{ ++ assert_ptr_equal(&dummy_crypto, crypto); ++ assert_int_equal(KRB5_KU_USAGE_SEAL, usage); ++ ++ assert_mem_in_valid_range(data, len); ++ ++ check_expected(len); ++ check_expected_ptr(data); ++ ++ result->data = malloc(len); ++ assert_non_null(result->data); ++ result->length = len; ++ ++ memcpy(result->data, data, len); ++ ++ return 0; ++} ++ ++krb5_error_code __wrap_krb5_decrypt_ivec(krb5_context context, ++ krb5_crypto crypto, ++ unsigned usage, ++ void *data, ++ size_t len, ++ krb5_data *result, ++ void *ivec); ++krb5_error_code __wrap_krb5_decrypt_ivec(krb5_context context, ++ krb5_crypto crypto, ++ unsigned usage, ++ void *data, ++ size_t len, ++ krb5_data *result, ++ void *ivec) ++{ ++ assert_ptr_equal(&dummy_crypto, crypto); ++ assert_int_equal(KRB5_KU_USAGE_SEQ, usage); ++ ++ assert_mem_in_valid_range(data, len); ++ ++ assert_int_equal(8, len); ++ check_expected_ptr(data); ++ check_expected_ptr(ivec); ++ ++ result->data = malloc(len); ++ assert_non_null(result->data); ++ result->length = len; ++ ++ memcpy(result->data, data, len); ++ ++ return 0; ++} ++ ++krb5_error_code __wrap_krb5_verify_checksum(krb5_context context, ++ krb5_crypto crypto, ++ krb5_key_usage usage, ++ void *data, ++ size_t len, ++ Checksum *cksum); ++krb5_error_code __wrap_krb5_verify_checksum(krb5_context context, ++ krb5_crypto crypto, ++ krb5_key_usage usage, ++ void *data, ++ size_t len, ++ Checksum *cksum) ++{ ++ assert_ptr_equal(&dummy_crypto, crypto); ++ assert_int_equal(KRB5_KU_USAGE_SIGN, usage); ++ ++ assert_mem_in_valid_range(data, len); ++ ++ check_expected(len); ++ check_expected_ptr(data); ++ ++ assert_non_null(cksum); ++ assert_int_equal(CKSUMTYPE_HMAC_SHA1_DES3, cksum->cksumtype); ++ assert_int_equal(20, cksum->checksum.length); ++ check_expected_ptr(cksum->checksum.data); ++ ++ return 0; ++} ++ ++krb5_error_code __wrap_krb5_crypto_destroy(krb5_context context, ++ krb5_crypto crypto); ++krb5_error_code __wrap_krb5_crypto_destroy(krb5_context context, ++ krb5_crypto crypto) ++{ ++ assert_ptr_equal(&dummy_crypto, crypto); ++ ++ return 0; ++} ++ ++ ++int __wrap_der_get_length(const unsigned char *p, ++ size_t len, ++ size_t *val, ++ size_t *size); ++int __real_der_get_length(const unsigned char *p, ++ size_t len, ++ size_t *val, ++ size_t *size); ++int __wrap_der_get_length(const unsigned char *p, ++ size_t len, ++ size_t *val, ++ size_t *size) ++{ ++ assert_mem_in_valid_range(p, len); ++ ++ return __real_der_get_length(p, len, val, size); ++} ++ ++int __wrap_ct_memcmp(const volatile void * volatile p1, ++ const volatile void * volatile p2, ++ size_t len); ++int __real_ct_memcmp(const volatile void * volatile p1, ++ const volatile void * volatile p2, ++ size_t len); ++int __wrap_ct_memcmp(const volatile void * volatile p1, ++ const volatile void * volatile p2, ++ size_t len) ++{ ++ assert_mem_outside_invalid_range(p1, len); ++ assert_mem_outside_invalid_range(p2, len); ++ ++ return __real_ct_memcmp(p1, p2, len); ++} ++ ++void *__wrap_malloc(size_t size); ++void *__real_malloc(size_t size); ++void *__wrap_malloc(size_t size) ++{ ++ /* ++ * Ensure the length isn't excessively large (a symptom of integer ++ * underflow). ++ */ ++ assert_in_range(size, 0, 0x10000); ++ ++ return __real_malloc(size); ++} ++ ++/***************************************************************************** ++ * Mock implementations ++ *****************************************************************************/ ++ ++/* ++ * Set the globals used by the mocked functions to a known and consistent state ++ * ++ */ ++static void init_mock_results(TALLOC_CTX *mem_ctx) ++{ ++ dummy_key.keytype = KRB5_ENCTYPE_DES3_CBC_MD5; ++ dummy_key.keyvalue.data = NULL; ++ dummy_key.keyvalue.length = 0; ++ ++ dummy_crypto = (struct krb5_crypto_data) {0}; ++ ++ valid_range_begin = NULL; ++ valid_range_end = NULL; ++ invalid_range_end = NULL; ++} ++ ++/***************************************************************************** ++ * Unit test set up and tear down ++ *****************************************************************************/ ++ ++struct context { ++ gss_ctx_id_t context_handle; ++}; ++ ++static int setup(void **state) { ++ struct context *ctx = NULL; ++ krb5_context context = NULL; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ krb5_error_code code; ++ ++ ctx = talloc_zero(NULL, struct context); ++ assert_non_null(ctx); ++ ++ init_mock_results(ctx); ++ ++ code = _gsskrb5_init(&context); ++ assert_int_equal(0, code); ++ ++ major_status = _gsskrb5_create_ctx(&minor_status, ++ &ctx->context_handle, ++ context, ++ GSS_C_NO_CHANNEL_BINDINGS, ++ ACCEPTOR_START); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ *state = ctx; ++ return 0; ++} ++ ++static int teardown(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ ++ major_status = _gsskrb5_delete_sec_context(&minor_status, ++ &ctx->context_handle, ++ GSS_C_NO_BUFFER); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ TALLOC_FREE(ctx); ++ return 0; ++} ++ ++/***************************************************************************** ++ * _gsskrb5_unwrap unit tests ++ *****************************************************************************/ ++ ++static void test_unwrap_dce_style_missing_payload(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gsskrb5_ctx gss_ctx; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 22); ++ ++ gss_ctx = (gsskrb5_ctx) ctx->context_handle; ++ gss_ctx->flags |= GSS_C_DCE_STYLE; ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_dce_style_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gsskrb5_ctx gss_ctx; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, ++ 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ gss_ctx = (gsskrb5_ctx) ctx->context_handle; ++ gss_ctx->flags |= GSS_C_DCE_STYLE; ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 16); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(0, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 0); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++static void test_unwrap_dce_style_with_seal_missing_payload(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gsskrb5_ctx gss_ctx; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 22); ++ ++ gss_ctx = (gsskrb5_ctx) ctx->context_handle; ++ gss_ctx->flags |= GSS_C_DCE_STYLE; ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_dce_style_with_seal_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gsskrb5_ctx gss_ctx; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, ++ 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ gss_ctx = (gsskrb5_ctx) ctx->context_handle; ++ gss_ctx->flags |= GSS_C_DCE_STYLE; ++ ++ expect_value(__wrap_krb5_decrypt, len, 8); ++ expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 16); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(1, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 0); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++static void test_unwrap_missing_8_bytes(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x2f, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 49); ++ ++ /* ++ * A fixed unwrap_des3() should fail before these wrappers are called, ++ * but we want the wrappers to have access to any required values in the ++ * event that they are called. Specifying WILL_RETURN_ONCE avoids a test ++ * failure if these values remain unused. ++ */ ++ expect_value_count(__wrap_krb5_decrypt_ivec, data, ++ (uint8_t *)input.value + 21, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN, ++ WILL_RETURN_ONCE); ++ ++ expect_value_count(__wrap_krb5_verify_checksum, len, 8, WILL_RETURN_ONCE); ++ expect_value_count(__wrap_krb5_verify_checksum, data, ++ (uint8_t *)input.value + 41, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20, ++ WILL_RETURN_ONCE); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_missing_payload(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x14, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0x00, 0xa1, 0xa2, 0xa3, /* padding byte / encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 22); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_truncated_header_0(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x00, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 2); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_DEFECTIVE_TOKEN, major_status); ++} ++ ++static void test_unwrap_truncated_header_1(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x02, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, /* GSS KRB5 mech */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 4); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, ++ 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 16); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(0, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 0); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++static void test_unwrap_with_padding_truncated_0(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0x04, 0x04, 0x04, 0x04, /* padding bytes */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ /* ++ * A fixed unwrap_des3() should fail before these wrappers are called, ++ * but we want the wrappers to have access to any required values in the ++ * event that they are called. Specifying WILL_RETURN_ONCE avoids a test ++ * failure if these values remain unused. ++ */ ++ expect_value_count(__wrap_krb5_decrypt_ivec, data, ++ (uint8_t *)input.value + 21, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN, ++ WILL_RETURN_ONCE); ++ ++ expect_value_count(__wrap_krb5_verify_checksum, len, 16, WILL_RETURN_ONCE); ++ expect_value_count(__wrap_krb5_verify_checksum, data, ++ (uint8_t *)input.value + 41, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20, ++ WILL_RETURN_ONCE); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_with_padding_truncated_1(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0x00, 0xa1, 0xa2, 0xa3, /* padding byte / encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* padding bytes */ ++ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ /* ++ * A fixed unwrap_des3() should fail before these wrappers are called, ++ * but we want the wrappers to have access to any required values in the ++ * event that they are called. Specifying WILL_RETURN_ONCE avoids a test ++ * failure if these values remain unused. ++ */ ++ expect_value_count(__wrap_krb5_decrypt_ivec, data, ++ (uint8_t *)input.value + 21, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN, ++ WILL_RETURN_ONCE); ++ ++ expect_value_count(__wrap_krb5_verify_checksum, len, 16, WILL_RETURN_ONCE); ++ expect_value_count(__wrap_krb5_verify_checksum, data, ++ (uint8_t *)input.value + 41, ++ WILL_RETURN_ONCE); ++ expect_memory_count(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20, ++ WILL_RETURN_ONCE); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_with_padding_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x3f, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0xff, 0xff, /* SEAL_ALG (none) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, 0xbf, ++ /* padding bytes */ ++ 0x08, 0x08, 0x08, 0x08, ++ 0x08, 0x08, 0x08, 0x08, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 65); ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 24); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(0, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 0); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++static void test_unwrap_with_seal_empty_token_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x37, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, ++ 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 57); ++ ++ expect_value(__wrap_krb5_decrypt, len, 8); ++ expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 16); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(1, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 0); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++static void test_unwrap_with_seal_missing_payload(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x14, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 22); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_BAD_MECH, major_status); ++} ++ ++static void test_unwrap_with_seal_valid(void **state) { ++ struct context *ctx = *state; ++ OM_uint32 major_status; ++ OM_uint32 minor_status; ++ gss_buffer_desc input = {0}; ++ gss_buffer_desc output = {0}; ++ int conf_state; ++ gss_qop_t qop_state; ++ ++ /* See RFC 1964 for token format. */ ++ static const uint8_t data[] = { ++ 0x60, /* ASN.1 Application tag */ ++ 0x3e, /* total length */ ++ 0x06, /* OBJECT IDENTIFIER */ ++ 0x09, /* mech length */ ++ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02, /* GSS KRB5 mech */ ++ 0x02, 0x01, /* TOK_ID */ ++ 0x04, 0x00, /* SGN_ALG (HMAC SHA1 DES3-KD) */ ++ 0x02, 0x00, /* SEAL_ALG (DES3-KD) */ ++ 0xff, 0xff, /* Filler */ ++ 0xa0, 0xa1, 0xa2, 0xa3, /* encrypted sequence number */ ++ 0x00, 0x00, 0x00, 0x00, /* sequence number direction (remote) */ ++ /* checksum */ ++ 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, ++ 0xa9, 0xaa, 0xab, 0xac, 0xad, ++ 0xae, 0xaf, 0xb0, 0xb1, 0xb2, ++ 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, ++ /* unused */ ++ 0xb8, 0xb9, 0xba, 0xbb, ++ 0xbc, 0xbd, 0xbe, 0xbf, ++ 0xc0, 0xc1, 0xc2, 0xc3, ++ 0xc4, 0xc5, ++ 0x00, /* padding byte */ ++ }; ++ ++ input = get_input_buffer(ctx, data, sizeof(data), 64); ++ ++ expect_value(__wrap_krb5_decrypt, len, 15); ++ expect_value(__wrap_krb5_decrypt, data, (uint8_t *)input.value + 49); ++ ++ expect_value(__wrap_krb5_decrypt_ivec, data, (uint8_t *)input.value + 21); ++ expect_memory(__wrap_krb5_decrypt_ivec, ivec, ++ (uint8_t *)input.value + 29, DES_CBLOCK_LEN); ++ ++ expect_value(__wrap_krb5_verify_checksum, len, 23); ++ expect_value(__wrap_krb5_verify_checksum, data, (uint8_t *)input.value + 41); ++ expect_memory(__wrap_krb5_verify_checksum, cksum->checksum.data, ++ (uint8_t *)input.value + 29, 20); ++ ++ major_status = _gsskrb5_unwrap(&minor_status, ++ ctx->context_handle, ++ &input, ++ &output, ++ &conf_state, ++ &qop_state); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++ ++ assert_int_equal(1, conf_state); ++ assert_int_equal(GSS_C_QOP_DEFAULT, qop_state); ++ ++ assert_int_equal(output.length, 7); ++ assert_memory_equal((uint8_t *)input.value + 57, output.value, output.length); ++ ++ major_status = gss_release_buffer(&minor_status, &output); ++ assert_int_equal(GSS_S_COMPLETE, major_status); ++} ++ ++int main(int argc, const char **argv) ++{ ++ static const struct CMUnitTest tests[] = { ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_dce_style_missing_payload, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_dce_style_valid, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_dce_style_with_seal_missing_payload, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_dce_style_with_seal_valid, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_missing_8_bytes, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_missing_payload, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_truncated_header_0, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_truncated_header_1, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_valid, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_padding_truncated_0, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_padding_truncated_1, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_padding_valid, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_seal_empty_token_valid, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_seal_missing_payload, setup, teardown), ++ cmocka_unit_test_setup_teardown( ++ test_unwrap_with_seal_valid, setup, teardown), ++ }; ++ ++ cmocka_set_message_output(CM_OUTPUT_SUBUNIT); ++ return cmocka_run_group_tests(tests, NULL, NULL); ++} +Index: samba/source4/auth/wscript_build +=================================================================== +--- samba.orig/source4/auth/wscript_build ++++ samba/source4/auth/wscript_build +@@ -49,6 +49,27 @@ bld.SAMBA_BINARY('test_kerberos', + for_selftest=True + ) + ++bld.SAMBA_BINARY('test_heimdal_gensec_unwrap_des', ++ source='tests/heimdal_unwrap_des.c', ++ deps='cmocka talloc gssapi-subsystem', ++ local_include=False, ++ for_selftest=True, ++ enabled=(bld.CONFIG_SET('SAMBA4_USES_HEIMDAL') and ++ not bld.CONFIG_SET('USING_SYSTEM_GSSAPI')), ++ ldflags=''' ++ -Wl,--wrap,ct_memcmp ++ -Wl,--wrap,der_get_length ++ -Wl,--wrap,krb5_auth_con_getlocalsubkey ++ -Wl,--wrap,krb5_crypto_destroy ++ -Wl,--wrap,krb5_crypto_init ++ -Wl,--wrap,krb5_decrypt ++ -Wl,--wrap,krb5_decrypt_ivec ++ -Wl,--wrap,krb5_free_keyblock ++ -Wl,--wrap,krb5_verify_checksum ++ -Wl,--wrap,malloc ++ ''' ++) ++ + pytalloc_util = bld.pyembed_libname('pytalloc-util') + pyparam_util = bld.pyembed_libname('pyparam_util') + pyldb_util = bld.pyembed_libname('pyldb-util') +Index: samba/source4/heimdal/lib/gssapi/krb5/arcfour.c +=================================================================== +--- samba.orig/source4/heimdal/lib/gssapi/krb5/arcfour.c ++++ samba/source4/heimdal/lib/gssapi/krb5/arcfour.c +@@ -385,9 +385,9 @@ _gssapi_verify_mic_arcfour(OM_uint32 * m + _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) +- cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); ++ cmp = ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + else +- cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); ++ cmp = ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + + memset(SND_SEQ, 0, sizeof(SND_SEQ)); + if (cmp != 0) { +@@ -656,9 +656,9 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint + _gsskrb5_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) +- cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); ++ cmp = ct_memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + else +- cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); ++ cmp = ct_memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + + if (cmp != 0) { + *minor_status = 0; +@@ -1266,19 +1266,9 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *mi + _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number); + + if (ctx->more_flags & LOCAL) { +- cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); ++ cmp = ct_memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); + } else { +- cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); +- } +- if (cmp != 0) { +- *minor_status = 0; +- return GSS_S_BAD_MIC; +- } +- +- if (ctx->more_flags & LOCAL) { +- cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4); +- } else { +- cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); ++ cmp = ct_memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4); + } + if (cmp != 0) { + *minor_status = 0; +@@ -1353,7 +1343,7 @@ _gssapi_unwrap_iov_arcfour(OM_uint32 *mi + return GSS_S_FAILURE; + } + +- cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ ++ cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; +Index: samba/source4/heimdal/lib/gssapi/krb5/unwrap.c +=================================================================== +--- samba.orig/source4/heimdal/lib/gssapi/krb5/unwrap.c ++++ samba/source4/heimdal/lib/gssapi/krb5/unwrap.c +@@ -180,9 +180,10 @@ unwrap_des + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; +- memcpy (output_message_buffer->value, +- p + 24, +- output_message_buffer->length); ++ if (output_message_buffer->value != NULL) ++ memcpy (output_message_buffer->value, ++ p + 24, ++ output_message_buffer->length); + return GSS_S_COMPLETE; + } + #endif +@@ -227,7 +228,7 @@ unwrap_des3 + if (ret) + return ret; + +- if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ ++ if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + return GSS_S_BAD_SIG; + p += 2; + if (ct_memcmp (p, "\x02\x00", 2) == 0) { +@@ -374,9 +375,10 @@ unwrap_des3 + output_message_buffer->value = malloc(output_message_buffer->length); + if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) + return GSS_S_FAILURE; +- memcpy (output_message_buffer->value, +- p + 36, +- output_message_buffer->length); ++ if (output_message_buffer->value != NULL) ++ memcpy (output_message_buffer->value, ++ p + 36, ++ output_message_buffer->length); + return GSS_S_COMPLETE; + } + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-2.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-2.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-2.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-2.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,89 @@ +diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +index 86085f56950..4e3fcd659e9 100644 +--- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c ++++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +@@ -193,13 +193,13 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token, + if (wrapped_token->length < 1) + return GSS_S_BAD_MECH; + +- pad = (u_char *)wrapped_token->value + wrapped_token->length - 1; +- padlength = *pad; ++ pad = (u_char *)wrapped_token->value + wrapped_token->length; ++ padlength = pad[-1]; + + if (padlength > datalen) + return GSS_S_BAD_MECH; + +- for (i = padlength; i > 0 && *pad == padlength; i--, pad--) ++ for (i = padlength; i > 0 && *--pad == padlength; i--) + ; + if (i != 0) + return GSS_S_BAD_MIC; +-- +2.25.1 + + +From 73e28ffbce8894c93374feb95c4ed1a87f2e6051 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 15 Aug 2022 16:53:55 +1200 +Subject: [PATCH 08/11] CVE-2022-3437 source4/heimdal: Check the result of + _gsskrb5_get_mech() + +We should make sure that the result of 'total_len - mech_len' won't +overflow, and that we don't memcmp() past the end of the buffer. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/heimdal-des-overflow | 1 - + source4/heimdal/lib/gssapi/krb5/decapsulate.c | 4 ++++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow +index 23acbb43d31..68b304530db 100644 +--- a/selftest/knownfail.d/heimdal-des-overflow ++++ b/selftest/knownfail.d/heimdal-des-overflow +@@ -3,7 +3,6 @@ + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_1.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none +diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +index 4e3fcd659e9..031a621eabc 100644 +--- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c ++++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +@@ -80,6 +80,10 @@ _gssapi_verify_mech_header(u_char **str, + + if (mech_len != mech->length) + return GSS_S_BAD_MECH; ++ if (mech_len > total_len) ++ return GSS_S_BAD_MECH; ++ if (p - *str > total_len - mech_len) ++ return GSS_S_BAD_MECH; + if (ct_memcmp(p, + mech->elements, + mech->length) != 0) +-- +2.25.1 + + +From 3320c411c5cdf8bb9e4bc945e8bbe0947933d5e1 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 15 Aug 2022 16:54:23 +1200 +Subject: [PATCH 09/11] CVE-2022-3437 source4/heimdal: Check buffer length + against overflow for DES{,3} unwrap + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/heimdal-des-overflow | 5 ----- + source4/heimdal/lib/gssapi/krb5/unwrap.c | 14 ++++++++++++++ + 2 files changed, 14 insertions(+), 5 deletions(-) + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-3.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-3.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-3.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-3.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,13 @@ +diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow +index 68b304530db..94a49bbee7f 100644 +--- a/selftest/knownfail.d/heimdal-des-overflow ++++ b/selftest/knownfail.d/heimdal-des-overflow +@@ -1,8 +1,3 @@ +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_missing_payload.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_dce_style_with_seal_missing_payload.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_8_bytes.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_missing_payload.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_seal_missing_payload.none diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-4.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-4.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-4.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-4.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,72 @@ +diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c +index 9639091cb3a..70d26a75ccf 100644 +--- a/source4/heimdal/lib/gssapi/krb5/unwrap.c ++++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c +@@ -64,6 +64,8 @@ unwrap_des + + if (IS_DCE_STYLE(context_handle)) { + token_len = 22 + 8 + 15; /* 45 */ ++ if (input_message_buffer->length < token_len) ++ return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } +@@ -76,6 +78,11 @@ unwrap_des + if (ret) + return ret; + ++ len = (p - (u_char *)input_message_buffer->value) ++ + 22 + 8; ++ if (input_message_buffer->length < len) ++ return GSS_S_BAD_MECH; ++ + if (memcmp (p, "\x00\x00", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; +@@ -216,6 +223,8 @@ unwrap_des3 + + if (IS_DCE_STYLE(context_handle)) { + token_len = 34 + 8 + 15; /* 57 */ ++ if (input_message_buffer->length < token_len) ++ return GSS_S_BAD_MECH; + } else { + token_len = input_message_buffer->length; + } +@@ -228,6 +237,11 @@ unwrap_des3 + if (ret) + return ret; + ++ len = (p - (u_char *)input_message_buffer->value) ++ + 34 + 8; ++ if (input_message_buffer->length < len) ++ return GSS_S_BAD_MECH; ++ + if (ct_memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ + return GSS_S_BAD_SIG; + p += 2; +-- +2.25.1 + + +From 9eb844370966625733f90d17a5d9ad611002567f Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Mon, 10 Oct 2022 20:33:09 +1300 +Subject: [PATCH 10/11] CVE-2022-3437 source4/heimdal: Check for overflow in + _gsskrb5_get_mech() + +If len_len is equal to total_len - 1 (i.e. the input consists only of a +0x60 byte and a length), the expression 'total_len - 1 - len_len - 1', +used as the 'len' parameter to der_get_length(), will overflow to +SIZE_MAX. Then der_get_length() will proceed to read, unconstrained, +whatever data follows in memory. Add a check to ensure that doesn't +happen. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/heimdal-des-overflow | 1 - + source4/heimdal/lib/gssapi/krb5/decapsulate.c | 2 ++ + 2 files changed, 2 insertions(+), 1 deletion(-) + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-5.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-5.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-5.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-5.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,8 @@ +diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow +index 94a49bbee7f..a7416dc61d9 100644 +--- a/selftest/knownfail.d/heimdal-des-overflow ++++ b/selftest/knownfail.d/heimdal-des-overflow +@@ -1,3 +1,2 @@ +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_truncated_header_0.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none + ^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-6.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-6.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-6.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-6.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,40 @@ +diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +index 031a621eabc..d7b75a64222 100644 +--- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c ++++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c +@@ -54,6 +54,8 @@ _gsskrb5_get_mech (const u_char *ptr, + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return -1; ++ if (total_len < 1 + len_len + 1) ++ return -1; + p += len_len; + if (*p++ != 0x06) + return -1; +-- +2.25.1 + + +From 4c272bd20bbd512a63889e25f86506324957d232 Mon Sep 17 00:00:00 2001 +From: Joseph Sutton +Date: Wed, 12 Oct 2022 13:57:33 +1300 +Subject: [PATCH 11/11] CVE-2022-3437 source4/heimdal: Pass correct length to + _gssapi_verify_pad() + +We later subtract 8 when calculating the length of the output message +buffer. If padlength is excessively high, this calculation can underflow +and result in a very large positive value. + +Now we properly constrain the value of padlength so underflow shouldn't +be possible. + +BUG: https://bugzilla.samba.org/show_bug.cgi?id=15134 + +Signed-off-by: Joseph Sutton +Reviewed-by: Andrew Bartlett +--- + selftest/knownfail.d/heimdal-des-overflow | 2 -- + source4/heimdal/lib/gssapi/krb5/unwrap.c | 4 ++-- + 2 files changed, 2 insertions(+), 4 deletions(-) + delete mode 100644 selftest/knownfail.d/heimdal-des-overflow + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-7.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-7.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-7.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-7.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,8 @@ +diff --git a/selftest/knownfail.d/heimdal-des-overflow b/selftest/knownfail.d/heimdal-des-overflow +deleted file mode 100644 +index a7416dc61d9..00000000000 +--- a/selftest/knownfail.d/heimdal-des-overflow ++++ /dev/null +@@ -1,2 +0,0 @@ +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_0.none +-^samba.unittests.auth.heimdal_gensec_unwrap_des.test_unwrap_with_padding_truncated_1.none diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-8.patch samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-8.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-8.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2022-3437-des3-overflow-v4a-4.12-8.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,25 @@ +diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c +index 70d26a75ccf..ed8f7d78ffa 100644 +--- a/source4/heimdal/lib/gssapi/krb5/unwrap.c ++++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c +@@ -124,7 +124,7 @@ unwrap_des + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, +- input_message_buffer->length - len, ++ input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; +@@ -289,7 +289,7 @@ unwrap_des3 + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, +- input_message_buffer->length - len, ++ input_message_buffer->length - len - 8, + &padlength); + if (ret) + return ret; +-- +2.25.1 + diff -Nru samba-4.13.13+dfsg/debian/patches/CVE-2023-34968-pre.patch samba-4.13.13+dfsg/debian/patches/CVE-2023-34968-pre.patch --- samba-4.13.13+dfsg/debian/patches/CVE-2023-34968-pre.patch 1970-01-01 00:00:00.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/CVE-2023-34968-pre.patch 2024-03-19 20:59:40.000000000 +0000 @@ -0,0 +1,83 @@ +Description: backport subdir_of() needed by CVE-2023-34968 fix +Author: Santiago Ruano Rincón + +Index: samba/source3/lib/util_path.c +=================================================================== +--- samba.orig/source3/lib/util_path.c ++++ samba/source3/lib/util_path.c +@@ -23,6 +23,7 @@ + + #include "replace.h" + #include ++#include "lib/util/debug.h" + #include "lib/util/samba_util.h" + #include "lib/util_path.h" + +@@ -210,3 +211,53 @@ char *canonicalize_absolute_path(TALLOC_ + *p++ = '\0'; + return pathname; + } ++ ++/* ++ * Take two absolute paths, figure out if "subdir" is a proper ++ * subdirectory of "parent". Return the component relative to the ++ * "parent" without the potential "/". Take care of "parent" ++ * possibly ending in "/". ++ */ ++bool subdir_of(const char *parent, ++ size_t parent_len, ++ const char *subdir, ++ const char **_relative) ++{ ++ const char *relative = NULL; ++ bool matched; ++ ++ SMB_ASSERT(parent[0] == '/'); ++ SMB_ASSERT(subdir[0] == '/'); ++ ++ if (parent_len == 1) { ++ /* ++ * Everything is below "/" ++ */ ++ *_relative = subdir+1; ++ return true; ++ } ++ ++ if (parent[parent_len-1] == '/') { ++ parent_len -= 1; ++ } ++ ++ matched = (strncmp(subdir, parent, parent_len) == 0); ++ if (!matched) { ++ return false; ++ } ++ ++ relative = &subdir[parent_len]; ++ ++ if (relative[0] == '\0') { ++ *_relative = relative; /* nothing left */ ++ return true; ++ } ++ ++ if (relative[0] == '/') { ++ /* End of parent must match a '/' in subdir. */ ++ *_relative = relative+1; ++ return true; ++ } ++ ++ return false; ++} +Index: samba/source3/lib/util_path.h +=================================================================== +--- samba.orig/source3/lib/util_path.h ++++ samba/source3/lib/util_path.h +@@ -31,5 +31,9 @@ char *lock_path(TALLOC_CTX *mem_ctx, con + char *state_path(TALLOC_CTX *mem_ctx, const char *name); + char *cache_path(TALLOC_CTX *mem_ctx, const char *name); + char *canonicalize_absolute_path(TALLOC_CTX *ctx, const char *abs_path); ++bool subdir_of(const char *parent, ++ size_t parent_len, ++ const char *subdir, ++ const char **_relative); + + #endif diff -Nru samba-4.13.13+dfsg/debian/patches/series samba-4.13.13+dfsg/debian/patches/series --- samba-4.13.13+dfsg/debian/patches/series 2022-08-09 08:49:20.000000000 +0000 +++ samba-4.13.13+dfsg/debian/patches/series 2024-03-19 20:59:40.000000000 +0000 @@ -302,3 +302,32 @@ CVE-2022-32742-bug-15085-4.13.patch ldb-memory-bug-15096-4.13-v3.patch kpasswd_bugs_v15_4-13.patch +CVE-2022-2127-1.patch +CVE-2022-2127-2.patch +CVE-2022-2127-3.patch +CVE-2022-3437-des3-overflow-v4a-4.12-1.patch +CVE-2022-3437-des3-overflow-v4a-4.12-2.patch +CVE-2022-3437-des3-overflow-v4a-4.12-3.patch +CVE-2022-3437-des3-overflow-v4a-4.12-4.patch +CVE-2022-3437-des3-overflow-v4a-4.12-5.patch +CVE-2022-3437-des3-overflow-v4a-4.12-6.patch +CVE-2022-3437-des3-overflow-v4a-4.12-7.patch +CVE-2022-3437-des3-overflow-v4a-4.12-8.patch +0001-CVE-2023-4091-smbtorture-test-overwrite-dispositions.patch +0002-CVE-2023-4091-smbd-use-open_access_mask-for-access-c.patch +0001-CVE-2023-34966-CI-test-for-sl_unpack_loop.patch +0002-CVE-2023-34966-mdssvc-harden-sl_unpack_loop.patch +0001-CVE-2023-34967-CI-add-a-test-for-type-checking-of-da.patch +0002-CVE-2023-34967-mdssvc-add-type-checking-to-dalloc_va.patch +0001-CVE-2023-34968-mdssvc-cache-and-reuse-stat-info-in-s.patch +0002-CVE-2023-34968-mdssvc-add-missing-kMDSStoreMetaScope.patch +0003-CVE-2023-34968-mdscli-use-correct-TALLOC-memory-cont.patch +0004-CVE-2023-34968-mdscli-remove-response-blob-allocatio.patch +0005-CVE-2023-34968-smbtorture-remove-response-blob-alloc.patch +0006-CVE-2023-34968-rpcclient-remove-response-blob-alloca.patch +0007-CVE-2023-34968-mdssvc-remove-response-blob-allocatio.patch +0008-CVE-2023-34968-mdssvc-switch-to-doing-an-early-retur.patch +0009-CVE-2023-34968-mdssvc-introduce-an-allocating-wrappe.patch +0010-CVE-2023-34968-mdscli-return-share-relative-paths.patch +0011-CVE-2023-34968-mdssvc-return-a-fake-share-path.patch +CVE-2023-34968-pre.patch