summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2016-12-19 16:35:00 -0800
committerKarolin Seeger <kseeger@samba.org>2017-03-22 10:48:05 +0100
commit3e2bb3fcacf7e1eea9edb26f8eb38dc447cb5f6b (patch)
tree636b1cd8e872acd506f7ead1fe7be662bb9fead6
parent039eb4a36aca5ead9ccb8a0a6199c2c21ab062df (diff)
downloadsamba-3e2bb3fcacf7e1eea9edb26f8eb38dc447cb5f6b.tar.gz
CVE-2017-2619: s3: smbd: Create and use open_dir_safely(). Use from OpenDir().
Hardens OpenDir against TOC/TOU races. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12496 Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Uri Simchoni <uri@samba.org>
-rw-r--r--source3/smbd/dir.c77
1 files changed, 70 insertions, 7 deletions
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index a5d172a86e1..2b107a9b69b 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -1655,12 +1655,6 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
dirp->conn = conn;
dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
- dirp->dir_smb_fname = cp_smb_filename(dirp, smb_dname);
- if (!dirp->dir_smb_fname) {
- errno = ENOMEM;
- goto fail;
- }
-
if (sconn && !sconn->using_smb2) {
sconn->searches.dirhandles_open++;
}
@@ -1673,12 +1667,81 @@ static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
return NULL;
}
+/****************************************************************************
+ Open a directory handle by pathname, ensuring it's under the share path.
+****************************************************************************/
+
+static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ const struct smb_filename *smb_dname,
+ const char *wcard,
+ uint32_t attr)
+{
+ struct smb_Dir *dir_hnd = NULL;
+ struct smb_filename *smb_fname_cwd = NULL;
+ char *saved_dir = vfs_GetWd(ctx, conn);
+ NTSTATUS status;
+
+ if (saved_dir == NULL) {
+ return NULL;
+ }
+
+ if (vfs_ChDir(conn, smb_dname->base_name) == -1) {
+ goto out;
+ }
+
+ smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
+ ".",
+ NULL,
+ NULL,
+ smb_dname->flags);
+ if (smb_fname_cwd == NULL) {
+ goto out;
+ }
+
+ /*
+ * Now the directory is pinned, use
+ * REALPATH to ensure we can access it.
+ */
+ status = check_name(conn, ".");
+ if (!NT_STATUS_IS_OK(status)) {
+ goto out;
+ }
+
+ dir_hnd = OpenDir_internal(ctx,
+ conn,
+ smb_fname_cwd,
+ wcard,
+ attr);
+
+ if (dir_hnd == NULL) {
+ goto out;
+ }
+
+ /*
+ * OpenDir_internal only gets "." as the dir name.
+ * Store the real dir name here.
+ */
+
+ dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
+ if (!dir_hnd->dir_smb_fname) {
+ TALLOC_FREE(dir_hnd);
+ errno = ENOMEM;
+ }
+
+ out:
+
+ vfs_ChDir(conn, saved_dir);
+ TALLOC_FREE(saved_dir);
+ return dir_hnd;
+}
+
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
const struct smb_filename *smb_dname,
const char *mask,
uint32_t attr)
{
- return OpenDir_internal(mem_ctx,
+ return open_dir_safely(mem_ctx,
conn,
smb_dname,
mask,