diff options
-rw-r--r-- | source3/librpc/idl/smbXsrv.idl | 3 | ||||
-rw-r--r-- | source3/smbd/globals.h | 1 | ||||
-rw-r--r-- | source3/smbd/smb2_server.c | 15 |
3 files changed, 17 insertions, 2 deletions
diff --git a/source3/librpc/idl/smbXsrv.idl b/source3/librpc/idl/smbXsrv.idl index 1bfa51ea912..d3f8d30d1e3 100644 --- a/source3/librpc/idl/smbXsrv.idl +++ b/source3/librpc/idl/smbXsrv.idl @@ -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 { diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h index 78f1260909d..69db07a490b 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -744,6 +744,7 @@ struct smbd_smb2_request { * adapted again in reply. */ bool request_counters_updated; + uint64_t channel_generation; /* * The sub request for async backend calls. diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 69788e9b2f5..a731880e98e 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -2158,6 +2158,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; @@ -2184,6 +2185,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) { /* @@ -2239,6 +2248,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) { @@ -2252,12 +2262,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); @@ -2744,7 +2756,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 { |