From 2b799880b91f2ee44531644c62916f9a50531d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Thu, 25 Feb 2016 11:15:06 +0100 Subject: torture:smb2: add test for checking sequence number wrap around. Guenther Signed-off-by: Guenther Deschner Reviewed-by: Michael Adam Reviewed-by: Jeremy Allison --- source4/torture/smb2/replay.c | 266 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) (limited to 'source4/torture/smb2/replay.c') diff --git a/source4/torture/smb2/replay.c b/source4/torture/smb2/replay.c index c32533b1d69..8388837dde4 100644 --- a/source4/torture/smb2/replay.c +++ b/source4/torture/smb2/replay.c @@ -1428,6 +1428,271 @@ done: return ret; } +static bool test_channel_sequence_table(struct torture_context *tctx, + struct smb2_tree *tree, + bool do_replay, + uint16_t opcode) +{ + NTSTATUS status; + TALLOC_CTX *mem_ctx = talloc_new(tctx); + struct smb2_handle handle; + struct smb2_handle *phandle = NULL; + struct smb2_create io; + struct GUID create_guid = GUID_random(); + bool ret = true; + const char *fname = BASEDIR "\\channel_sequence.dat"; + uint16_t csn = 0; + uint16_t limit = UINT16_MAX - 0x7fff; + int i; + struct { + uint16_t csn; + bool csn_rand_low; + bool csn_rand_high; + NTSTATUS expected_status; + } tests[] = { + { + .csn = 0, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0x7fff + 1, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 0x7fff + 2, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = -1, + .csn_rand_high = true, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 0xffff, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 0x7fff, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0x7ffe, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 0, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = -1, + .csn_rand_low = true, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 0x7fff + 1, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0xffff, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0, + .expected_status = NT_STATUS_OK, + },{ + .csn = 1, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + },{ + .csn = 1, + .expected_status = NT_STATUS_OK, + },{ + .csn = 0xffff, + .expected_status = NT_STATUS_FILE_NOT_AVAILABLE, + } + }; + + smb2cli_session_reset_channel_sequence(tree->session->smbXcli, 0); + + csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli); + torture_comment(tctx, "Testing create with channel sequence number: 0x%04x\n", csn); + + smb2_oplock_create_share(&io, fname, + smb2_util_share_access("RWD"), + smb2_util_oplock_level("b")); + io.in.durable_open = false; + io.in.durable_open_v2 = true; + io.in.create_guid = create_guid; + io.in.timeout = UINT32_MAX; + + torture_assert_ntstatus_ok_goto(tctx, + smb2_create(tree, mem_ctx, &io), + ret, done, "failed to call smb2_create"); + + handle = io.out.file.handle; + phandle = &handle; + + for (i=0; i session->smbXcli, csn); + csn = smb2cli_session_current_channel_sequence(tree->session->smbXcli); + + torture_comment(tctx, "Testing %s (replay: %s) with CSN 0x%04x, expecting: %s\n", + opstr, do_replay ? "true" : "false", csn, + nt_errstr(tests[i].expected_status)); + + if (do_replay) { + smb2cli_session_start_replay(tree->session->smbXcli); + } + + switch (opcode) { + case SMB2_OP_WRITE: { + DATA_BLOB blob = data_blob_talloc(tctx, NULL, 255); + + generate_random_buffer(blob.data, blob.length); + + status = smb2_util_write(tree, handle, blob.data, 0, blob.length); + if (NT_STATUS_IS_OK(status)) { + struct smb2_read rd; + + rd = (struct smb2_read) { + .in.file.handle = handle, + .in.length = blob.length, + .in.offset = 0 + }; + + torture_assert_ntstatus_ok_goto(tctx, + smb2_read(tree, tree, &rd), + ret, done, "failed to read after write"); + + torture_assert_data_blob_equal(tctx, + rd.out.data, blob, + "read/write mismatch"); + } + break; + } + case SMB2_OP_IOCTL: { + union smb_ioctl ioctl; + ioctl = (union smb_ioctl) { + .smb2.level = RAW_IOCTL_SMB2, + .smb2.in.file.handle = handle, + .smb2.in.function = FSCTL_CREATE_OR_GET_OBJECT_ID, + .smb2.in.max_response_size = 64, + .smb2.in.flags = SMB2_IOCTL_FLAG_IS_FSCTL + }; + status = smb2_ioctl(tree, mem_ctx, &ioctl.smb2); + break; + } + case SMB2_OP_SETINFO: { + union smb_setfileinfo sfinfo; + ZERO_STRUCT(sfinfo); + sfinfo.generic.level = RAW_SFILEINFO_POSITION_INFORMATION; + sfinfo.generic.in.file.handle = handle; + sfinfo.position_information.in.position = 0x1000; + status = smb2_setinfo_file(tree, &sfinfo); + break; + } + default: + break; + } + + qfinfo = (union smb_fileinfo) { + .generic.level = RAW_SFILEINFO_POSITION_INFORMATION, + .generic.in.file.handle = handle + }; + + torture_assert_ntstatus_ok_goto(tctx, + smb2_getinfo_file(tree, mem_ctx, &qfinfo), + ret, done, "failed to read after write"); + + if (do_replay) { + smb2cli_session_stop_replay(tree->session->smbXcli); + } + + torture_assert_ntstatus_equal_goto(tctx, + status, tests[i].expected_status, + ret, done, "got unexpected failure code"); + + } +done: + if (phandle != NULL) { + smb2_util_close(tree, *phandle); + } + + smb2_util_unlink(tree, fname); + + return ret; +} + +static bool test_channel_sequence(struct torture_context *tctx, + struct smb2_tree *tree) +{ + TALLOC_CTX *mem_ctx = talloc_new(tctx); + bool ret = true; + const char *fname = BASEDIR "\\channel_sequence.dat"; + struct smb2_transport *transport1 = tree->session->transport; + struct smb2_handle handle; + uint32_t server_capabilities; + uint16_t opcodes[] = { SMB2_OP_WRITE, SMB2_OP_IOCTL, SMB2_OP_SETINFO }; + int i; + + if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) { + torture_skip(tctx, "SMB 3.X Dialect family required for " + "Replay tests\n"); + } + + server_capabilities = smb2cli_conn_server_capabilities( + tree->session->transport->conn); + if (!(server_capabilities & SMB2_CAP_MULTI_CHANNEL)) { + torture_skip(tctx, + "Server does not support multi-channel."); + } + + torture_comment(tctx, "Testing channel sequence numbers\n"); + + torture_assert_ntstatus_ok_goto(tctx, + torture_smb2_testdir(tree, BASEDIR, &handle), + ret, done, "failed to setup test directory"); + + smb2_util_close(tree, handle); + smb2_util_unlink(tree, fname); + + for (i=0; i