aboutsummaryrefslogtreecommitdiffstats
path: root/meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch')
-rw-r--r--meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch484
1 files changed, 484 insertions, 0 deletions
diff --git a/meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch b/meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch
new file mode 100644
index 0000000000..57668f5eef
--- /dev/null
+++ b/meta-networking/recipes-connectivity/samba/samba/CVE-2023-34968_0010.patch
@@ -0,0 +1,484 @@
+From a5c570e262911874e43e82de601d809aa5b1b729 Mon Sep 17 00:00:00 2001
+From: Ralph Boehme <slow@samba.org>
+Date: Sat, 17 Jun 2023 13:53:27 +0200
+Subject: [PATCH] CVE-2023-34968: mdscli: return share relative paths 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.
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+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 <slow@samba.org>
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+
+Upstream-Status: Backport [https://github.com/samba-team/samba/commit/a5c570e262911874e43e82de601d809aa5b1b729]
+
+CVE: CVE-2023-34968
+
+Signed-off-by: Archana Polampalli <archana.polampalli@windriver.com>
+---
+ 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 +
+ 5 files changed, 243 insertions(+), 14 deletions(-)
+
+diff --git a/python/samba/tests/dcerpc/mdssvc.py b/python/samba/tests/dcerpc/mdssvc.py
+index b0df509..5002e5d 100644
+--- a/python/samba/tests/dcerpc/mdssvc.py
++++ b/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)
+diff --git a/source3/rpc_client/cli_mdssvc.c b/source3/rpc_client/cli_mdssvc.c
+index 07c19b5..a047b91 100644
+--- a/source3/rpc_client/cli_mdssvc.c
++++ b/source3/rpc_client/cli_mdssvc.c
+@@ -43,10 +43,12 @@ char *mdscli_get_basepath(TALLOC_CTX *mem_ctx,
+ 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(struct tevent_req *subreq)
+ 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(struct tevent_req *subreq)
+ 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(struct tevent_req *subreq)
+ 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);
+@@ -153,6 +170,108 @@ static void mdscli_connect_unknown1_done(struct tevent_req *subreq)
+ if (tevent_req_nterror(req, status)) {
+ 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 tevent_req *subreq)
+ 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 *subreq)
+ 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);
+diff --git a/source3/rpc_client/cli_mdssvc_private.h b/source3/rpc_client/cli_mdssvc_private.h
+index 031af85..b10aca0 100644
+--- a/source3/rpc_client/cli_mdssvc_private.h
++++ b/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 {
+diff --git a/source3/rpc_client/cli_mdssvc_util.c b/source3/rpc_client/cli_mdssvc_util.c
+index a39202d..1eaaca7 100644
+--- a/source3/rpc_client/cli_mdssvc_util.c
++++ b/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)
+diff --git a/source3/rpc_client/cli_mdssvc_util.h b/source3/rpc_client/cli_mdssvc_util.h
+index 7a98c85..3f32475 100644
+--- a/source3/rpc_client/cli_mdssvc_util.h
++++ b/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);
+--
+2.40.0