torture: Add test for channel sequence number handling
authorVolker Lendecke <vl@samba.org>
Thu, 11 Jan 2018 10:55:39 +0000 (11:55 +0100)
committerStefan Metzmacher <metze@samba.org>
Sun, 14 Jan 2018 13:47:15 +0000 (14:47 +0100)
We run into an assert when the csn wraps

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

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Stefan Metzmacher <metze@samba.org>
Autobuild-Date(master): Sun Jan 14 14:47:15 CET 2018 on sn-devel-144

source4/torture/smb2/replay.c

index 889ecd73c72c165a60c2d4bd48a6b7a449e4868f..2ef40445aeef3924b2736a270abcd7c1ad5b3d6f 100644 (file)
@@ -2425,6 +2425,102 @@ done:
        return ret;
 }
 
+static bool test_replay7(struct torture_context *tctx, struct smb2_tree *tree)
+{
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       struct smb2_transport *transport = tree->session->transport;
+       NTSTATUS status;
+       struct smb2_handle _dh;
+       struct smb2_handle *dh = NULL;
+       struct smb2_notify notify;
+       struct smb2_request *req;
+       union smb_fileinfo qfinfo;
+       bool ret = false;
+
+       if (smbXcli_conn_protocol(transport->conn) < PROTOCOL_SMB3_00) {
+               torture_skip(tctx, "SMB 3.X Dialect family required for "
+                                  "replay tests\n");
+       }
+
+       torture_comment(tctx, "Notify across increment/decrement of csn\n");
+
+       smbXcli_conn_set_force_channel_sequence(transport->conn, true);
+
+       status = torture_smb2_testdir(tree, BASEDIR, &_dh);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       dh = &_dh;
+
+       notify.in.recursive             = 0x0000;
+       notify.in.buffer_size   = 0xffff;
+       notify.in.file.handle   = _dh;
+       notify.in.completion_filter     = FILE_NOTIFY_CHANGE_FILE_NAME;
+       notify.in.unknown               = 0x00000000;
+
+       /*
+        * This posts a long-running request with csn==0 to "dh". Now
+        * op->request_count==1 in smb2_server.c.
+        */
+       smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
+       req = smb2_notify_send(tree, &notify);
+
+       qfinfo = (union smb_fileinfo) {
+               .generic.level = RAW_FILEINFO_POSITION_INFORMATION,
+               .generic.in.file.handle = _dh
+       };
+
+       /*
+        * This sequence of 2 dummy requests moves
+        * op->request_count==1 to op->pre_request_count. The numbers
+        * used avoid int16 overflow.
+        */
+
+       smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 30000);
+       status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 60000);
+       status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * This final request turns the op->global->channel_sequence
+        * to the same as we had when sending the notify above. The
+        * notify's request count has in the meantime moved to
+        * op->pre_request_count.
+        */
+
+       smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0);
+       status = smb2_getinfo_file(tree, mem_ctx, &qfinfo);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       /*
+        * At this point op->request_count==0.
+        *
+        * The next cancel makes us reply to the notify. Because the
+        * csn we currently use is the same as we used when sending
+        * the notify, smbd thinks it must decrement op->request_count
+        * and not op->pre_request_count.
+        */
+
+       status = smb2_cancel(req);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       status = smb2_notify_recv(req, mem_ctx, &notify);
+       CHECK_STATUS(status, NT_STATUS_CANCELLED);
+
+       ret = true;
+
+done:
+       if (dh != NULL) {
+               smb2_util_close(tree, _dh);
+       }
+       smb2_deltree(tree, BASEDIR);
+       talloc_free(tree);
+       talloc_free(mem_ctx);
+
+       return ret;
+}
+
 struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
 {
        struct torture_suite *suite =
@@ -2445,6 +2541,7 @@ struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
        torture_suite_add_1smb2_test(suite, "replay4", test_replay4);
        torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
        torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
+       torture_suite_add_1smb2_test(suite, "replay7", test_replay7);
 
        suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");