From afc03441611022a810020d3c7c2f336aa660476a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 21 May 2019 14:52:22 +0200 Subject: [PATCH 1/3] smbd: Enable "smbd:suicide mode" for smb2 The next commit needs an smbd to just exit and leave data behind in the locking.tdb file. Don't make it harder to eventually phase out SMB1: Do the test in SMB2. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13957 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- source3/smbd/smb2_server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index 49c3eb9499d..6a95d33ab01 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -31,6 +31,7 @@ #include "lib/util/iov_buf.h" #include "auth.h" #include "lib/crypto/sha512.h" +#include "libcli/smb/smbXcli_base.h" #undef DBGC_CLASS #define DBGC_CLASS DBGC_SMB2 @@ -445,6 +446,17 @@ static NTSTATUS smbd_smb2_inbuf_parse_compound(struct smbXsrv_connection *xconn, */ if (len < SMB2_HDR_BODY + 2) { + + if ((len == 5) && + (IVAL(hdr, 0) == 0x74697865) && + lp_parm_bool(-1, "smbd", "suicide mode", false)) { + uint8_t exitcode = CVAL(hdr, 4); + DBG_WARNING("SUICIDE: Exiting immediately " + "with code %"PRIu8"\n", + exitcode); + exit(exitcode); + } + DEBUG(10, ("%d bytes left, expected at least %d\n", (int)len, SMB2_HDR_BODY)); goto inval; -- 2.17.1 From a286666016caf68a7e69498cb516c4d6ed75159a Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 21 May 2019 14:53:46 +0200 Subject: [PATCH 2/3] smbtorture: Add a test to make smbd panic Bug: https://bugzilla.samba.org/show_bug.cgi?id=13957 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme --- selftest/knownfail | 2 + source4/torture/smb2/oplock.c | 75 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index f850d9e1a87..b0357250574 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -133,6 +133,7 @@ ^samba4.smb2.oplock.exclusive9\(.*\)$ ^samba4.smb2.oplock.brl3\(.*\)$ # samba 4 oplocks are a mess ^samba4.smb2.oplock.levelii500\(.*\)$ # samba 4 oplocks are a mess +^samba4.smb2.oplock.levelii502\(.*\)$ # samba 4 oplocks are a mess ^samba4.smb2.oplock.brl1\(.*\)$ # samba 4 oplocks are a mess ^samba4.smb2.oplock.batch22\(.*\)$ # samba 4 oplocks are a mess ^samba4.smb2.oplock.batch19\(.*\)$ # samba 4 oplocks are a mess @@ -174,6 +175,7 @@ ^samba3.smb2.dir.modify ^samba3.smb2.oplock.batch20 ^samba3.smb2.oplock.stream1 +^samba3.smb2.oplock.levelii502 ^samba3.smb2.streams.rename ^samba3.smb2.streams.rename2 ^samba3.smb2.streams.attributes diff --git a/source4/torture/smb2/oplock.c b/source4/torture/smb2/oplock.c index 800a4cf299f..fc440b4063b 100644 --- a/source4/torture/smb2/oplock.c +++ b/source4/torture/smb2/oplock.c @@ -26,6 +26,7 @@ #include "libcli/smb2/smb2_calls.h" #include "libcli/smb_composite/smb_composite.h" #include "libcli/resolve/resolve.h" +#include "libcli/smb/smbXcli_base.h" #include "lib/cmdline/popt_common.h" #include "lib/events/events.h" @@ -3949,6 +3950,78 @@ static void levelII501_timeout_cb(struct tevent_context *ev, state->done = true; } +static bool test_smb2_oplock_levelII502(struct torture_context *tctx, + struct smb2_tree *tree1, + struct smb2_tree *tree2) + +{ + const char *fname = BASEDIR "\\test_levelII502.dat"; + NTSTATUS status; + union smb_open io; + struct smb2_close closeio; + struct smb2_handle h; + + status = torture_smb2_testdir(tree1, BASEDIR, &h); + torture_assert_ntstatus_ok(tctx, status, "Error creating directory"); + + /* cleanup */ + smb2_util_unlink(tree1, fname); + + /* + base ntcreatex parms + */ + ZERO_STRUCT(io.smb2); + io.generic.level = RAW_OPEN_SMB2; + io.smb2.in.desired_access = SEC_RIGHTS_FILE_ALL; + io.smb2.in.alloc_size = 0; + io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; + io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN_IF; + io.smb2.in.create_options = 0; + io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; + io.smb2.in.security_flags = 0; + io.smb2.in.fname = fname; + + torture_comment( + tctx, + "LEVELII502: Open a stale LEVEL2 oplock with OVERWRITE"); + + io.smb2.in.desired_access = SEC_RIGHTS_FILE_READ | + SEC_RIGHTS_FILE_WRITE; + io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | + NTCREATEX_SHARE_ACCESS_WRITE; + io.smb2.in.create_flags = NTCREATEX_FLAGS_EXTENDED; + io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_II; + status = smb2_create(tree1, tctx, &(io.smb2)); + torture_assert_ntstatus_ok(tctx, status, "Error opening the file"); + torture_assert(tctx, + io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_II, + "Did not get LEVEL_II oplock\n"); + + status = smbXcli_conn_samba_suicide( + tree1->session->transport->conn, 93); + torture_assert_ntstatus_ok(tctx, status, "suicide failed"); + + sleep(1); + + io.smb2.in.oplock_level = SMB2_OPLOCK_LEVEL_BATCH; + io.smb2.in.create_disposition = NTCREATEX_DISP_OVERWRITE; + + status = smb2_create(tree2, tctx, &(io.smb2)); + torture_assert_ntstatus_ok(tctx, status, "Error opening the file"); + torture_assert(tctx, + io.smb2.out.oplock_level==SMB2_OPLOCK_LEVEL_BATCH, + "Did not get BATCH oplock\n"); + + closeio = (struct smb2_close) { + .in.file.handle = io.smb2.out.file.handle, + }; + status = smb2_close(tree2, &closeio); + torture_assert_ntstatus_equal( + tctx, status, NT_STATUS_OK, "close failed"); + + return true; +} + struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx) { struct torture_suite *suite = @@ -3995,6 +4068,8 @@ struct torture_suite *torture_smb2_oplocks_init(TALLOC_CTX *ctx) torture_suite_add_1smb2_test(suite, "levelii500", test_smb2_oplock_levelII500); torture_suite_add_2smb2_test(suite, "levelii501", test_smb2_oplock_levelII501); + torture_suite_add_2smb2_test(suite, "levelii502", + test_smb2_oplock_levelII502); suite->description = talloc_strdup(suite, "SMB2-OPLOCK tests"); return suite; -- 2.17.1 From d1d2c67bf905f278253e59cdcb939b4574899c4f Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 21 May 2019 15:26:55 +0200 Subject: [PATCH 3/3] smbd: Fix a panic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opening a file with a stale (smbd died) LEVEL_II oplock makes vfs_set_filelen-> ... ->contend_level2_oplocks_begin_default trigger the immediate leading to do_break_to_none. This goes through because fsp->oplock_type is not initialized yet, thus 0. Also, file_has_read_oplocks is still valid, because the smbd that has died could not clean up the brlock.tdb entry. Later in the code the exclusive oplock is granted, which is then found by do_break_to_none, making it panic. This patch just runs the direct FTRUNCATE instead of vfs_set_filelen. This means the contend_level2_oplock code is skipped. The relevant break (LEVEL_II to NONE) is now done in delay_for_oplock() with the nice effect of removing a comment that was very confusing to me. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13957 Signed-off-by: Volker Lendecke Reviewed-by: Ralph Boehme Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Wed May 22 20:09:29 UTC 2019 on sn-devel-184 --- selftest/knownfail | 1 - source3/smbd/open.c | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/selftest/knownfail b/selftest/knownfail index b0357250574..4139bfd02bc 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -175,7 +175,6 @@ ^samba3.smb2.dir.modify ^samba3.smb2.oplock.batch20 ^samba3.smb2.oplock.stream1 -^samba3.smb2.oplock.levelii502 ^samba3.smb2.streams.rename ^samba3.smb2.streams.rename2 ^samba3.smb2.streams.attributes diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 461fb7eb237..af6a36f0bd0 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1875,12 +1875,7 @@ static bool delay_for_oplock(files_struct *fsp, break_to = e_lease_type & ~delay_mask; if (will_overwrite) { - /* - * we'll decide about SMB2_LEASE_READ later. - * - * Maybe the break will be deferred - */ - break_to &= ~SMB2_LEASE_HANDLE; + break_to &= ~(SMB2_LEASE_HANDLE|SMB2_LEASE_READ); } DEBUG(10, ("entry %u: e_lease_type %u, will_overwrite: %u\n", @@ -3622,13 +3617,17 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn, (!S_ISFIFO(fsp->fsp_name->st.st_ex_mode))) { int ret; - ret = vfs_set_filelen(fsp, 0); + ret = SMB_VFS_FTRUNCATE(fsp, 0); if (ret != 0) { status = map_nt_error_from_unix(errno); TALLOC_FREE(lck); fd_close(fsp); return status; } + notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_ATTRIBUTES, + fsp->fsp_name->base_name); } /* -- 2.17.1