From 1018d16a78e14511ec68ec778151a6819969a440 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:18:12 -0800 Subject: [PATCH 01/12] CVE-2015-7560: s3: smbd: Add refuse_symlink() function that can be used to prevent operations on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index b6109b2..7de4f05 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -53,6 +53,34 @@ static char *store_file_unix_basic_info2(connection_struct *conn, files_struct *fsp, const SMB_STRUCT_STAT *psbuf); +/**************************************************************************** + Check if an open file handle or pathname is a symlink. +****************************************************************************/ + +static NTSTATUS refuse_symlink(connection_struct *conn, + const files_struct *fsp, + const char *name) +{ + SMB_STRUCT_STAT sbuf; + const SMB_STRUCT_STAT *pst = NULL; + + if (fsp) { + pst = &fsp->fsp_name->st; + } else { + int ret = vfs_stat_smb_basename(conn, + name, + &sbuf); + if (ret == -1) { + return map_nt_error_from_unix(errno); + } + pst = &sbuf; + } + if (S_ISLNK(pst->st_ex_mode)) { + return NT_STATUS_ACCESS_DENIED; + } + return NT_STATUS_OK; +} + /******************************************************************** The canonical "check access" based on object handle or path function. ********************************************************************/ -- 1.9.1 From 6f2e1fbd5de2239d89db785e1b9c3a41aa82adee Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 10:38:28 -0800 Subject: [PATCH 02/12] CVE-2015-7560: s3: smbd: Refuse to get an ACL from a POSIX file handle on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/nttrans.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 131009b..5a6a784 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -1912,6 +1912,13 @@ NTSTATUS smbd_do_query_security_desc(connection_struct *conn, return NT_STATUS_ACCESS_DENIED; } + if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) { + DEBUG(10, ("ACL get on symlink %s denied.\n", + fsp_str_dbg(fsp))); + TALLOC_FREE(frame); + return NT_STATUS_ACCESS_DENIED; + } + if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER| SECINFO_GROUP|SECINFO_SACL)) { /* Don't return SECINFO_LABEL if anything else was -- 1.9.1 From a728e2bdcd91a6ae7413b48ff140c3978276b05b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 10:52:50 -0800 Subject: [PATCH 03/12] CVE-2015-7560: s3: smbd: Refuse to set an ACL from a POSIX file handle on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/nttrans.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 5a6a784..8d887a3 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -882,6 +882,12 @@ NTSTATUS set_sd(files_struct *fsp, struct security_descriptor *psd, return NT_STATUS_OK; } + if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) { + DEBUG(10, ("ACL set on symlink %s denied.\n", + fsp_str_dbg(fsp))); + return NT_STATUS_ACCESS_DENIED; + } + if (psd->owner_sid == NULL) { security_info_sent &= ~SECINFO_OWNER; } -- 1.9.1 From 73eaaa5d61e5ec7a24ac990de04454748e23dc73 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:22:12 -0800 Subject: [PATCH 04/12] CVE-2015-7560: s3: smbd: Refuse to set a POSIX ACL on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 7de4f05..5b008f5 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -6567,6 +6567,7 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, uint16 num_def_acls; bool valid_file_acls = True; bool valid_def_acls = True; + NTSTATUS status; if (total_data < SMB_POSIX_ACL_HEADER_SIZE) { return NT_STATUS_INVALID_PARAMETER; @@ -6594,6 +6595,11 @@ static NTSTATUS smb_set_posix_acl(connection_struct *conn, return NT_STATUS_INVALID_PARAMETER; } + status = refuse_symlink(conn, fsp, smb_fname->base_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n", smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp), (unsigned int)num_file_acls, -- 1.9.1 From 3074a65924edee75db879cb5e474795de51e96e3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:24:36 -0800 Subject: [PATCH 05/12] CVE-2015-7560: s3: smbd: Refuse to get a POSIX ACL on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 5b008f5..3fca8f2 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -5058,6 +5058,13 @@ NTSTATUS smbd_do_qfilepathinfo(connection_struct *conn, uint16 num_file_acls = 0; uint16 num_def_acls = 0; + status = refuse_symlink(conn, + fsp, + smb_fname->base_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + if (fsp && fsp->fh->fd != -1) { file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, talloc_tos()); -- 1.9.1 From 94cad26df95ab7c244f1274f0feb29ab376f02c2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:05:48 -0800 Subject: [PATCH 06/12] CVE-2015-7560: s3: smbd: Set return values early, allows removal of code duplication. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 3fca8f2..3d16d6e 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -237,11 +237,12 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, size_t num_names; ssize_t sizeret = -1; + if (pnames) { + *pnames = NULL; + } + *pnum_names = 0; + if (!lp_ea_support(SNUM(conn))) { - if (pnames) { - *pnames = NULL; - } - *pnum_names = 0; return NT_STATUS_OK; } @@ -291,10 +292,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, if (sizeret == 0) { TALLOC_FREE(names); - if (pnames) { - *pnames = NULL; - } - *pnum_names = 0; return NT_STATUS_OK; } -- 1.9.1 From cd3730a17bcade2f1ec7aabb296fda90b4342655 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:29:38 -0800 Subject: [PATCH 07/12] CVE-2015-7560: s3: smbd: Silently return no EA's available on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 3d16d6e..04a13c4 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -236,6 +236,7 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, char **names, **tmp; size_t num_names; ssize_t sizeret = -1; + NTSTATUS status; if (pnames) { *pnames = NULL; @@ -246,6 +247,14 @@ NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, return NT_STATUS_OK; } + status = refuse_symlink(conn, fsp, fname); + if (!NT_STATUS_IS_OK(status)) { + /* + * Just return no EA's on a symlink. + */ + return NT_STATUS_OK; + } + /* * TALLOC the result early to get the talloc hierarchy right. */ -- 1.9.1 From 1469687cff56dcf651e6f74f61ba0360626ee657 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 5 Jan 2016 11:33:48 -0800 Subject: [PATCH 08/12] CVE-2015-7560: s3: smbd: Refuse to set EA's on a symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/smbd/trans2.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 04a13c4..103e601 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -658,6 +658,11 @@ NTSTATUS set_ea(connection_struct *conn, files_struct *fsp, return NT_STATUS_EAS_NOT_SUPPORTED; } + status = refuse_symlink(conn, fsp, smb_fname->base_name); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = check_access(conn, fsp, smb_fname, FILE_WRITE_EA); if (!NT_STATUS_IS_OK(status)) { return status; -- 1.9.1 From e39434f73dc0468aff003559846d435505088183 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 6 Jan 2016 17:17:24 -0800 Subject: [PATCH 09/12] CVE-2015-7560: s3: libsmb: Rename cli_posix_getfaclXX() functions to cli_posix_getacl() as they operate on pathnames. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/client/client.c | 2 +- source3/libsmb/clifile.c | 30 +++++++++++++++--------------- source3/libsmb/proto.h | 6 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index 00f8282..aa54736 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -3380,7 +3380,7 @@ static int cmd_getfacl(void) return 1; } - status = cli_posix_getfacl(targetcli, targetname, ctx, &rb_size, &retbuf); + status = cli_posix_getacl(targetcli, targetname, ctx, &rb_size, &retbuf); if (!NT_STATUS_IS_OK(status)) { d_printf("%s getfacl file %s\n", nt_errstr(status), src); diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 70b769d..b353b2b 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -590,25 +590,25 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli, } /**************************************************************************** - Do a POSIX getfacl (UNIX extensions). + Do a POSIX getacl - pathname based ACL get (UNIX extensions). ****************************************************************************/ -struct getfacl_state { +struct getacl_state { uint32_t num_data; uint8_t *data; }; -static void cli_posix_getfacl_done(struct tevent_req *subreq); +static void cli_posix_getacl_done(struct tevent_req *subreq); -struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx, +struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, const char *fname) { struct tevent_req *req = NULL, *subreq = NULL; - struct getfacl_state *state = NULL; + struct getacl_state *state = NULL; - req = tevent_req_create(mem_ctx, &state, struct getfacl_state); + req = tevent_req_create(mem_ctx, &state, struct getacl_state); if (req == NULL) { return NULL; } @@ -617,16 +617,16 @@ struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx, if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, cli_posix_getfacl_done, req); + tevent_req_set_callback(subreq, cli_posix_getacl_done, req); return req; } -static void cli_posix_getfacl_done(struct tevent_req *subreq) +static void cli_posix_getacl_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); - struct getfacl_state *state = tevent_req_data( - req, struct getfacl_state); + struct getacl_state *state = tevent_req_data( + req, struct getacl_state); NTSTATUS status; status = cli_qpathinfo_recv(subreq, state, &state->data, @@ -638,12 +638,12 @@ static void cli_posix_getfacl_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req, +NTSTATUS cli_posix_getacl_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, size_t *prb_size, char **retbuf) { - struct getfacl_state *state = tevent_req_data(req, struct getfacl_state); + struct getacl_state *state = tevent_req_data(req, struct getacl_state); NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { @@ -654,7 +654,7 @@ NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req, return NT_STATUS_OK; } -NTSTATUS cli_posix_getfacl(struct cli_state *cli, +NTSTATUS cli_posix_getacl(struct cli_state *cli, const char *fname, TALLOC_CTX *mem_ctx, size_t *prb_size, @@ -679,7 +679,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli, goto fail; } - req = cli_posix_getfacl_send(frame, + req = cli_posix_getacl_send(frame, ev, cli, fname); @@ -693,7 +693,7 @@ NTSTATUS cli_posix_getfacl(struct cli_state *cli, goto fail; } - status = cli_posix_getfacl_recv(req, mem_ctx, prb_size, retbuf); + status = cli_posix_getacl_recv(req, mem_ctx, prb_size, retbuf); fail: TALLOC_FREE(frame); diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 525625c..e20e06c 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -255,15 +255,15 @@ NTSTATUS cli_posix_hardlink(struct cli_state *cli, const char *newname); uint32_t unix_perms_to_wire(mode_t perms); mode_t wire_perms_to_unix(uint32_t perms); -struct tevent_req *cli_posix_getfacl_send(TALLOC_CTX *mem_ctx, +struct tevent_req *cli_posix_getacl_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, const char *fname); -NTSTATUS cli_posix_getfacl_recv(struct tevent_req *req, +NTSTATUS cli_posix_getacl_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, size_t *prb_size, char **retbuf); -NTSTATUS cli_posix_getfacl(struct cli_state *cli, +NTSTATUS cli_posix_getacl(struct cli_state *cli, const char *fname, TALLOC_CTX *mem_ctx, size_t *prb_size, -- 1.9.1 From 47bd596a43eb5dcfffedda5045fab757ee1ead64 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 6 Jan 2016 17:02:52 -0800 Subject: [PATCH 10/12] CVE-2015-7560: s3: libsmb: Add SMB1-only POSIX cli_posix_setacl() functions. Needed for tests. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- source3/libsmb/clifile.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++ source3/libsmb/proto.h | 11 ++++++ 2 files changed, 111 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index b353b2b..642f597 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -701,6 +701,106 @@ NTSTATUS cli_posix_getacl(struct cli_state *cli, } /**************************************************************************** + Do a POSIX setacl - pathname based ACL set (UNIX extensions). +****************************************************************************/ + +struct setacl_state { + uint8_t *data; +}; + +static void cli_posix_setacl_done(struct tevent_req *subreq); + +struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + const void *data, + size_t num_data) +{ + struct tevent_req *req = NULL, *subreq = NULL; + struct setacl_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, struct setacl_state); + if (req == NULL) { + return NULL; + } + state->data = talloc_memdup(state, data, num_data); + if (tevent_req_nomem(state->data, req)) { + return tevent_req_post(req, ev); + } + + subreq = cli_setpathinfo_send(state, + ev, + cli, + SMB_SET_POSIX_ACL, + fname, + state->data, + num_data); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_posix_setacl_done, req); + return req; +} + +static void cli_posix_setacl_done(struct tevent_req *subreq) +{ + NTSTATUS status = cli_setpathinfo_recv(subreq); + tevent_req_simple_finish_ntstatus(subreq, status); +} + +NTSTATUS cli_posix_setacl_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +NTSTATUS cli_posix_setacl(struct cli_state *cli, + const char *fname, + const void *acl_buf, + size_t acl_buf_size) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct tevent_context *ev = NULL; + struct tevent_req *req = NULL; + NTSTATUS status = NT_STATUS_OK; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = samba_tevent_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_posix_setacl_send(frame, + ev, + cli, + fname, + acl_buf, + acl_buf_size); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + goto fail; + } + + status = cli_posix_setacl_recv(req); + + fail: + TALLOC_FREE(frame); + return status; +} + +/**************************************************************************** Stat a file (UNIX extensions). ****************************************************************************/ diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index e20e06c..d670693 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -268,6 +268,17 @@ NTSTATUS cli_posix_getacl(struct cli_state *cli, TALLOC_CTX *mem_ctx, size_t *prb_size, char **retbuf); +struct tevent_req *cli_posix_setacl_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *fname, + const void *acl_buf, + size_t acl_buf_size); +NTSTATUS cli_posix_setacl_recv(struct tevent_req *req); +NTSTATUS cli_posix_setacl(struct cli_state *cli, + const char *fname, + const void *acl_buf, + size_t acl_buf_size); struct tevent_req *cli_posix_stat_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, -- 1.9.1 From 96ecabd03cc50e615e621d63d0a3ca3f0b2e5504 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 7 Jan 2016 12:58:34 -0800 Subject: [PATCH 11/12] CVE-2015-7560: s3: torture3: Add new POSIX-SYMLINK-ACL test. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- selftest/knownfail | 1 + source3/selftest/tests.py | 2 +- source3/torture/torture.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 1 deletion(-) diff --git a/selftest/knownfail b/selftest/knownfail index 104ddbd..ac374c0 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -16,6 +16,7 @@ ^samba3.smbtorture_s3.plain\(dc\).UID-REGRESSION-TEST # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).SHORTNAME-TEST # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).POSIX-APPEND # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-ACL # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).NTTRANS-FSCTL # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).SMB2-NEGPROT # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).BAD-NBT-SESSION # Fails against the s4 ntvfs server diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 786b52a..abd9b3f 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -79,7 +79,7 @@ tests = ["RW1", "RW2", "RW3"] for t in tests: plantestsuite("samba3.smbtorture_s3.vfs_aio_fork(simpleserver).%s" % t, "simpleserver", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/vfs_aio_fork', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) -posix_tests = ["POSIX", "POSIX-APPEND"] +posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL"] for t in posix_tests: plantestsuite("samba3.smbtorture_s3.plain(s3dc).%s" % t, "s3dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/posix_share', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 2e66912..82ff1ca 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -5754,6 +5754,203 @@ static bool run_simple_posix_open_test(int dummy) return correct; } +/* + Test POSIX and Windows ACLs are rejected on symlinks. + */ +static bool run_acl_symlink_test(int dummy) +{ + static struct cli_state *cli; + const char *fname = "posix_file"; + const char *sname = "posix_symlink"; + uint16_t fnum = (uint16_t)-1; + bool correct = false; + NTSTATUS status; + char *posix_acl = NULL; + size_t posix_acl_len = 0; + char *posix_acl_sym = NULL; + size_t posix_acl_len_sym = 0; + struct security_descriptor *sd = NULL; + struct security_descriptor *sd_sym = NULL; + TALLOC_CTX *frame = NULL; + + frame = talloc_stackframe(); + + printf("Starting acl symlink test\n"); + + if (!torture_open_connection(&cli, 0)) { + TALLOC_FREE(frame); + return false; + } + + smbXcli_conn_set_sockopt(cli->conn, sockops); + + status = torture_setup_unix_extensions(cli); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return false; + } + + cli_setatr(cli, fname, 0, 0); + cli_posix_unlink(cli, fname); + cli_setatr(cli, sname, 0, 0); + cli_posix_unlink(cli, sname); + + status = cli_ntcreate(cli, + fname, + 0, + READ_CONTROL_ACCESS, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_CREATE, + 0x0, + 0x0, + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_ntcreate of %s failed (%s)\n", + fname, + nt_errstr(status)); + goto out; + } + + /* Get the Windows ACL on the file. */ + status = cli_query_secdesc(cli, + fnum, + frame, + &sd); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_query_secdesc failed (%s)\n", + nt_errstr(status)); + goto out; + } + + /* Get the POSIX ACL on the file. */ + status = cli_posix_getacl(cli, + fname, + frame, + &posix_acl_len, + &posix_acl); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_getacl failed (%s)\n", + nt_errstr(status)); + goto out; + } + + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed (%s)\n", nt_errstr(status)); + goto out; + } + fnum = (uint16_t)-1; + + /* Now create a symlink. */ + status = cli_posix_symlink(cli, fname, sname); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_symlink of %s -> %s failed (%s)\n", + sname, + fname, + nt_errstr(status)); + goto out; + } + + /* Open a handle on the symlink. */ + status = cli_ntcreate(cli, + sname, + 0, + READ_CONTROL_ACCESS|SEC_STD_WRITE_DAC, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, + 0x0, + 0x0, + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_open of %s failed (%s)\n", + sname, + nt_errstr(status)); + goto out; + } + + /* Get the Windows ACL on the symlink handle. Should fail */ + status = cli_query_secdesc(cli, + fnum, + frame, + &sd_sym); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("cli_query_secdesc on a symlink gave %s. " + "Should be NT_STATUS_ACCESS_DENIED.\n", + nt_errstr(status)); + goto out; + } + + /* Get the POSIX ACL on the symlink pathname. Should fail. */ + status = cli_posix_getacl(cli, + sname, + frame, + &posix_acl_len_sym, + &posix_acl_sym); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("cli_posix_getacl on a symlink gave %s. " + "Should be NT_STATUS_ACCESS_DENIED.\n", + nt_errstr(status)); + goto out; + } + + /* Set the Windows ACL on the symlink handle. Should fail */ + status = cli_set_security_descriptor(cli, + fnum, + SECINFO_DACL, + sd); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("cli_query_secdesc on a symlink gave %s. " + "Should be NT_STATUS_ACCESS_DENIED.\n", + nt_errstr(status)); + goto out; + } + + /* Set the POSIX ACL on the symlink pathname. Should fail. */ + status = cli_posix_setacl(cli, + sname, + posix_acl, + posix_acl_len); + + if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + printf("cli_posix_getacl on a symlink gave %s. " + "Should be NT_STATUS_ACCESS_DENIED.\n", + nt_errstr(status)); + goto out; + } + + printf("ACL symlink test passed\n"); + correct = true; + + out: + + if (fnum != (uint16_t)-1) { + cli_close(cli, fnum); + fnum = (uint16_t)-1; + } + + cli_setatr(cli, sname, 0, 0); + cli_posix_unlink(cli, sname); + cli_setatr(cli, fname, 0, 0); + cli_posix_unlink(cli, fname); + + if (!torture_close_connection(cli)) { + correct = false; + } + + TALLOC_FREE(frame); + return correct; +} + static uint32 open_attrs_table[] = { FILE_ATTRIBUTE_NORMAL, @@ -9458,6 +9655,7 @@ static struct { {"OPEN", run_opentest, 0}, {"POSIX", run_simple_posix_open_test, 0}, {"POSIX-APPEND", run_posix_append, 0}, + {"POSIX-SYMLINK-ACL", run_acl_symlink_test, 0}, {"CASE-INSENSITIVE-CREATE", run_case_insensitive_create, 0}, {"ASYNC-ECHO", run_async_echo, 0}, { "UID-REGRESSION-TEST", run_uid_regression_test, 0}, -- 1.9.1 From eaf2c6bd79b0f136def6a0e0a6cb403cd5b249d7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 7 Jan 2016 14:26:35 -0800 Subject: [PATCH 12/12] CVE-2015-7560: s3: torture3: Add new POSIX-SYMLINK-EA test. BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648 Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam --- selftest/knownfail | 1 + source3/selftest/tests.py | 2 +- source3/torture/torture.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+), 1 deletion(-) diff --git a/selftest/knownfail b/selftest/knownfail index ac374c0..bf35b75 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -17,6 +17,7 @@ ^samba3.smbtorture_s3.plain\(dc\).SHORTNAME-TEST # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).POSIX-APPEND # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-ACL # Fails against the s4 ntvfs server +^samba3.smbtorture_s3.plain\(ad_dc_ntvfs\).POSIX-SYMLINK-EA # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).NTTRANS-FSCTL # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).SMB2-NEGPROT # Fails against the s4 ntvfs server ^samba3.smbtorture_s3.plain\(dc\).BAD-NBT-SESSION # Fails against the s4 ntvfs server diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index abd9b3f..02adeed 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -79,7 +79,7 @@ tests = ["RW1", "RW2", "RW3"] for t in tests: plantestsuite("samba3.smbtorture_s3.vfs_aio_fork(simpleserver).%s" % t, "simpleserver", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/vfs_aio_fork', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) -posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL"] +posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA"] for t in posix_tests: plantestsuite("samba3.smbtorture_s3.plain(s3dc).%s" % t, "s3dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/posix_share', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"]) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 82ff1ca..78803cf 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -5951,6 +5951,183 @@ static bool run_acl_symlink_test(int dummy) return correct; } +/* + Test setting EA's are rejected on symlinks. + */ +static bool run_ea_symlink_test(int dummy) +{ + static struct cli_state *cli; + const char *fname = "posix_file_ea"; + const char *sname = "posix_symlink_ea"; + const char *ea_name = "testea_name"; + const char *ea_value = "testea_value"; + uint16_t fnum = (uint16_t)-1; + bool correct = false; + NTSTATUS status; + size_t i, num_eas; + struct ea_struct *eas = NULL; + TALLOC_CTX *frame = NULL; + + frame = talloc_stackframe(); + + printf("Starting EA symlink test\n"); + + if (!torture_open_connection(&cli, 0)) { + TALLOC_FREE(frame); + return false; + } + + smbXcli_conn_set_sockopt(cli->conn, sockops); + + status = torture_setup_unix_extensions(cli); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(frame); + return false; + } + + cli_setatr(cli, fname, 0, 0); + cli_posix_unlink(cli, fname); + cli_setatr(cli, sname, 0, 0); + cli_posix_unlink(cli, sname); + + status = cli_ntcreate(cli, + fname, + 0, + READ_CONTROL_ACCESS, + 0, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_CREATE, + 0x0, + 0x0, + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_ntcreate of %s failed (%s)\n", + fname, + nt_errstr(status)); + goto out; + } + + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + printf("close failed (%s)\n", + nt_errstr(status)); + goto out; + } + fnum = (uint16_t)-1; + + /* Set an EA on the path. */ + status = cli_set_ea_path(cli, + fname, + ea_name, + ea_value, + strlen(ea_value)+1); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_set_ea_path failed (%s)\n", + nt_errstr(status)); + goto out; + } + + /* Now create a symlink. */ + status = cli_posix_symlink(cli, fname, sname); + if (!NT_STATUS_IS_OK(status)) { + printf("cli_posix_symlink of %s -> %s failed (%s)\n", + sname, + fname, + nt_errstr(status)); + goto out; + } + + /* Get the EA list on the path. Should return value set. */ + status = cli_get_ea_list_path(cli, + fname, + frame, + &num_eas, + &eas); + + if (!NT_STATUS_IS_OK(status)) { + printf("cli_get_ea_list_path failed (%s)\n", + nt_errstr(status)); + goto out; + } + + /* Ensure the EA we set is there. */ + for (i=0; i