95 lines
2.7 KiB
Diff
95 lines
2.7 KiB
Diff
From 9c2e3c72c0cdde31a2a5c2e58ce508070ec151d0 Mon Sep 17 00:00:00 2001
|
|
From: Jeremy Allison <jra@samba.org>
|
|
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 <jra@samba.org>
|
|
---
|
|
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;
|
|
|
|
if (!CAN_WRITE(conn) || (access_mask & ~(conn->share_access))) {
|
|
DEBUG(5,("mkdir_internal: failing share access "
|
|
@@ -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,
|
|
conn->cwd_fsp,
|
|
- 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;
|
|
}
|
|
|
|
/****************************************************************************
|