smbd: Fix channel sequence number checks for long-running requests
authorVolker Lendecke <vl@samba.org>
Thu, 11 Jan 2018 14:34:45 +0000 (15:34 +0100)
committerStefan Metzmacher <metze@samba.org>
Thu, 8 Mar 2018 20:55:23 +0000 (21:55 +0100)
When the client's supplied csn overflows and hits a pending, long-running
request's csn, we panic. Fix this by counting the overflows in
smbXsrv_open_global0->channel_generation

Bug: https://bugzilla.samba.org/show_bug.cgi?id=13215

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
(cherry picked from commit 0b57434151a8334a6e9b9b7542824ce4915421a2)

source3/librpc/idl/smbXsrv.idl
source3/smbd/globals.h
source3/smbd/smb2_server.c

index 1bfa51ea91258def7d67089ef688eb44c2d94c3f..d3f8d30d1e30a7edd5212aed7d37e9c7f9d8f2f3 100644 (file)
@@ -430,7 +430,8 @@ interface smbXsrv
                uint32                                  durable_timeout_msec;
                boolean8                                durable;
                DATA_BLOB                               backend_cookie;
-               hyper                                   channel_sequence;
+               uint16                                  channel_sequence;
+               hyper                                   channel_generation;
        } smbXsrv_open_global0;
 
        typedef union {
index d3b9800f590b185e57536dc8a37f341d1ea0da58..efcf3e96c8a8dd82b2dba151197e14ee1afa00e6 100644 (file)
@@ -733,6 +733,7 @@ struct smbd_smb2_request {
         * adapted again in reply.
         */
        bool request_counters_updated;
+       uint64_t channel_generation;
 
        /*
         * The sub request for async backend calls.
index e3e51996096b1c5fcf4445b64c55124c533f7808..573f5f6be8c73672f5443861669add19f67b6c95 100644 (file)
@@ -2141,6 +2141,7 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
        struct smbXsrv_connection *xconn = req->xconn;
        const uint8_t *inhdr;
        uint16_t channel_sequence;
+       uint8_t generation_wrap = 0;
        uint32_t flags;
        int cmp;
        struct smbXsrv_open *op;
@@ -2167,6 +2168,14 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
        channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE);
 
        cmp = channel_sequence - op->global->channel_sequence;
+       if (cmp < 0) {
+               /*
+                * csn wrap. We need to watch out for long-running
+                * requests that are still sitting on a previously
+                * used csn. SMB2_OP_NOTIFY can take VERY long.
+                */
+               generation_wrap += 1;
+       }
 
        if (abs(cmp) > INT16_MAX) {
                /*
@@ -2222,6 +2231,7 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
                        op->pre_request_count += op->request_count;
                        op->request_count = 1;
                        op->global->channel_sequence = channel_sequence;
+                       op->global->channel_generation += generation_wrap;
                        update_open = true;
                        req->request_counters_updated = true;
                } else if (modify_call) {
@@ -2235,12 +2245,14 @@ static NTSTATUS smbd_smb2_request_dispatch_update_counts(
                        op->pre_request_count += op->request_count;
                        op->request_count = 1;
                        op->global->channel_sequence = channel_sequence;
+                       op->global->channel_generation += generation_wrap;
                        update_open = true;
                        req->request_counters_updated = true;
                } else if (modify_call) {
                        return NT_STATUS_FILE_NOT_AVAILABLE;
                }
        }
+       req->channel_generation = op->global->channel_generation;
 
        if (update_open) {
                status = smbXsrv_open_update(op);
@@ -2726,7 +2738,8 @@ static void smbd_smb2_request_reply_update_counts(struct smbd_smb2_request *req)
        inhdr = SMBD_SMB2_IN_HDR_PTR(req);
        channel_sequence = SVAL(inhdr, SMB2_HDR_CHANNEL_SEQUENCE);
 
-       if (op->global->channel_sequence == channel_sequence) {
+       if ((op->global->channel_sequence == channel_sequence) &&
+           (op->global->channel_generation == req->channel_generation)) {
                SMB_ASSERT(op->request_count > 0);
                op->request_count -= 1;
        } else {