CVE-2023-34968: mdssvc: return a fake share path
authorRalph Boehme <slow@samba.org>
Mon, 5 Jun 2023 16:02:20 +0000 (18:02 +0200)
committerJule Anger <janger@samba.org>
Fri, 21 Jul 2023 12:05:35 +0000 (12:05 +0000)
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 <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/rpc_server/mdssvc/mdssvc.c
source3/rpc_server/mdssvc/mdssvc.h
source3/rpc_server/mdssvc/srv_mdssvc_nt.c

index 20b88560c73ef288cee42a30cdc83d1a8d0faa2b..335b267c0e5ec967617f14ae69be8729ed2d3b6b 100644 (file)
@@ -520,10 +520,13 @@ static bool inode_map_add(struct sl_query *slq,
 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;
        uint64_t ino64;
        int result;
        NTSTATUS status;
+       bool sub;
        bool ok;
 
        /*
@@ -598,6 +601,17 @@ bool mds_add_result(struct sl_query *slq, const char *path)
                }
        }
 
+       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
@@ -610,18 +624,30 @@ bool mds_add_result(struct sl_query *slq, const char *path)
                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;
@@ -828,6 +854,32 @@ static void slq_close_timer(struct tevent_context *ev,
        }
 }
 
+/**
+ * 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
  **/
@@ -940,8 +992,8 @@ static bool slrpc_open_query(struct mds_ctx *mds_ctx,
                goto error;
        }
 
-       slq->path_scope = talloc_strdup(slq, scope);
-       if (slq->path_scope == NULL) {
+       ok = mdssvc_real_scope(slq, scope);
+       if (!ok) {
                goto error;
        }
 
@@ -1662,6 +1714,7 @@ NTSTATUS mds_init_ctx(TALLOC_CTX *mem_ctx,
                status = NT_STATUS_NO_MEMORY;
                goto error;
        }
+       mds_ctx->spath_len = strlen(path);
 
        mds_ctx->snum = snum;
        mds_ctx->pipe_session_info = session_info;
index 47f5be55d2a840f442eb2a4793e14739912be649..38029232242b0af02d8376039a377fac1ef31817 100644 (file)
@@ -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 ae6a73605e190f0328bcee424925043b7ff71cdc..c77e71855211766f4b848f26aed7d86c70de5eb1 100644 (file)
@@ -81,6 +81,7 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
                loadparm_s3_global_substitution();
        int snum;
        char *outpath = discard_const_p(char, r->out.share_path);
+       char *fake_path = NULL;
        char *path;
        NTSTATUS status;
 
@@ -98,12 +99,21 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
 
        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,
@@ -112,18 +122,20 @@ void _mdssvc_open(struct pipes_struct *p, struct mdssvc_open *r)
        if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_VOLUME)) {
                ZERO_STRUCTP(r->out.handle);
                talloc_free(path);
+               talloc_free(fake_path);
                return;
        }
        if (!NT_STATUS_IS_OK(status)) {
                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;
 }