smbd/smb2_ioctl: check for for overlap of dup extent ranges
authorDavid Disseldorp <ddiss@samba.org>
Tue, 20 Sep 2016 16:48:37 +0000 (09:48 -0700)
committerRalph Boehme <slow@samba.org>
Wed, 10 May 2017 06:22:19 +0000 (08:22 +0200)
Signed-off-by: David Disseldorp <ddiss@samba.org>
Reviewed-by: Ralph Böhme <slow@samba.org>
source3/smbd/smb2_ioctl_filesys.c

index a4385254bf074ffc8a985ee1bbd533bd6b59d361..54a28e0ef7f663b9e24fcc46c597994772c40259 100644 (file)
 #include "librpc/gen_ndr/ndr_ioctl.h"
 #include "smb2_ioctl_private.h"
 
+static NTSTATUS fsctl_dup_extents_check_overlap(struct files_struct *src_fsp,
+                                               struct files_struct *dst_fsp,
+                               struct fsctl_dup_extents_to_file *dup_extents)
+{
+       uint64_t src_off_last;
+       uint64_t tgt_off_last;
+
+       if (!file_id_equal(&src_fsp->file_id, &dst_fsp->file_id)) {
+               /* src and dest refer to different files */
+               return NT_STATUS_OK;
+       }
+
+       if (dup_extents->byte_count == 0) {
+               /* no range to overlap */
+               return NT_STATUS_OK;
+       }
+
+       /*
+        * [MS-FSCC] 2.3.8 FSCTL_DUPLICATE_EXTENTS_TO_FILE Reply
+        * STATUS_NOT_SUPPORTED:
+        * The source and target destination ranges overlap on the same file.
+        */
+
+       src_off_last = dup_extents->source_off + dup_extents->byte_count - 1;
+       if ((dup_extents->target_off >= dup_extents->source_off)
+                               && (dup_extents->target_off <= src_off_last)) {
+               /*
+                * src: |-----------|
+                * tgt:       |-----------|
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+
+       tgt_off_last = dup_extents->target_off + dup_extents->byte_count - 1;
+       if ((tgt_off_last >= dup_extents->source_off)
+                                       && (tgt_off_last <= src_off_last)) {
+               /*
+                * src:       |-----------|
+                * tgt: |-----------|
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       return NT_STATUS_OK;
+}
+
 struct fsctl_dup_extents_state {
        struct tevent_context *ev;
        struct connection_struct *conn;
@@ -52,6 +99,7 @@ static struct tevent_req *fsctl_dup_extents_send(TALLOC_CTX *mem_ctx,
        uint64_t src_fid_volatile = 0;
        struct files_struct *src_fsp = NULL;
        int ndr_ret;
+       NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct fsctl_dup_extents_state);
@@ -108,6 +156,13 @@ static struct tevent_req *fsctl_dup_extents_send(TALLOC_CTX *mem_ctx,
                return tevent_req_post(req, ev);
        }
 
+       status = fsctl_dup_extents_check_overlap(src_fsp, dst_fsp,
+                                                &state->dup_extents);
+       if (!NT_STATUS_IS_OK(status)) {
+               tevent_req_nterror(req, status);
+               return tevent_req_post(req, ev);
+       }
+
        subreq = SMB_VFS_COPY_CHUNK_SEND(dst_fsp->conn, state, ev,
                                         src_fsp, state->dup_extents.source_off,
                                         dst_fsp, state->dup_extents.target_off,