The branch, v4-5-test has been updated via 4b3bda7 ctdb-scripts: Initialise CTDB_NFS_CALLOUT in statd-callout via e7856f0 ctdb-tests: Add more comm tests via 90a1908 ctdb-common: Fix use-after-free error in comm_fd_handler() via 23d35b6 s3: torture: Regression test for smbd trying to open an invalid symlink. via e6eb880 s3: smbd: Don't loop infinitely on bad-symlink resolution. via fe31f48 s3-vfs: Only walk the directory once in open_and_sort_dir() via 8f60339 s3/rpc_server/mdssvc: add attribute "kMDItemContentType" via 12dc552 s3/smbd: check for invalid access_mask smbd_calculate_access_mask() via 7da2473 selftest: also run test base.createx_access against ad_dc from 1a73c19 s3:librpc: remove bigendian argument from dcerpc_pull_ncacn_packet()
https://git.samba.org/?p=samba.git;a=shortlog;h=v4-5-test - Log ----------------------------------------------------------------- commit 4b3bda78a98ee45d1407d5cbbed0b84d8ce4404e Author: Martin Schwenke <mar...@meltin.net> Date: Tue Feb 14 09:04:41 2017 +1100 ctdb-scripts: Initialise CTDB_NFS_CALLOUT in statd-callout Some configurations may set CTDB_NFS_CALLOUT to the empty string. They may do this if they allow a choice of NFS implementations. In this case the default call-out for Linux kernel NFS should be used. However, statd-callout does not call nfs_callout_init() to set the default. Therefore, statd-callout is unable to restart the lock manager, so the grace period is never entered. statd-callout must call nfs_callout_init() before trying to restart the lock manager. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12589 Signed-off-by: Martin Schwenke <mar...@meltin.net> Reviewed-by: Amitay Isaacs <ami...@gmail.com> Autobuild-User(master): Martin Schwenke <mart...@samba.org> Autobuild-Date(master): Thu Feb 16 09:21:03 CET 2017 on sn-devel-144 (cherry picked from commit 5e7ae1b1e2fa8137aaa6a2a2f446156ae61f4c84) Autobuild-User(v4-5-test): Karolin Seeger <ksee...@samba.org> Autobuild-Date(v4-5-test): Fri Feb 17 16:17:25 CET 2017 on sn-devel-144 commit e7856f051b311ee52ad0a3a5cd580cf35d368e98 Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Feb 7 15:18:02 2017 +1100 ctdb-tests: Add more comm tests BUG: https://bugzilla.samba.org/show_bug.cgi?id=12580 Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> (cherry picked from commit 024a2c20d2bcdbcc43d16d492c7cd2d09b93c8f0) commit 90a190895b1e8cb0717e5a928947726b50bee85f Author: Amitay Isaacs <ami...@gmail.com> Date: Mon Feb 6 15:54:55 2017 +1100 ctdb-common: Fix use-after-free error in comm_fd_handler() BUG: https://bugzilla.samba.org/show_bug.cgi?id=12580 comm_write_send() creates a new tevent_req and adds it to the queue of requests to be processed. If this tevent_req is freed, then the queue entry is not removed causing use-after-free error. If the tevent_req returned by comm_write_send() is freed, then that request should be removed from the queue and any pending actions based on that request should also be removed. Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> (cherry picked from commit 9db7785fc6ffbaad434ee189c0f46c488358aab5) commit 23d35b6724fe179065357fb784707cb91bb47053 Author: Jeremy Allison <j...@samba.org> Date: Tue Feb 14 12:59:58 2017 -0800 s3: torture: Regression test for smbd trying to open an invalid symlink. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12572 Pair-programmed-with: Ralph Boehme <s...@samba.org> Signed-off-by: Jeremy Allison <j...@samba.org> Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Thu Feb 16 22:06:51 CET 2017 on sn-devel-144 (cherry picked from commit 40d813cdb312fd8378db310543e0778193a1a684) commit e6eb8807bfdf826c739a35055f65bb6a20ca7124 Author: Jeremy Allison <j...@samba.org> Date: Wed Feb 15 15:42:52 2017 -0800 s3: smbd: Don't loop infinitely on bad-symlink resolution. In the FILE_OPEN_IF case we have O_CREAT, but not O_EXCL. Previously we went into a loop trying first ~(O_CREAT|O_EXCL), and if that returned ENOENT try (O_CREAT|O_EXCL). We kept looping indefinately until we got an error, or the file was created or opened. The big problem here is dangling symlinks. Opening without O_NOFOLLOW means both bad symlink and missing path return -1, ENOENT from open(). As POSIX is pathname based it's not possible to tell the difference between these two cases in a non-racy way, so change to try only two attempts before giving up. We don't have this problem for the O_NOFOLLOW case as we just return NT_STATUS_OBJECT_PATH_NOT_FOUND mapped from the ELOOP POSIX error and immediately returned. Unroll the loop logic to two tries instead. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12572 Pair-programmed-with: Ralph Boehme <s...@samba.org> Signed-off-by: Jeremy Allison <j...@samba.org> Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Ralph Boehme <s...@samba.org> (cherry picked from commit 10c3e3923022485c720f322ca4f0aca5d7501310) commit fe31f48ace127d546ad24d749106536e15c5ed01 Author: Andreas Schneider <a...@samba.org> Date: Thu Feb 9 15:05:01 2017 +0100 s3-vfs: Only walk the directory once in open_and_sort_dir() On a slow filesystem or network filesystem this can make a huge difference. BUG: https://bugzilla.samba.org/show_bug.cgi?id=12571 Signed-off-by: Andreas Schneider <a...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> (cherry picked from commit 6c3aaccd0eb648e31fd2717aaca0187966e125d5) commit 8f6033961fe3af0a7cd6f39ab3e300ac96c63043 Author: Ralph Boehme <s...@samba.org> Date: Tue Jan 31 16:09:55 2017 +0100 s3/rpc_server/mdssvc: add attribute "kMDItemContentType" Bug: https://bugzilla.samba.org/show_bug.cgi?id=12545 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Wed Feb 15 06:20:52 CET 2017 on sn-devel-144 (cherry picked from commit e08110ece699eeb1b9ef688c92bf84c69a6fa5fc) commit 12dc552481f1be73df2309e38911672f78e62bce Author: Ralph Boehme <s...@samba.org> Date: Mon Jan 23 16:19:06 2017 +0100 s3/smbd: check for invalid access_mask smbd_calculate_access_mask() This makes us pass "base.createx_access". Bug: https://bugzilla.samba.org/show_bug.cgi?id=12536 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> (cherry picked from commit 326765923f1d384e5cd8b7fda048b459c67a4bf5) commit 7da247346d519c6673b14db3a6d53018378b2e46 Author: Ralph Boehme <s...@samba.org> Date: Mon Jan 23 17:35:51 2017 +0100 selftest: also run test base.createx_access against ad_dc Fails currently, will be made to work in the next commit. Bug: https://bugzilla.samba.org/show_bug.cgi?id=12536 Signed-off-by: Ralph Boehme <s...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> (cherry picked from commit a3781d1cfe7d5e7df20fc65a9a7653937f03808c) ----------------------------------------------------------------------- Summary of changes: ctdb/common/comm.c | 46 ++++- ctdb/config/statd-callout | 1 + ctdb/tests/cunit/comm_test_001.sh | 10 +- ctdb/tests/src/comm_test.c | 309 +++++++++++++++++++++++++---- selftest/skip | 1 + source3/modules/vfs_dirsort.c | 63 +++--- source3/rpc_server/mdssvc/sparql_mapping.c | 5 + source3/selftest/tests.py | 6 +- source3/smbd/open.c | 110 +++++----- source3/torture/torture.c | 101 ++++++++++ 10 files changed, 536 insertions(+), 116 deletions(-) Changeset truncated at 500 lines: diff --git a/ctdb/common/comm.c b/ctdb/common/comm.c index 7f370da..12f4970 100644 --- a/ctdb/common/comm.c +++ b/ctdb/common/comm.c @@ -251,14 +251,22 @@ static void comm_read_failed(struct tevent_req *req) * Write packets */ +struct comm_write_entry { + struct comm_context *comm; + struct tevent_queue_entry *qentry; + struct tevent_req *req; +}; + struct comm_write_state { struct tevent_context *ev; struct comm_context *comm; + struct comm_write_entry *entry; struct tevent_req *subreq; uint8_t *buf; size_t buflen, nwritten; }; +static int comm_write_entry_destructor(struct comm_write_entry *entry); static void comm_write_trigger(struct tevent_req *req, void *private_data); static void comm_write_done(struct tevent_req *subreq); @@ -269,6 +277,7 @@ struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; struct comm_write_state *state; + struct comm_write_entry *entry; req = tevent_req_create(mem_ctx, &state, struct comm_write_state); if (req == NULL) { @@ -280,15 +289,38 @@ struct tevent_req *comm_write_send(TALLOC_CTX *mem_ctx, state->buf = buf; state->buflen = buflen; - if (!tevent_queue_add_entry(comm->queue, ev, req, - comm_write_trigger, NULL)) { - talloc_free(req); - return NULL; + entry = talloc_zero(state, struct comm_write_entry); + if (tevent_req_nomem(entry, req)) { + return tevent_req_post(req, ev); } + entry->comm = comm; + entry->req = req; + entry->qentry = tevent_queue_add_entry(comm->queue, ev, req, + comm_write_trigger, NULL); + if (tevent_req_nomem(entry->qentry, req)) { + return tevent_req_post(req, ev); + } + + state->entry = entry; + talloc_set_destructor(entry, comm_write_entry_destructor); + return req; } +static int comm_write_entry_destructor(struct comm_write_entry *entry) +{ + struct comm_context *comm = entry->comm; + + if (comm->write_req == entry->req) { + comm->write_req = NULL; + TEVENT_FD_NOT_WRITEABLE(comm->fde); + } + + TALLOC_FREE(entry->qentry); + return 0; +} + static void comm_write_trigger(struct tevent_req *req, void *private_data) { struct comm_write_state *state = tevent_req_data( @@ -333,6 +365,8 @@ static void comm_write_done(struct tevent_req *subreq) } state->nwritten = nwritten; + state->entry->qentry = NULL; + TALLOC_FREE(state->entry); tevent_req_done(req); } @@ -382,8 +416,8 @@ static void comm_fd_handler(struct tevent_context *ev, struct comm_write_state *write_state; if (comm->write_req == NULL) { - /* This should never happen */ - abort(); + TEVENT_FD_NOT_WRITEABLE(comm->fde); + return; } write_state = tevent_req_data(comm->write_req, diff --git a/ctdb/config/statd-callout b/ctdb/config/statd-callout index 3f2dd39..38f847b 100755 --- a/ctdb/config/statd-callout +++ b/ctdb/config/statd-callout @@ -128,6 +128,7 @@ case "$1" in # where the lock manager will respond "strangely" immediately # after restarting it, which causes clients to fail to reclaim # their locks. + nfs_callout_init "$CTDB_NFS_CALLOUT" "stop" "nlockmgr" >/dev/null 2>&1 sleep 2 "$CTDB_NFS_CALLOUT" "start" "nlockmgr" >/dev/null 2>&1 diff --git a/ctdb/tests/cunit/comm_test_001.sh b/ctdb/tests/cunit/comm_test_001.sh index 5d20db2..ac09f5c 100755 --- a/ctdb/tests/cunit/comm_test_001.sh +++ b/ctdb/tests/cunit/comm_test_001.sh @@ -2,6 +2,12 @@ . "${TEST_SCRIPTS_DIR}/unit.sh" -ok "100 2048 500 4096 1024 8192 200 16384 300 32768 400 65536 1048576 " -unit_test comm_test +ok_null +unit_test comm_test 1 + +ok_null +unit_test comm_test 2 + +ok "100 2048 500 4096 1024 8192 200 16384 300 32768 400 65536 1048576 " +unit_test comm_test 3 diff --git a/ctdb/tests/src/comm_test.c b/ctdb/tests/src/comm_test.c index 2189435..5e1d694 100644 --- a/ctdb/tests/src/comm_test.c +++ b/ctdb/tests/src/comm_test.c @@ -26,7 +26,218 @@ #include "common/pkt_write.c" #include "common/comm.c" -static void dead_handler(void *private_data) +/* + * Test read_handler and dead_handler + */ + +static void test1_read_handler(uint8_t *buf, size_t buflen, + void *private_data) +{ + int *result = (int *)private_data; + + *result = -1; +} + +static void test1_dead_handler(void *private_data) +{ + int *result = (int *)private_data; + + *result = 1; +} + +static void test1(void) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct comm_context *comm; + int fd[2]; + int result = 0; + uint32_t data[2]; + int ret; + ssize_t n; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + ret = pipe(fd); + assert(ret == 0); + + ret = comm_setup(ev, ev, fd[0], test1_read_handler, &result, + test1_dead_handler, &result, &comm); + assert(ret == 0); + + data[0] = 2 * sizeof(uint32_t); + data[1] = 0; + + n = write(fd[1], (void *)&data, data[0]); + assert(n == data[0]); + + while (result == 0) { + tevent_loop_once(ev); + } + + assert(result == -1); + + result = 0; + close(fd[1]); + + while (result == 0) { + tevent_loop_once(ev); + } + + assert(result == 1); + + talloc_free(mem_ctx); +} + +/* + * Test that the tevent_req returned by comm_write_send() can be free'd. + */ + +struct test2_state { + TALLOC_CTX *mem_ctx; + bool done; +}; + +static void test2_read_handler(uint8_t *buf, size_t buflen, + void *private_data) +{ + struct test2_state *state = (struct test2_state *)private_data; + + TALLOC_FREE(state->mem_ctx); +} + +static void test2_dead_handler(void *private_data) +{ + abort(); +} + +struct test2_write_state { + int count; +}; + +static void test2_write_done(struct tevent_req *subreq); + +static struct tevent_req *test2_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + uint8_t *buf, size_t buflen) +{ + struct tevent_req *req, *subreq; + struct test2_write_state *state; + int i; + + req = tevent_req_create(mem_ctx, &state, struct test2_write_state); + if (req == NULL) { + return NULL; + } + + state->count = 0; + + for (i=0; i<10; i++) { + subreq = comm_write_send(state, ev, comm, buf, buflen); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, test2_write_done, req); + } + + return req; +} + +static void test2_write_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct test2_write_state *state = tevent_req_data( + req, struct test2_write_state); + bool status; + int ret; + + status = comm_write_recv(subreq, &ret); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; + } + + state->count += 1; + + if (state->count == 10) { + tevent_req_done(req); + } +} + +static void test2_timer_handler(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval cur_time, + void *private_data) +{ + struct test2_state *state = (struct test2_state *)private_data; + + state->done = true; +} + +static void test2(void) +{ + TALLOC_CTX *mem_ctx; + struct tevent_context *ev; + struct comm_context *comm_reader, *comm_writer; + struct test2_state test2_state; + struct tevent_req *req; + struct tevent_timer *te; + int fd[2]; + uint32_t data[2]; + int ret; + + mem_ctx = talloc_new(NULL); + assert(mem_ctx != NULL); + + test2_state.mem_ctx = talloc_new(mem_ctx); + assert(test2_state.mem_ctx != NULL); + + test2_state.done = false; + + ev = tevent_context_init(mem_ctx); + assert(ev != NULL); + + ret = pipe(fd); + assert(ret == 0); + + ret = comm_setup(ev, ev, fd[0], test2_read_handler, &test2_state, + test2_dead_handler, NULL, &comm_reader); + assert(ret == 0); + + ret = comm_setup(ev, ev, fd[1], NULL, NULL, test2_dead_handler, NULL, + &comm_writer); + assert(ret == 0); + + data[0] = 2 * sizeof(uint32_t); + data[1] = 0; + + req = test2_write_send(test2_state.mem_ctx, ev, comm_writer, + (uint8_t *)data, data[0]); + assert(req != NULL); + + te = tevent_add_timer(ev, ev, tevent_timeval_current_ofs(5,0), + test2_timer_handler, &test2_state); + assert(te != NULL); + + while (! test2_state.done) { + tevent_loop_once(ev); + } + + talloc_free(mem_ctx); +} + +/* + * Test that data is written and read correctly. + */ + +static void test3_dead_handler(void *private_data) { int dead_data = *(int *)private_data; @@ -34,14 +245,14 @@ static void dead_handler(void *private_data) if (dead_data == 1) { /* reader */ - printf("writer closed pipe\n"); + fprintf(stderr, "writer closed pipe\n"); } else { /* writer */ - printf("reader closed pipe\n"); + fprintf(stderr, "reader closed pipe\n"); } } -struct writer_state { +struct test3_writer_state { struct tevent_context *ev; struct comm_context *comm; uint8_t *buf; @@ -49,15 +260,15 @@ struct writer_state { int count, id; }; -static void writer_next(struct tevent_req *subreq); +static void test3_writer_next(struct tevent_req *subreq); -static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct comm_context *comm, - size_t *pkt_size, int count) +static struct tevent_req *test3_writer_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct comm_context *comm, + size_t *pkt_size, int count) { struct tevent_req *req, *subreq; - struct writer_state *state; + struct test3_writer_state *state; size_t max_size = 0, buflen; int i; @@ -67,7 +278,7 @@ static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, } } - req = tevent_req_create(mem_ctx, &state, struct writer_state); + req = tevent_req_create(mem_ctx, &state, struct test3_writer_state); if (req == NULL) { return NULL; } @@ -95,16 +306,16 @@ static struct tevent_req *writer_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - tevent_req_set_callback(subreq, writer_next, req); + tevent_req_set_callback(subreq, test3_writer_next, req); return req; } -static void writer_next(struct tevent_req *subreq) +static void test3_writer_next(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); - struct writer_state *state = tevent_req_data( - req, struct writer_state); + struct test3_writer_state *state = tevent_req_data( + req, struct test3_writer_state); bool ret; int err; size_t buflen; @@ -130,10 +341,10 @@ static void writer_next(struct tevent_req *subreq) return; } - tevent_req_set_callback(subreq, writer_next, req); + tevent_req_set_callback(subreq, test3_writer_next, req); } -static void writer_recv(struct tevent_req *req, int *perr) +static void test3_writer_recv(struct tevent_req *req, int *perr) { if (tevent_req_is_unix_error(req, perr)) { return; @@ -141,7 +352,7 @@ static void writer_recv(struct tevent_req *req, int *perr) *perr = 0; } -static void writer(int fd, size_t *pkt_size, int count) +static void test3_writer(int fd, size_t *pkt_size, int count) { TALLOC_CTX *mem_ctx; struct tevent_context *ev; @@ -157,31 +368,32 @@ static void writer(int fd, size_t *pkt_size, int count) assert(ev != NULL); err = comm_setup(mem_ctx, ev, fd, NULL, NULL, - dead_handler, &dead_data, &comm); + test3_dead_handler, &dead_data, &comm); assert(err == 0); assert(comm != NULL); - req = writer_send(mem_ctx, ev, comm, pkt_size, count); + req = test3_writer_send(mem_ctx, ev, comm, pkt_size, count); assert(req != NULL); tevent_req_poll(req, ev); - writer_recv(req, &err); + test3_writer_recv(req, &err); assert(err == 0); talloc_free(mem_ctx); } -struct reader_state { +struct test3_reader_state { size_t *pkt_size; int count, received; bool done; }; -static void reader_handler(uint8_t *buf, size_t buflen, void *private_data) +static void test3_reader_handler(uint8_t *buf, size_t buflen, + void *private_data) { - struct reader_state *state = talloc_get_type_abort( - private_data, struct reader_state); + struct test3_reader_state *state = talloc_get_type_abort( + private_data, struct test3_reader_state); assert(buflen == state->pkt_size[state->received]); printf("%zi ", buflen); @@ -193,12 +405,12 @@ static void reader_handler(uint8_t *buf, size_t buflen, void *private_data) } } -static void reader(int fd, size_t *pkt_size, int count) +static void test3_reader(int fd, size_t *pkt_size, int count) { TALLOC_CTX *mem_ctx; struct tevent_context *ev; struct comm_context *comm; - struct reader_state *state; + struct test3_reader_state *state; int dead_data = 1; int err; -- Samba Shared Repository