From: Volker Lendecke Date: Thu, 11 Jan 2018 14:34:45 +0000 (+0100) Subject: smbd: Fix channel sequence number checks for long-running requests X-Git-Tag: samba-4.6.15~35 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=082c08efb4dc9aad0f3a5223c7fbbc853105104f;p=thirdparty%2Fsamba.git smbd: Fix channel sequence number checks for long-running requests 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 Signed-off-by: Volker Lendecke Signed-off-by: Stefan Metzmacher (cherry picked from commit 0b57434151a8334a6e9b9b7542824ce4915421a2) --- 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 d3b9800f590..efcf3e96c8a 100644 --- a/source3/smbd/globals.h +++ b/source3/smbd/globals.h @@ -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. diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index e3e51996096..573f5f6be8c 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -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 {