summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2021-09-21 17:38:27 -0700
committerJule Anger <janger@samba.org>2022-01-08 11:38:19 +0100
commit9c2e3c72c0cdde31a2a5c2e58ce508070ec151d0 (patch)
tree70b2a98daefddf62f652404129d67cfa53acdfce
parentc3f170643bbc3024aba3dae819cf9c5ba35733f8 (diff)
downloadsamba-9c2e3c72c0cdde31a2a5c2e58ce508070ec151d0.tar.gz
s3: smbd: Fix mkdir race condition allows share escape in Samba 4.13.X and below: CVE-2021-43566
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13979 Signed-off-by: Jeremy Allison <jra@samba.org>
-rw-r--r--source3/smbd/open.c43
1 files changed, 40 insertions, 3 deletions
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index ef158657684..17163e9ddea 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -4255,6 +4255,8 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
uint32_t access_mask = SEC_DIR_ADD_SUBDIR;
int ret;
bool ok;
+ struct smb_filename *oldwd_fname = NULL;
+ struct smb_filename *smb_fname_rel = NULL;
SMB_ASSERT(*dirfsp == conn->cwd_fsp);
@@ -4267,7 +4269,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
ok = parent_smb_fname(talloc_tos(),
smb_dname,
&parent_dir_fname,
- NULL);
+ &smb_fname_rel);
if (!ok) {
return NT_STATUS_NO_MEMORY;
}
@@ -4295,14 +4297,40 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
return status;
}
+ oldwd_fname = vfs_GetWd(talloc_tos(), conn);
+ if (oldwd_fname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* Pin parent directory in place. */
+ if (vfs_ChDir(conn, parent_dir_fname) == -1) {
+ status = map_nt_error_from_unix(errno);
+ TALLOC_FREE(oldwd_fname);
+ return status;
+ }
+
+ /* Ensure the relative path is below the share. */
+ status = check_reduced_name(conn, parent_dir_fname, smb_fname_rel);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto need_chdir_err;
+ }
+
ret = SMB_VFS_MKDIRAT(conn,
*dirfsp,
- smb_dname,
+ smb_fname_rel,
mode);
if (ret != 0) {
- return map_nt_error_from_unix(errno);
+ status = map_nt_error_from_unix(errno);
+ goto need_chdir_err;
}
+ /* Return to share $cwd. */
+ ret = vfs_ChDir(conn, oldwd_fname);
+ if (ret == -1) {
+ smb_panic("unable to get back to old directory\n");
+ }
+ TALLOC_FREE(oldwd_fname);
+
/* Ensure we're checking for a symlink here.... */
/* We don't want to get caught by a symlink racer. */
@@ -4378,6 +4406,15 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
smb_dname->base_name);
return NT_STATUS_OK;
+
+ need_chdir_err:
+
+ ret = vfs_ChDir(conn, oldwd_fname);
+ if (ret == -1) {
+ smb_panic("unable to get back to old directory\n");
+ }
+ TALLOC_FREE(oldwd_fname);
+ return status;
}
/****************************************************************************