summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2012-06-27 15:33:43 +0200
committerStefan Metzmacher <metze@samba.org>2012-06-29 00:14:54 +0200
commitee8ae459aea6879377b5510851a6dc673cf72aad (patch)
tree960cd37312c85a9dc99603a302c7f949df2c76aa
parent4fe41c0bb14f6ae7e52aa7f180e66c7695eb6fa0 (diff)
downloadsamba-ee8ae459aea6879377b5510851a6dc673cf72aad.tar.gz
samba-ee8ae459aea6879377b5510851a6dc673cf72aad.tar.bz2
samba-ee8ae459aea6879377b5510851a6dc673cf72aad.zip
s3:smb2_server: make sure we don't grant more credits than we allow
If the client hasn't consumed the lowest seqnum, but the distance between lowest and highest seqnum has reached max credits. In that case we should stop granting credits. metze
-rw-r--r--source3/smbd/globals.h43
-rw-r--r--source3/smbd/smb2_server.c84
2 files changed, 92 insertions, 35 deletions
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 4cbafe47ca..9512d05735 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -641,14 +641,49 @@ struct smbd_server_connection {
bool blocking_lock_unlock_state;
} locks;
struct smbd_smb2_request *requests;
+ /*
+ * seqnum_low is the lowest sequence number
+ * we will accept.
+ */
uint64_t seqnum_low;
- uint32_t credits_granted;
- uint32_t max_credits;
+ /*
+ * seqnum_range is the range of credits we have
+ * granted from the sequence windows starting
+ * at seqnum_low.
+ *
+ * This gets incremented when new credits are
+ * granted and gets decremented when the
+ * lowest sequence number is consumed
+ * (when seqnum_low gets incremented).
+ */
+ uint16_t seqnum_range;
+ /*
+ * credits_grantedThe number of credits we have currently granted
+ * to the client.
+ *
+ * This gets incremented when new credits are
+ * granted and gets decremented when any credit
+ * is comsumed.
+ *
+ * Note: the decrementing is different compared
+ * to seqnum_range.
+ */
+ uint16_t credits_granted;
+ /*
+ * The maximum number of credits we will ever
+ * grant to the client.
+ *
+ * This is the "server max credits" parameter.
+ */
+ uint16_t max_credits;
+ /*
+ * a bitmap of size max_credits
+ */
+ struct bitmap *credits_bitmap;
+ bool supports_multicredit;
uint32_t max_trans;
uint32_t max_read;
uint32_t max_write;
- bool supports_multicredit;
- struct bitmap *credits_bitmap;
bool compound_related_in_progress;
} smb2;
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 872e5b9dce..320923a4cf 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -109,6 +109,7 @@ static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
}
sconn->smb2.seqnum_low = 0;
+ sconn->smb2.seqnum_range = 1;
sconn->smb2.credits_granted = 1;
sconn->smb2.max_credits = lp_smb2_max_credits();
sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
@@ -301,21 +302,25 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
if (seq_id < sconn->smb2.seqnum_low) {
DEBUG(0,("smb2_validate_sequence_number: bad message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu)\n",
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits));
+ (unsigned int)sconn->smb2.seqnum_range));
return false;
}
- if (seq_id > (sconn->smb2.seqnum_low + sconn->smb2.max_credits)) {
+ if (seq_id >= sconn->smb2.seqnum_low + sconn->smb2.seqnum_range) {
DEBUG(0,("smb2_validate_sequence_number: bad message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu)\n",
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits));
+ (unsigned int)sconn->smb2.seqnum_range));
return false;
}
@@ -323,12 +328,14 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
if (bitmap_query(credits_bm, offset)) {
DEBUG(0,("smb2_validate_sequence_number: duplicate message_id "
- "%llu (sequence id %llu) (low = %llu, max = %lu) "
+ "%llu (sequence id %llu) "
+ "(granted = %u, low = %llu, range = %u) "
"(bm offset %u)\n",
(unsigned long long)message_id,
(unsigned long long)seq_id,
+ (unsigned int)sconn->smb2.credits_granted,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.max_credits,
+ (unsigned int)sconn->smb2.seqnum_range,
offset));
return false;
}
@@ -352,6 +359,7 @@ static bool smb2_validate_sequence_number(struct smbd_server_connection *sconn,
bitmap_clear(credits_bm, offset);
sconn->smb2.seqnum_low += 1;
+ sconn->smb2.seqnum_range -= 1;
offset = sconn->smb2.seqnum_low % sconn->smb2.max_credits;
}
@@ -376,23 +384,25 @@ static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
credit_charge = MAX(credit_charge, 1);
}
- DEBUG(11, ("smb2_validate_message_id: mid %llu, credits_granted %llu, "
- "charge %llu, max_credits %llu, seqnum_low: %llu\n",
+ DEBUG(11, ("smb2_validate_message_id: mid %llu (charge %llu), "
+ "credits_granted %llu, "
+ "seqnum low/range: %llu/%llu\n",
(unsigned long long) message_id,
- (unsigned long long) sconn->smb2.credits_granted,
(unsigned long long) credit_charge,
- (unsigned long long) sconn->smb2.max_credits,
- (unsigned long long) sconn->smb2.seqnum_low));
+ (unsigned long long) sconn->smb2.credits_granted,
+ (unsigned long long) sconn->smb2.seqnum_low,
+ (unsigned long long) sconn->smb2.seqnum_range));
if (sconn->smb2.credits_granted < credit_charge) {
DEBUG(0, ("smb2_validate_message_id: client used more "
- "credits than granted, mid %llu, credits_granted %llu, "
- "charge %llu, max_credits %llu, seqnum_low: %llu\n",
+ "credits than granted, mid %llu, charge %llu, "
+ "credits_granted %llu, "
+ "seqnum low/range: %llu/%llu\n",
(unsigned long long) message_id,
- (unsigned long long) sconn->smb2.credits_granted,
(unsigned long long) credit_charge,
- (unsigned long long) sconn->smb2.max_credits,
- (unsigned long long) sconn->smb2.seqnum_low));
+ (unsigned long long) sconn->smb2.credits_granted,
+ (unsigned long long) sconn->smb2.seqnum_low,
+ (unsigned long long) sconn->smb2.seqnum_range));
return false;
}
@@ -517,6 +527,7 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
uint16_t credits_requested;
uint32_t out_flags;
uint16_t credits_granted = 0;
+ uint64_t credits_possible;
credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
out_flags = IVAL(outhdr, SMB2_HDR_FLAGS);
@@ -529,10 +540,8 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
* response, we should not grant
* credits on the final response.
*/
- credits_requested = 0;
- }
-
- if (credits_requested) {
+ credits_granted = 0;
+ } else if (credits_requested > 0) {
uint16_t modified_credits_requested;
uint32_t multiplier;
@@ -552,25 +561,38 @@ static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
modified_credits_requested = 1;
}
- /* Remember what we gave out. */
- credits_granted = MIN(modified_credits_requested,
- (sconn->smb2.max_credits - sconn->smb2.credits_granted));
- }
-
- if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
- /* First negprot packet, or ensure the client credits can
- never drop to zero. */
+ credits_granted = modified_credits_requested;
+ } else if (sconn->smb2.credits_granted == 0) {
+ /*
+ * Make sure the client has always at least one credit
+ */
credits_granted = 1;
}
+ /*
+ * remove the range we'll already granted to the client
+ * this makes sure the client consumes the lowest sequence
+ * number, before we can grant additional credits.
+ */
+ credits_possible = sconn->smb2.max_credits;
+ credits_possible -= sconn->smb2.seqnum_range;
+
+ credits_granted = MIN(credits_granted, credits_possible);
+
SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
sconn->smb2.credits_granted += credits_granted;
+ sconn->smb2.seqnum_range += credits_granted;
DEBUG(10,("smb2_set_operation_credit: requested %u, "
- "granted %u, total granted %u\n",
+ "granted %u, current possible %u, "
+ "total granted/max/low/range %u/%u/%llu/%u\n",
(unsigned int)credits_requested,
(unsigned int)credits_granted,
- (unsigned int)sconn->smb2.credits_granted ));
+ (unsigned int)credits_possible,
+ (unsigned int)sconn->smb2.credits_granted,
+ (unsigned int)sconn->smb2.max_credits,
+ (unsigned long long)sconn->smb2.seqnum_low,
+ (unsigned int)sconn->smb2.seqnum_range));
}
static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,