The branch, master has been updated via 6f51a1f talloc: fixed a use after free error via 66db49e talloc: added a test for the use after free Rusty found from 26c8a52 upgradeprovision: Fix use of dict.get().
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 6f51a1f45bf4de062cce7a562477e8140630a53d Author: Andrew Tridgell <tri...@samba.org> Date: Wed Jan 5 16:33:13 2011 +1100 talloc: fixed a use after free error this is the minimal fix for the problem Rusty found. I previously thought that the best fix would be to change tc->parent to be valid for all pointers, but that is expensive for realloc with large numbers of child pointers, which is much more commmon than I expected it to be. Autobuild-User: Andrew Tridgell <tri...@samba.org> Autobuild-Date: Wed Jan 5 07:22:27 CET 2011 on sn-devel-104 commit 66db49e35f87f0e0a9d82cfa661d2cc604758406 Author: Andrew Tridgell <tri...@samba.org> Date: Wed Dec 22 15:29:37 2010 +1100 talloc: added a test for the use after free Rusty found ----------------------------------------------------------------------- Summary of changes: lib/talloc/talloc.c | 17 ++++++++++++++++- lib/talloc/testsuite.c | 17 +++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletions(-) Changeset truncated at 500 lines: diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c index d6115af..c616f34 100644 --- a/lib/talloc/talloc.c +++ b/lib/talloc/talloc.c @@ -645,13 +645,28 @@ static inline int _talloc_free_internal(void *ptr, const char *location) final choice is the null context. */ void *child = TC_PTR_FROM_CHUNK(tc->child); const void *new_parent = null_context; + struct talloc_chunk *old_parent = NULL; if (unlikely(tc->child->refs)) { struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); if (p) new_parent = TC_PTR_FROM_CHUNK(p); } + /* finding the parent here is potentially quite + expensive, but the alternative, which is to change + talloc to always have a valid tc->parent pointer, + makes realloc more expensive where there are a + large number of children. + + The reason we need the parent pointer here is that + if _talloc_free_internal() fails due to references + or a failing destructor we need to re-parent, but + the free call can invalidate the prev pointer. + */ + if (new_parent == null_context && (tc->child->refs || tc->child->destructor)) { + old_parent = talloc_parent_chunk(ptr); + } if (unlikely(_talloc_free_internal(child, location) == -1)) { if (new_parent == null_context) { - struct talloc_chunk *p = talloc_parent_chunk(ptr); + struct talloc_chunk *p = old_parent; if (p) new_parent = TC_PTR_FROM_CHUNK(p); } _talloc_steal_internal(new_parent, child); diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index 0026931..ee6256b 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -1167,6 +1167,21 @@ static bool test_free_ref_null_context(void) return true; } +static bool test_rusty(void) +{ + void *root; + const char *p1; + + talloc_enable_null_tracking(); + root = talloc_new(NULL); + p1 = talloc_strdup(root, "foo"); + talloc_increase_ref_count(p1); + talloc_report_full(root, stdout); + talloc_free(root); + return true; +} + + static void test_reset(void) { talloc_set_log_fn(test_log_stdout); @@ -1221,6 +1236,8 @@ bool torture_local_talloc(struct torture_context *tctx) ret &= test_pool(); test_reset(); ret &= test_free_ref_null_context(); + test_reset(); + ret &= test_rusty(); if (ret) { test_reset(); -- Samba Shared Repository