diff options
author | Volker Lendecke <vl@samba.org> | 2018-01-11 15:34:45 +0100 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2018-01-14 10:26:05 +0100 |
commit | 0b57434151a8334a6e9b9b7542824ce4915421a2 (patch) | |
tree | 8a148e7184186689efcfa1dbc359d5e779ab7231 | |
parent | 03f65a7cdc91091a171269cfebc9916f2f678388 (diff) | |
download | samba-0b57434151a8334a6e9b9b7542824ce4915421a2.tar.gz |
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 <metze@samba.org>
Signed-off-by: Volker Lendecke <vl@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
-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 { |