From 547250374a5f4917d634fff3d63bd77a6011d3a4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 12:28:54 -0800 Subject: [PATCH 01/10] CVE-2021-44141: s3: torture: Add samba3.blackbox.test_symlink_traversal.SMB2. Add to knownfail.d/symlink_traversal BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 1 + .../tests/test_symlink_traversal_smb2.sh | 263 ++++++++++++++++++ source3/selftest/tests.py | 6 + 3 files changed, 270 insertions(+) create mode 100644 selftest/knownfail.d/symlink_traversal create mode 100755 source3/script/tests/test_symlink_traversal_smb2.sh diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal new file mode 100644 index 00000000000..a8ac4bbae1f --- /dev/null +++ b/selftest/knownfail.d/symlink_traversal @@ -0,0 +1 @@ +^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) diff --git a/source3/script/tests/test_symlink_traversal_smb2.sh b/source3/script/tests/test_symlink_traversal_smb2.sh new file mode 100755 index 00000000000..7e1de6dde1a --- /dev/null +++ b/source3/script/tests/test_symlink_traversal_smb2.sh @@ -0,0 +1,263 @@ +#!/bin/sh + +if [ $# -lt 7 ]; then +cat < "$tmpfile" < Date: Tue, 7 Dec 2021 12:32:19 -0800 Subject: [PATCH 02/10] CVE-2021-44141: s3: torture: Add samba3.blackbox.test_symlink_traversal.SMB1. Add to knownfail.d/symlink_traversal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 1 + .../tests/test_symlink_traversal_smb1.sh | 263 ++++++++++++++++++ source3/selftest/tests.py | 4 + 3 files changed, 268 insertions(+) create mode 100755 source3/script/tests/test_symlink_traversal_smb1.sh diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal index a8ac4bbae1f..2a51ff3f91d 100644 --- a/selftest/knownfail.d/symlink_traversal +++ b/selftest/knownfail.d/symlink_traversal @@ -1 +1,2 @@ ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) +^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\) diff --git a/source3/script/tests/test_symlink_traversal_smb1.sh b/source3/script/tests/test_symlink_traversal_smb1.sh new file mode 100755 index 00000000000..1deaaccbb54 --- /dev/null +++ b/source3/script/tests/test_symlink_traversal_smb1.sh @@ -0,0 +1,263 @@ +#!/bin/sh + +if [ $# -lt 7 ]; then +cat < "$tmpfile" < Date: Tue, 7 Dec 2021 12:34:38 -0800 Subject: [PATCH 03/10] CVE-2021-44141: s3: torture: Add samba3.blackbox.test_symlink_traversal.SMB1.posix Add to knownfail.d/symlink_traversal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 1 + .../test_symlink_traversal_smb1_posix.sh | 270 ++++++++++++++++++ source3/selftest/tests.py | 5 + 3 files changed, 276 insertions(+) create mode 100755 source3/script/tests/test_symlink_traversal_smb1_posix.sh diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal index 2a51ff3f91d..25a4da8f250 100644 --- a/selftest/knownfail.d/symlink_traversal +++ b/selftest/knownfail.d/symlink_traversal @@ -1,2 +1,3 @@ ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\) +^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\) diff --git a/source3/script/tests/test_symlink_traversal_smb1_posix.sh b/source3/script/tests/test_symlink_traversal_smb1_posix.sh new file mode 100755 index 00000000000..6241434dcf6 --- /dev/null +++ b/source3/script/tests/test_symlink_traversal_smb1_posix.sh @@ -0,0 +1,270 @@ +#!/bin/sh + +if [ $# -lt 7 ]; then +cat < "$tmpfile" < Date: Tue, 7 Dec 2021 12:56:51 -0800 Subject: [PATCH 04/10] CVE-2021-44141: s3: torture: In test_smbclient_s3, change the error codes expected for test_widelinks() and test_nosymlinks() from ACCESS_DENIED to NT_STATUS_OBJECT_NAME_NOT_FOUND. For SMB1/2/3 (minus posix) we need to treat bad symlinks as though they don't exist. Add to knwownfail.d/symlink_traversal BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 2 ++ selftest/target/Samba3.pm | 2 +- source3/script/tests/test_smbclient_s3.sh | 10 +++++----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal index 25a4da8f250..840ab38b0f9 100644 --- a/selftest/knownfail.d/symlink_traversal +++ b/selftest/knownfail.d/symlink_traversal @@ -1,3 +1,5 @@ ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\) ^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\) +^samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\) +^samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\) diff --git a/selftest/target/Samba3.pm b/selftest/target/Samba3.pm index 7385b755273..3282d763bd3 100755 --- a/selftest/target/Samba3.pm +++ b/selftest/target/Samba3.pm @@ -2536,7 +2536,7 @@ sub provision($$) create_file_chmod("$widelinks_target", 0666) or return undef; ## - ## This link should get ACCESS_DENIED + ## This link should get an error ## symlink "$widelinks_target", "$widelinks_shrdir/source"; ## diff --git a/source3/script/tests/test_smbclient_s3.sh b/source3/script/tests/test_smbclient_s3.sh index 89a17656159..e250d4dd106 100755 --- a/source3/script/tests/test_smbclient_s3.sh +++ b/source3/script/tests/test_smbclient_s3.sh @@ -1044,12 +1044,12 @@ EOF return 1 fi -# This should fail with NT_STATUS_ACCESS_DENIED - echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' +# This should fail with NT_STATUS_OBJECT_NAME_NOT_FOUND + echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND' ret=$? if [ $ret != 0 ] ; then echo "$out" - echo "failed - should get NT_STATUS_ACCESS_DENIED listing \\widelinks_share\\source" + echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND listing \\widelinks_share\\source" return 1 fi } @@ -1168,11 +1168,11 @@ EOF return 1 fi - echo "$out" | grep 'NT_STATUS_ACCESS_DENIED' + echo "$out" | grep 'NT_STATUS_OBJECT_NAME_NOT_FOUND' ret=$? if [ $ret -ne 0 ] ; then echo "$out" - echo "failed - should get NT_STATUS_ACCESS_DENIED getting \\nosymlinks\\source" + echo "failed - should get NT_STATUS_OBJECT_NAME_NOT_FOUND getting \\nosymlinks\\source" return 1 fi -- 2.30.2 From 288f54628ac0705632809c62f8ed103eff5c7cb2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 17:56:35 -0800 Subject: [PATCH 05/10] CVE-2021-44141: s3: torture: Change expected error return for samba3.smbtorture_s3.plain.POSIX.smbtorture. Trying to open a symlink as a terminal component should return NT_STATUS_OBJECT_NAME_NOT_FOUND, not NT_STATUS_OBJECT_PATH_NOT_FOUND. Mark as knownfail.d/simple_posix_open until we fix the server. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/simple_posix_open | 1 + source3/torture/torture.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 selftest/knownfail.d/simple_posix_open diff --git a/selftest/knownfail.d/simple_posix_open b/selftest/knownfail.d/simple_posix_open new file mode 100644 index 00000000000..5fcbdbdc2c6 --- /dev/null +++ b/selftest/knownfail.d/simple_posix_open @@ -0,0 +1 @@ +^samba3.smbtorture_s3.plain.POSIX.smbtorture\(.*\) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 7e193e3d8aa..7a9be0b2e04 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -8028,9 +8028,9 @@ static bool run_simple_posix_open_test(int dummy) goto out; } else { if (!check_both_error(__LINE__, status, ERRDOS, ERRbadpath, - NT_STATUS_OBJECT_PATH_NOT_FOUND)) { + NT_STATUS_OBJECT_NAME_NOT_FOUND)) { printf("POSIX open of %s should have failed " - "with NT_STATUS_OBJECT_PATH_NOT_FOUND, " + "with NT_STATUS_OBJECT_NAME_NOT_FOUND, " "failed with %s instead.\n", sname, nt_errstr(status)); goto out; -- 2.30.2 From dc588465d070b4ea8c9a91104b02cfb14bc8963d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 11:44:09 -0800 Subject: [PATCH 06/10] CVE-2021-44141: s3: smbd: For SMB1+POSIX clients trying to open a symlink, always return NT_STATUS_OBJECT_NAME_NOT_FOUND. Matches the error return from openat_pathref_fsp(). NT_STATUS_OBJECT_PATH_NOT_FOUND is for a bad component in a path, not a bad terminal symlink. Remove knownfail.d/simple_posix_open, we now pass. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/simple_posix_open | 1 - source3/smbd/open.c | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) delete mode 100644 selftest/knownfail.d/simple_posix_open diff --git a/selftest/knownfail.d/simple_posix_open b/selftest/knownfail.d/simple_posix_open deleted file mode 100644 index 5fcbdbdc2c6..00000000000 --- a/selftest/knownfail.d/simple_posix_open +++ /dev/null @@ -1 +0,0 @@ -^samba3.smbtorture_s3.plain.POSIX.smbtorture\(.*\) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 7f1aedbd1fb..753c0f56ada 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1448,12 +1448,10 @@ static NTSTATUS open_file(files_struct *fsp, * POSIX client that hit a symlink. We don't want to * return NT_STATUS_STOPPED_ON_SYMLINK to avoid handling * this special error code in all callers, so we map - * this to NT_STATUS_OBJECT_PATH_NOT_FOUND. Historically - * the lower level functions returned status code mapped - * from errno by map_nt_error_from_unix() where ELOOP is - * mapped to NT_STATUS_OBJECT_PATH_NOT_FOUND. + * this to NT_STATUS_OBJECT_NAME_NOT_FOUND to match + * openat_pathref_fsp(). */ - status = NT_STATUS_OBJECT_PATH_NOT_FOUND; + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " @@ -1536,9 +1534,10 @@ static NTSTATUS open_file(files_struct *fsp, { /* * Don't allow stat opens on symlinks directly unless - * it's a POSIX open. + * it's a POSIX open. Match the return code from + * openat_pathref_fsp(). */ - return NT_STATUS_OBJECT_PATH_NOT_FOUND; + return NT_STATUS_OBJECT_NAME_NOT_FOUND; } if (!fsp->fsp_flags.is_pathref) { -- 2.30.2 From 6a0f77324041d09e85ef9dc910d55a4506698a17 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 14:33:17 -0800 Subject: [PATCH 07/10] CVE-2021-44141: s3: smbd: Inside check_reduced_name() ensure we return the correct error codes when failing symlinks. NT_STATUS_OBJECT_PATH_NOT_FOUND for a path component failure. NT_STATUS_OBJECT_NAME_NOT_FOUND for a terminal component failure. Remove: samba3.blackbox.test_symlink_traversal.SMB1.posix samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\) samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\) in knownfail.d/symlink_traversal as we now pass these. Only one more fix remaining to get rid of knownfail.d/symlink_traversal completely. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 3 --- source3/smbd/vfs.c | 18 ++++++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal index 840ab38b0f9..2a51ff3f91d 100644 --- a/selftest/knownfail.d/symlink_traversal +++ b/selftest/knownfail.d/symlink_traversal @@ -1,5 +1,2 @@ ^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) ^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\) -^samba3.blackbox.test_symlink_traversal.SMB1.posix.symlink_traversal_SMB1_posix\(fileserver_smb1_done\) -^samba3.blackbox.smbclient_s3.*.Ensure\ widelinks\ are\ restricted\(.*\) -^samba3.blackbox.smbclient_s3.*.follow\ symlinks\ \=\ no\(.*\) diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 4091aa304d4..eadb97650a6 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1146,6 +1146,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, bool allow_symlinks = true; const char *conn_rootdir; size_t rootdir_len; + bool parent_dir_checked = false; DBG_DEBUG("check_reduced_name [%s] [%s]\n", fname, conn->connectpath); @@ -1207,6 +1208,7 @@ NTSTATUS check_reduced_name(connection_struct *conn, if (resolved_name == NULL) { return NT_STATUS_NO_MEMORY; } + parent_dir_checked = true; } else { resolved_name = resolved_fname->base_name; } @@ -1256,7 +1258,13 @@ NTSTATUS check_reduced_name(connection_struct *conn, conn_rootdir, resolved_name); TALLOC_FREE(resolved_fname); - return NT_STATUS_ACCESS_DENIED; + if (parent_dir_checked) { + /* Part of a component path. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } else { + /* End of a path. */ + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } } } @@ -1311,7 +1319,13 @@ NTSTATUS check_reduced_name(connection_struct *conn, p); TALLOC_FREE(resolved_fname); TALLOC_FREE(new_fname); - return NT_STATUS_ACCESS_DENIED; + if (parent_dir_checked) { + /* Part of a component path. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } else { + /* End of a path. */ + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } } } -- 2.30.2 From 00e552a0393840e791bc6d5351de1740f9706b90 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 14:39:42 -0800 Subject: [PATCH 08/10] CVE-2021-44141: s3: smbd: Fix a subtle bug in the error returns from filename_convert(). If filename_convert() fails to convert the path, we never call check_name(). This means we can return an incorrect error code (NT_STATUS_ACCESS_DENIED) if we ran into a symlink that points outside the share to a non-readable directory. We need to make sure in this case we always call check_name(). Remove knownfail.d/symlink_traversal. BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/symlink_traversal | 2 -- source3/smbd/filename.c | 36 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/symlink_traversal diff --git a/selftest/knownfail.d/symlink_traversal b/selftest/knownfail.d/symlink_traversal deleted file mode 100644 index 2a51ff3f91d..00000000000 --- a/selftest/knownfail.d/symlink_traversal +++ /dev/null @@ -1,2 +0,0 @@ -^samba3.blackbox.test_symlink_traversal.SMB2.symlink_traversal_SMB2\(fileserver\) -^samba3.blackbox.test_symlink_traversal.SMB1.symlink_traversal_SMB1\(fileserver_smb1_done\) diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 19eea2d6a77..6b0c4b5a2a7 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -36,6 +36,9 @@ static int get_real_filename(connection_struct *conn, TALLOC_CTX *mem_ctx, char **found_name); +static NTSTATUS check_name(connection_struct *conn, + const struct smb_filename *smb_fname); + uint32_t ucf_flags_from_smb_request(struct smb_request *req) { uint32_t ucf_flags = 0; @@ -546,6 +549,39 @@ static NTSTATUS unix_convert_step_search_fail(struct uc_state *state) if (errno == EACCES) { if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) { + /* + * Could be a symlink pointing to + * a directory outside the share + * to which we don't have access. + * If so, we need to know that here + * so we can return the correct error code. + * check_name() is never called if we + * error out of filename_convert(). + */ + int ret; + NTSTATUS status; + struct smb_filename dname = (struct smb_filename) { + .base_name = state->dirpath, + .twrp = state->smb_fname->twrp, + }; + + /* handle null paths */ + if ((dname.base_name == NULL) || + (dname.base_name[0] == '\0')) { + return NT_STATUS_ACCESS_DENIED; + } + ret = SMB_VFS_LSTAT(state->conn, &dname); + if (ret != 0) { + return NT_STATUS_ACCESS_DENIED; + } + if (!S_ISLNK(dname.st.st_ex_mode)) { + return NT_STATUS_ACCESS_DENIED; + } + status = check_name(state->conn, &dname); + if (!NT_STATUS_IS_OK(status)) { + /* We know this is an intermediate path. */ + return NT_STATUS_OBJECT_PATH_NOT_FOUND; + } return NT_STATUS_ACCESS_DENIED; } else { /* -- 2.30.2 From e999f2a84376201c5376a98e8131267357d3dc08 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 7 Dec 2021 22:15:46 -0800 Subject: [PATCH 09/10] CVE-2021-44141: s3: torture: Add a test samba3.blackbox.test_symlink_rename.SMB1.posix that shows we still leak target info across a SMB1+POSIX rename. Add a knownfail.d/posix_sylink_rename BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_sylink_rename | 1 + .../tests/test_symlink_rename_smb1_posix.sh | 186 ++++++++++++++++++ source3/selftest/tests.py | 5 + 3 files changed, 192 insertions(+) create mode 100644 selftest/knownfail.d/posix_sylink_rename create mode 100755 source3/script/tests/test_symlink_rename_smb1_posix.sh diff --git a/selftest/knownfail.d/posix_sylink_rename b/selftest/knownfail.d/posix_sylink_rename new file mode 100644 index 00000000000..9c3cc0a41ba --- /dev/null +++ b/selftest/knownfail.d/posix_sylink_rename @@ -0,0 +1 @@ +^samba3.blackbox.test_symlink_rename.SMB1.posix.symlink_rename_SMB1_posix\(fileserver_smb1_done\) diff --git a/source3/script/tests/test_symlink_rename_smb1_posix.sh b/source3/script/tests/test_symlink_rename_smb1_posix.sh new file mode 100755 index 00000000000..7d2e0037b8d --- /dev/null +++ b/source3/script/tests/test_symlink_rename_smb1_posix.sh @@ -0,0 +1,186 @@ +#!/bin/sh + +if [ $# -lt 7 ]; then +cat < "$tmpfile" < Date: Tue, 7 Dec 2021 22:19:29 -0800 Subject: [PATCH 10/10] CVE-2021-44141: s3: smbd: Inside rename_internals_fsp(), we must use vfs_stat() for existence, not SMB_VFS_STAT(). We need to take SMB1+POSIX into account here and do an LSTAT if it's a POSIX name. Remove knownfail.d/posix_sylink_rename BUG: https://bugzilla.samba.org/show_bug.cgi?id=14911 Signed-off-by: Jeremy Allison --- selftest/knownfail.d/posix_sylink_rename | 1 - source3/smbd/reply.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 selftest/knownfail.d/posix_sylink_rename diff --git a/selftest/knownfail.d/posix_sylink_rename b/selftest/knownfail.d/posix_sylink_rename deleted file mode 100644 index 9c3cc0a41ba..00000000000 --- a/selftest/knownfail.d/posix_sylink_rename +++ /dev/null @@ -1 +0,0 @@ -^samba3.blackbox.test_symlink_rename.SMB1.posix.symlink_rename_SMB1_posix\(fileserver_smb1_done\) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index d7c5b962ca7..7e520e0256c 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -7271,7 +7271,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, goto out; } - dst_exists = SMB_VFS_STAT(conn, smb_fname_dst) == 0; + dst_exists = vfs_stat(conn, smb_fname_dst) == 0; if(!replace_if_exists && dst_exists) { DEBUG(3, ("rename_internals_fsp: dest exists doing rename " -- 2.30.2