From 9c2e3c72c0cdde31a2a5c2e58ce508070ec151d0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 21 Sep 2021 17:38:27 -0700 Subject: [PATCH] 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 --- source3/smbd/open.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file 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; } /**************************************************************************** -- 2.11.4.GIT