diff --git a/.gitignore b/.gitignore index 4115b2d..7e13c2f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/tdb-1.3.8.tar.gz +SOURCES/tdb-1.3.12.tar.gz diff --git a/.libtdb.metadata b/.libtdb.metadata index b7b6ff6..ffea0e7 100644 --- a/.libtdb.metadata +++ b/.libtdb.metadata @@ -1 +1 @@ -3ac6779e14ed37caa27d5243777a2c7c485ef087 SOURCES/tdb-1.3.8.tar.gz +86fec2b5e698ef15da07be4a26672773575e37cd SOURCES/tdb-1.3.12.tar.gz diff --git a/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch b/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch new file mode 100644 index 0000000..afa0bbb --- /dev/null +++ b/SOURCES/0001-waf-disable-python-align-tdb-s-wscript.patch @@ -0,0 +1,52 @@ +From 81ff0f306523079396e8538d5cbff7e9f008f062 Mon Sep 17 00:00:00 2001 +From: Ian Stakenvicius +Date: Fri, 27 Jan 2017 14:42:05 -0500 +Subject: [PATCH] waf: disable-python - align tdb's wscript + +Drop the configure option for --disable-python as it is now +global in wafsamba. + +If samba is set to use a system copy of tdb, and tdb wasn't built +with python support, then the system pytevent will not be found. If +samba is being built without python support then pytdb is not needed, +so do not bother to try and find it. + +Signed-off-by: Ian Stakenvicius +Reviewed-by: Andrew Bartlett +Reviewed-by: Douglas Bagnall +--- + lib/tdb/wscript | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/lib/tdb/wscript b/lib/tdb/wscript +index 34058e4c9fa5889c627a89c2e1a1731390555f84..0d682ebb4cdaa001904e0b40e50e1a2e46f230ee 100644 +--- a/lib/tdb/wscript ++++ b/lib/tdb/wscript +@@ -60,10 +60,6 @@ def set_options(opt): + help=("Disable the use of pthread robust mutexes"), + action="store_true", dest='disable_tdb_mutex_locking', + default=False) +- if opt.IN_LAUNCH_DIR(): +- opt.add_option('--disable-python', +- help=("disable the pytdb module"), +- action="store_true", dest='disable_python', default=False) + + + def configure(conf): +@@ -82,11 +78,10 @@ def configure(conf): + implied_deps='replace'): + conf.define('USING_SYSTEM_TDB', 1) + conf.env.building_tdb = False +- if conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION): ++ if not conf.env.disable_python and \ ++ conf.CHECK_BUNDLED_SYSTEM_PYTHON('pytdb', 'tdb', minversion=VERSION): + conf.define('USING_SYSTEM_PYTDB', 1) + +- conf.env.disable_python = getattr(Options.options, 'disable_python', False) +- + if (conf.CONFIG_SET('HAVE_ROBUST_MUTEXES') and + conf.env.building_tdb and + not conf.env.disable_tdb_mutex_locking): +-- +2.9.3 + diff --git a/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch b/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch new file mode 100644 index 0000000..886de64 --- /dev/null +++ b/SOURCES/0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch @@ -0,0 +1,43 @@ +From 0558715b5b125ffa7948f06451ea979c7045b20c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= +Date: Mon, 27 Mar 2017 17:43:07 +0200 +Subject: [PATCH] tdb/tools: add documentation for the tdbbackup -n option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Björn Baumbach +Reviewed-by: Jeremy Allison -s suffix + -v + -h ++ -n hashsize + -l + + +@@ -71,6 +72,13 @@ + + + ++ -n hashsize ++ ++ The -n option sets the hash size for the new backup tdb. ++ ++ ++ ++ + -l + + This options disables any locking, by passing TDB_NOLOCK +-- +2.9.3 + diff --git a/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch b/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch new file mode 100644 index 0000000..4c11b8a --- /dev/null +++ b/SOURCES/0003-tdb-Fix-some-signed-unsigned-hickups.patch @@ -0,0 +1,65 @@ +From 97cafdcfaaaff17ebffe873b5e31462f0d1268b1 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Mon, 7 Nov 2016 21:38:58 +0100 +Subject: [PATCH] tdb: Fix some signed/unsigned hickups + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison +--- + lib/tdb/common/lock.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c +index 195dbb5daf265c8d8f997a3ccdd81fe7b642945c..594c28751f1d68c8305bd225f228c437fee81c9e 100644 +--- a/lib/tdb/common/lock.c ++++ b/lib/tdb/common/lock.c +@@ -294,7 +294,7 @@ fail: + static struct tdb_lock_type *find_nestlock(struct tdb_context *tdb, + tdb_off_t offset) + { +- unsigned int i; ++ int i; + + for (i=0; inum_lockrecs; i++) { + if (tdb->lockrecs[i].off == offset) { +@@ -381,7 +381,7 @@ static int tdb_lock_and_recover(struct tdb_context *tdb) + + static bool have_data_locks(const struct tdb_context *tdb) + { +- unsigned int i; ++ int i; + + for (i = 0; i < tdb->num_lockrecs; i++) { + if (tdb->lockrecs[i].off >= lock_offset(-1)) +@@ -560,7 +560,8 @@ static int tdb_allrecord_check(struct tdb_context *tdb, int ltype, + return -1; + } + +- if (tdb->allrecord_lock.count && tdb->allrecord_lock.ltype == ltype) { ++ if (tdb->allrecord_lock.count && ++ tdb->allrecord_lock.ltype == (uint32_t)ltype) { + tdb->allrecord_lock.count++; + return 0; + } +@@ -706,7 +707,7 @@ int tdb_allrecord_unlock(struct tdb_context *tdb, int ltype, bool mark_lock) + } + + /* Upgradable locks are marked as write locks. */ +- if (tdb->allrecord_lock.ltype != ltype ++ if (tdb->allrecord_lock.ltype != (uint32_t)ltype + && (!tdb->allrecord_lock.off || ltype != F_RDLCK)) { + tdb->ecode = TDB_ERR_LOCK; + return -1; +@@ -945,7 +946,8 @@ bool tdb_have_extra_locks(struct tdb_context *tdb) + /* The transaction code uses this to remove all locks. */ + void tdb_release_transaction_locks(struct tdb_context *tdb) + { +- unsigned int i, active = 0; ++ int i; ++ unsigned int active = 0; + + if (tdb->allrecord_lock.count != 0) { + tdb_allrecord_unlock(tdb, tdb->allrecord_lock.ltype, false); +-- +2.9.3 + diff --git a/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch b/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch new file mode 100644 index 0000000..4a6e146 --- /dev/null +++ b/SOURCES/0004-tdb-Do-lock-upgrades-properly.patch @@ -0,0 +1,47 @@ +From a6f1532d7fedc6b6f36b511aebe8998e9452b7ff Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Mon, 7 Nov 2016 21:40:15 +0100 +Subject: [PATCH] tdb: Do lock upgrades properly + +When a process holds a readlock and wants to upgrade, this needs to be +reflected in the underlying lock. Without this, it is possible to cheat: +One process holds a readlock, and another process wants to write this +record. All the writer has to do is take a readonly lock on the key and +then do the store. + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison +--- + lib/tdb/common/lock.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c +index 594c28751f1d68c8305bd225f228c437fee81c9e..4ad70cff3fe639abb781b204aa86a437e4a7adfe 100644 +--- a/lib/tdb/common/lock.c ++++ b/lib/tdb/common/lock.c +@@ -321,6 +321,22 @@ int tdb_nest_lock(struct tdb_context *tdb, uint32_t offset, int ltype, + + new_lck = find_nestlock(tdb, offset); + if (new_lck) { ++ if ((new_lck->ltype == F_RDLCK) && (ltype == F_WRLCK)) { ++ if (!tdb_have_mutexes(tdb)) { ++ int ret; ++ /* ++ * Upgrade the underlying fcntl ++ * lock. Mutexes don't do readlocks, ++ * so this only applies to fcntl ++ * locking. ++ */ ++ ret = tdb_brlock(tdb, ltype, offset, 1, flags); ++ if (ret != 0) { ++ return ret; ++ } ++ } ++ new_lck->ltype = F_WRLCK; ++ } + /* + * Just increment the in-memory struct, posix locks + * don't stack. +-- +2.9.3 + diff --git a/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch b/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch new file mode 100644 index 0000000..edffe8e --- /dev/null +++ b/SOURCES/0005-tdb-Test-for-readonly-lock-upgrade-bug.patch @@ -0,0 +1,203 @@ +From 397d1936ec34fa573c7d46cc51c971986e8f7fe8 Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Tue, 8 Nov 2016 17:01:56 +0100 +Subject: [PATCH] tdb: Test for readonly lock upgrade bug + +Signed-off-by: Volker Lendecke +Reviewed-by: Jeremy Allison + +Autobuild-User(master): Jeremy Allison +Autobuild-Date(master): Tue Apr 11 00:33:31 CEST 2017 on sn-devel-144 +--- + lib/tdb/test/run-rdlock-upgrade.c | 166 ++++++++++++++++++++++++++++++++++++++ + lib/tdb/wscript | 1 + + 2 files changed, 167 insertions(+) + create mode 100644 lib/tdb/test/run-rdlock-upgrade.c + +diff --git a/lib/tdb/test/run-rdlock-upgrade.c b/lib/tdb/test/run-rdlock-upgrade.c +new file mode 100644 +index 0000000000000000000000000000000000000000..042001b4231530e93618f481d3fbeef4ecfd309b +--- /dev/null ++++ b/lib/tdb/test/run-rdlock-upgrade.c +@@ -0,0 +1,166 @@ ++#include "../common/io.c" ++#include "../common/tdb.c" ++#include "../common/lock.c" ++#include "../common/freelist.c" ++#include "../common/traverse.c" ++#include "../common/transaction.c" ++#include "../common/error.c" ++#include "../common/open.c" ++#include "../common/check.c" ++#include "../common/hash.c" ++#include "../common/mutex.c" ++#include "tap-interface.h" ++#include ++#include ++#include ++#include ++#include "logging.h" ++ ++static TDB_DATA key, data; ++ ++static void do_chainlock(const char *name, int tdb_flags, int up, int down) ++{ ++ struct tdb_context *tdb; ++ int ret; ++ ssize_t nread, nwritten; ++ char c = 0; ++ ++ tdb = tdb_open_ex(name, 3, tdb_flags, ++ O_RDWR|O_CREAT, 0755, &taplogctx, NULL); ++ ok(tdb, "tdb_open_ex should succeed"); ++ ++ ret = tdb_chainlock_read(tdb, key); ++ ok(ret == 0, "tdb_chainlock_read should succeed"); ++ ++ nwritten = write(up, &c, sizeof(c)); ++ ok(nwritten == sizeof(c), "write should succeed"); ++ ++ nread = read(down, &c, sizeof(c)); ++ ok(nread == 0, "read should succeed"); ++ ++ exit(0); ++} ++ ++static void do_trylock(const char *name, int tdb_flags, int up, int down) ++{ ++ struct tdb_context *tdb; ++ int ret; ++ ssize_t nread, nwritten; ++ char c = 0; ++ ++ tdb = tdb_open_ex(name, 3, tdb_flags, ++ O_RDWR|O_CREAT, 0755, &taplogctx, NULL); ++ ok(tdb, "tdb_open_ex should succeed"); ++ ++ /* ++ * tdb used to have a bug where with fcntl locks an upgrade ++ * from a readlock to writelock did not check for the ++ * underlying fcntl lock. Mutexes don't distinguish between ++ * readlocks and writelocks, so that bug does not apply here. ++ */ ++ ++ ret = tdb_chainlock_read(tdb, key); ++ ok(ret == 0, "tdb_chainlock_read should succeed"); ++ ++ ret = tdb_chainlock_nonblock(tdb, key); ++ ok(ret == -1, "tdb_chainlock_nonblock should fail"); ++ ++ nwritten = write(up, &c, sizeof(c)); ++ ok(nwritten == sizeof(c), "write should succeed"); ++ ++ nread = read(down, &c, sizeof(c)); ++ ok(nread == 0, "read should succeed"); ++ ++ exit(0); ++} ++ ++static int do_tests(const char *name, int tdb_flags) ++{ ++ int ret; ++ pid_t chainlock_child, store_child; ++ int chainlock_down[2]; ++ int chainlock_up[2]; ++ int store_down[2]; ++ int store_up[2]; ++ char c; ++ ssize_t nread; ++ ++ key.dsize = strlen("hi"); ++ key.dptr = discard_const_p(uint8_t, "hi"); ++ data.dsize = strlen("world"); ++ data.dptr = discard_const_p(uint8_t, "world"); ++ ++ ret = pipe(chainlock_down); ++ ok(ret == 0, "pipe should succeed"); ++ ++ ret = pipe(chainlock_up); ++ ok(ret == 0, "pipe should succeed"); ++ ++ ret = pipe(store_down); ++ ok(ret == 0, "pipe should succeed"); ++ ++ ret = pipe(store_up); ++ ok(ret == 0, "pipe should succeed"); ++ ++ chainlock_child = fork(); ++ ok(chainlock_child != -1, "fork should succeed"); ++ ++ if (chainlock_child == 0) { ++ close(chainlock_up[0]); ++ close(chainlock_down[1]); ++ close(store_up[0]); ++ close(store_up[1]); ++ close(store_down[0]); ++ close(store_down[1]); ++ do_chainlock(name, tdb_flags, ++ chainlock_up[1], chainlock_down[0]); ++ exit(0); ++ } ++ close(chainlock_up[1]); ++ close(chainlock_down[0]); ++ ++ nread = read(chainlock_up[0], &c, sizeof(c)); ++ ok(nread == sizeof(c), "read should succeed"); ++ ++ /* ++ * Now we have a process holding a chain read lock. Start ++ * another process trying to write lock. This should fail. ++ */ ++ ++ store_child = fork(); ++ ok(store_child != -1, "fork should succeed"); ++ ++ if (store_child == 0) { ++ close(chainlock_up[0]); ++ close(chainlock_down[1]); ++ close(store_up[0]); ++ close(store_down[1]); ++ do_trylock(name, tdb_flags, ++ store_up[1], store_down[0]); ++ exit(0); ++ } ++ close(store_up[1]); ++ close(store_down[0]); ++ ++ nread = read(store_up[0], &c, sizeof(c)); ++ ok(nread == sizeof(c), "read should succeed"); ++ ++ close(chainlock_up[0]); ++ close(chainlock_down[1]); ++ close(store_up[0]); ++ close(store_down[1]); ++ diag("%s tests done", name); ++ return exit_status(); ++} ++ ++int main(int argc, char *argv[]) ++{ ++ int ret; ++ ++ ret = do_tests("rdlock-upgrade.tdb", ++ TDB_CLEAR_IF_FIRST | ++ TDB_INCOMPATIBLE_HASH); ++ ok(ret == 0, "rdlock-upgrade.tdb tests should succeed"); ++ ++ return exit_status(); ++} +diff --git a/lib/tdb/wscript b/lib/tdb/wscript +index 0d682ebb4cdaa001904e0b40e50e1a2e46f230ee..693787cb75da6462a81dcae6fba8981b99e90e69 100644 +--- a/lib/tdb/wscript ++++ b/lib/tdb/wscript +@@ -34,6 +34,7 @@ tdb1_unit_tests = [ + 'run-readonly-check', + 'run-rescue', + 'run-rescue-find_entry', ++ 'run-rdlock-upgrade', + 'run-rwlock-check', + 'run-summary', + 'run-transaction-expand', +-- +2.9.3 + diff --git a/SOURCES/0006-tdbtool-Add-storehex-command.patch b/SOURCES/0006-tdbtool-Add-storehex-command.patch new file mode 100644 index 0000000..8c99b83 --- /dev/null +++ b/SOURCES/0006-tdbtool-Add-storehex-command.patch @@ -0,0 +1,168 @@ +From 5d288a9b1705b75e7e8dcf93a93b7fd6715ad5ef Mon Sep 17 00:00:00 2001 +From: Volker Lendecke +Date: Fri, 21 Apr 2017 14:10:33 +0200 +Subject: [PATCH] tdbtool: Add "storehex" command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Volker Lendecke +Reviewed-by: Ralph Böhme + +Autobuild-User(master): Jeremy Allison +Autobuild-Date(master): Sat Apr 22 09:16:16 CEST 2017 on sn-devel-144 +--- + lib/tdb/man/tdbtool.8.xml | 10 ++++++ + lib/tdb/tools/tdbtool.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 97 insertions(+) + +diff --git a/lib/tdb/man/tdbtool.8.xml b/lib/tdb/man/tdbtool.8.xml +index 9a9b95e6a0621dc3c880c154d28c972ea02be401..045cbde73dd7d88c36a77c8ed35d49e69bf17554 100644 +--- a/lib/tdb/man/tdbtool.8.xml ++++ b/lib/tdb/man/tdbtool.8.xml +@@ -160,6 +160,16 @@ + + + ++ ++ KEY ++ DATA ++ ++ Store (replace) a record in the ++ current database where key and data are in hex format. ++ ++ ++ ++ + + KEY + +diff --git a/lib/tdb/tools/tdbtool.c b/lib/tdb/tools/tdbtool.c +index beb3af18e23051586991bbd101fa6a5d2fa8103d..e3535b93c7c4296a9b4f9d3b9797841f762062cd 100644 +--- a/lib/tdb/tools/tdbtool.c ++++ b/lib/tdb/tools/tdbtool.c +@@ -48,6 +48,7 @@ enum commands { + CMD_DUMP, + CMD_INSERT, + CMD_MOVE, ++ CMD_STOREHEX, + CMD_STORE, + CMD_SHOW, + CMD_KEYS, +@@ -83,6 +84,7 @@ COMMAND_TABLE cmd_table[] = { + {"dump", CMD_DUMP}, + {"insert", CMD_INSERT}, + {"move", CMD_MOVE}, ++ {"storehex", CMD_STOREHEX}, + {"store", CMD_STORE}, + {"show", CMD_SHOW}, + {"keys", CMD_KEYS}, +@@ -229,6 +231,7 @@ static void help(void) + " info : print summary info about the database\n" + " insert key data : insert a record\n" + " move key file : move a record to a destination tdb\n" ++" storehex key data : store a record (replace), key/value in hex format\n" + " store key data : store a record (replace)\n" + " show key : show a record by key\n" + " delete key : delete a record by key\n" +@@ -346,6 +349,86 @@ static void store_tdb(char *keyname, size_t keylen, char* data, size_t datalen) + } + } + ++static bool hexchar(char c, uint8_t *v) ++{ ++ if ((c >= '0') && (c <= '9')) { ++ *v = (c - '0'); ++ return true; ++ } ++ if ((c >= 'A') && (c <= 'F')) { ++ *v = (c - 'A' + 10); ++ return true; ++ } ++ if ((c >= 'a') && (c <= 'f')) { ++ *v = (c - 'a' + 10); ++ return true; ++ } ++ return false; ++} ++ ++static bool parse_hex(const char *src, size_t srclen, uint8_t *dst) ++{ ++ size_t i=0; ++ ++ if ((srclen % 2) != 0) { ++ return false; ++ } ++ ++ while (i +Date: Tue, 14 Mar 2017 14:24:18 +0100 +Subject: [PATCH] tdb: runtime check for robust mutexes may hang in threaded + programs + +The current runtime check for robust mutexes in +tdb_runtime_check_for_robust_mutexes() is not thread-safe. + +When called in a multi-threaded program where any another thread doesn't +have SIGCHLD blocked, we may end up hung in sigsuspend() waiting for a +SIGCHLD of a child procecss and the signal was delivered to another +thread. + +Revert to the previous behaviour of waiting for the child instead of +waiting for the SIGCHLD signal. + +Ensure the pid we wait for is not reset to -1 in a toctou race with the +signal handler. + +Check whether waitpid() returns ECHILD which can happen if the signal +handler is run by more then one thread in parallel (yes, this can +happen) or if tdb_robust_mutex_wait_for_child() and the signal handler +are racing. + +Bug: https://bugzilla.samba.org/show_bug.cgi?id=12593 + +Pair-programmed-with: Stefan Metzmacher + +Signed-off-by: Ralph Boehme +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andreas Schneider +--- + lib/tdb/common/mutex.c | 116 +++++++++++++++++++++++++++++-------------------- + 1 file changed, 70 insertions(+), 46 deletions(-) + +diff --git a/lib/tdb/common/mutex.c b/lib/tdb/common/mutex.c +index cac3916713f2da97694cf8d02f67ab9cf0da3025..8a122d5d6a2ec321bce25cf06062acc808f1e126 100644 +--- a/lib/tdb/common/mutex.c ++++ b/lib/tdb/common/mutex.c +@@ -752,12 +752,23 @@ static bool tdb_robust_mutex_setup_sigchild(void (*handler)(int), + + static void tdb_robust_mutex_handler(int sig) + { +- if (tdb_robust_mutex_pid != -1) { ++ pid_t child_pid = tdb_robust_mutex_pid; ++ ++ if (child_pid != -1) { + pid_t pid; +- int status; + +- pid = waitpid(tdb_robust_mutex_pid, &status, WNOHANG); +- if (pid == tdb_robust_mutex_pid) { ++ pid = waitpid(child_pid, NULL, WNOHANG); ++ if (pid == -1) { ++ switch (errno) { ++ case ECHILD: ++ tdb_robust_mutex_pid = -1; ++ return; ++ ++ default: ++ return; ++ } ++ } ++ if (pid == child_pid) { + tdb_robust_mutex_pid = -1; + return; + } +@@ -776,6 +787,44 @@ static void tdb_robust_mutex_handler(int sig) + tdb_robust_mutext_old_handler(sig); + } + ++static void tdb_robust_mutex_wait_for_child(pid_t *child_pid) ++{ ++ int options = WNOHANG; ++ ++ if (*child_pid == -1) { ++ return; ++ } ++ ++ while (tdb_robust_mutex_pid > 0) { ++ pid_t pid; ++ ++ /* ++ * First we try with WNOHANG, as the process might not exist ++ * anymore. Once we've sent SIGKILL we block waiting for the ++ * exit. ++ */ ++ pid = waitpid(*child_pid, NULL, options); ++ if (pid == -1) { ++ if (errno == EINTR) { ++ continue; ++ } else if (errno == ECHILD) { ++ break; ++ } else { ++ abort(); ++ } ++ } ++ if (pid == *child_pid) { ++ break; ++ } ++ ++ kill(*child_pid, SIGKILL); ++ options = 0; ++ } ++ ++ tdb_robust_mutex_pid = -1; ++ *child_pid = -1; ++} ++ + _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + { + void *ptr = NULL; +@@ -788,9 +837,8 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + char c = 0; + bool ok; + static bool initialized; +- sigset_t mask, old_mask, suspend_mask; ++ pid_t saved_child_pid = -1; + bool cleanup_ma = false; +- bool cleanup_sigmask = false; + + if (initialized) { + return tdb_mutex_locking_cached; +@@ -798,8 +846,6 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + + initialized = true; + +- sigemptyset(&suspend_mask); +- + ok = tdb_mutex_locking_supported(); + if (!ok) { + return false; +@@ -845,26 +891,13 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + } + m = (pthread_mutex_t *)ptr; + +- /* +- * Block SIGCHLD so we can atomically wait for it later with +- * sigsuspend() +- */ +- sigemptyset(&mask); +- sigaddset(&mask, SIGCHLD); +- ret = pthread_sigmask(SIG_BLOCK, &mask, &old_mask); +- if (ret != 0) { +- goto cleanup; +- } +- cleanup_sigmask = true; +- suspend_mask = old_mask; +- sigdelset(&suspend_mask, SIGCHLD); +- + if (tdb_robust_mutex_setup_sigchild(tdb_robust_mutex_handler, + &tdb_robust_mutext_old_handler) == false) { + goto cleanup; + } + + tdb_robust_mutex_pid = fork(); ++ saved_child_pid = tdb_robust_mutex_pid; + if (tdb_robust_mutex_pid == 0) { + size_t nwritten; + close(pipe_down[1]); +@@ -914,14 +947,7 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + goto cleanup; + } + +- while (tdb_robust_mutex_pid > 0) { +- ret = sigsuspend(&suspend_mask); +- if (ret != -1 || errno != EINTR) { +- abort(); +- } +- } +- tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL); +- tdb_robust_mutext_old_handler = SIG_ERR; ++ tdb_robust_mutex_wait_for_child(&saved_child_pid); + + ret = pthread_mutex_trylock(m); + if (ret != EOWNERDEAD) { +@@ -950,23 +976,21 @@ _PUBLIC_ bool tdb_runtime_check_for_robust_mutexes(void) + tdb_mutex_locking_cached = true; + + cleanup: +- while (tdb_robust_mutex_pid > 0) { +- kill(tdb_robust_mutex_pid, SIGKILL); +- ret = sigsuspend(&suspend_mask); +- if (ret != -1 || errno != EINTR) { +- abort(); +- } +- } ++ /* ++ * Note that we don't reset the signal handler we just reset ++ * tdb_robust_mutex_pid to -1. This is ok as this code path is only ++ * called once per process. ++ * ++ * Leaving our signal handler avoids races with other threads potentialy ++ * setting up their SIGCHLD handlers. ++ * ++ * The worst thing that can happen is that the other newer signal ++ * handler will get the SIGCHLD signal for our child and/or reap the ++ * child with a wait() function. tdb_robust_mutex_wait_for_child() ++ * handles the case where waitpid returns ECHILD. ++ */ ++ tdb_robust_mutex_wait_for_child(&saved_child_pid); + +- if (tdb_robust_mutext_old_handler != SIG_ERR) { +- tdb_robust_mutex_setup_sigchild(tdb_robust_mutext_old_handler, NULL); +- } +- if (cleanup_sigmask) { +- ret = pthread_sigmask(SIG_SETMASK, &old_mask, NULL); +- if (ret != 0) { +- abort(); +- } +- } + if (m != NULL) { + pthread_mutex_destroy(m); + } +-- +2.9.3 + diff --git a/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch b/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch new file mode 100644 index 0000000..8dc1da6 --- /dev/null +++ b/SOURCES/0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch @@ -0,0 +1,54 @@ +From 1148e8f0408b62b0417daf8e2727cdaf7cffed09 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Thu, 30 Mar 2017 19:11:06 +1300 +Subject: [PATCH] tdb: Improve debugging when the allrecord lock fails to + upgrade + +Pair-Programmed-With: Stefan Metzmacher + +Signed-off-by: Andrew Bartlett +Signed-off-by: Stefan Metzmacher +Reviewed-by: Andreas Schneider +--- + lib/tdb/common/lock.c | 2 ++ + lib/tdb/common/transaction.c | 5 ++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/lib/tdb/common/lock.c b/lib/tdb/common/lock.c +index 4ad70cff3fe639abb781b204aa86a437e4a7adfe..e330201961a05bfef839659f260a5bbae078fbb5 100644 +--- a/lib/tdb/common/lock.c ++++ b/lib/tdb/common/lock.c +@@ -257,12 +257,14 @@ int tdb_allrecord_upgrade(struct tdb_context *tdb) + TDB_LOG((tdb, TDB_DEBUG_ERROR, + "tdb_allrecord_upgrade failed: count %u too high\n", + tdb->allrecord_lock.count)); ++ tdb->ecode = TDB_ERR_LOCK; + return -1; + } + + if (tdb->allrecord_lock.off != 1) { + TDB_LOG((tdb, TDB_DEBUG_ERROR, + "tdb_allrecord_upgrade failed: already upgraded?\n")); ++ tdb->ecode = TDB_ERR_LOCK; + return -1; + } + +diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c +index 0dd057ba7a71151e5173cb6d9b25666f915eab27..4d08fee6c25e61c61c783d08fc64c611fab51119 100644 +--- a/lib/tdb/common/transaction.c ++++ b/lib/tdb/common/transaction.c +@@ -982,7 +982,10 @@ static int _tdb_transaction_prepare_commit(struct tdb_context *tdb) + + /* upgrade the main transaction lock region to a write lock */ + if (tdb_allrecord_upgrade(tdb) == -1) { +- TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n")); ++ TDB_LOG((tdb, TDB_DEBUG_ERROR, ++ "tdb_transaction_prepare_commit: " ++ "failed to upgrade hash locks: %s\n", ++ tdb_errorstr(tdb))); + _tdb_transaction_cancel(tdb); + return -1; + } +-- +2.9.3 + diff --git a/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch b/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch new file mode 100644 index 0000000..bb45e0a --- /dev/null +++ b/SOURCES/0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch @@ -0,0 +1,30 @@ +From 36078263344fbad348fe21da757976ecd6d55be6 Mon Sep 17 00:00:00 2001 +From: Andrew Bartlett +Date: Fri, 31 Mar 2017 17:35:06 +1300 +Subject: [PATCH] tdb: Improve debugging in _tdb_transaction_start + +Signed-off-by: Andrew Bartlett +Reviewed-by: Stefan Metzmacher +Reviewed-by: Andreas Schneider +--- + lib/tdb/common/transaction.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/lib/tdb/common/transaction.c b/lib/tdb/common/transaction.c +index 4d08fee6c25e61c61c783d08fc64c611fab51119..f1050a2f7d9e9c86856d1469739c2a2d70ca1c85 100644 +--- a/lib/tdb/common/transaction.c ++++ b/lib/tdb/common/transaction.c +@@ -476,6 +476,10 @@ static int _tdb_transaction_start(struct tdb_context *tdb, + SAFE_FREE(tdb->transaction); + if ((lockflags & TDB_LOCK_WAIT) == 0) { + tdb->ecode = TDB_ERR_NOLOCK; ++ } else { ++ TDB_LOG((tdb, TDB_DEBUG_ERROR, ++ "tdb_transaction_start: " ++ "failed to get transaction lock\n")); + } + return -1; + } +-- +2.9.3 + diff --git a/SPECS/libtdb.spec b/SPECS/libtdb.spec index eda20d8..e10526c 100644 --- a/SPECS/libtdb.spec +++ b/SPECS/libtdb.spec @@ -5,8 +5,8 @@ %{!?python_version: %global python_version %(%{__python} -c "from distutils.sysconfig import get_python_version; print(get_python_version())")} Name: libtdb -Version: 1.3.8 -Release: 1%{?dist} +Version: 1.3.12 +Release: 2%{?dist} Group: System Environment/Daemons Summary: The tdb library License: LGPLv3+ @@ -22,6 +22,15 @@ BuildRequires: python-devel Provides: bundled(libreplace) # Patches +Patch0001: 0001-waf-disable-python-align-tdb-s-wscript.patch +Patch0002: 0002-tdb-tools-add-documentation-for-the-tdbbackup-n-opti.patch +Patch0003: 0003-tdb-Fix-some-signed-unsigned-hickups.patch +Patch0004: 0004-tdb-Do-lock-upgrades-properly.patch +Patch0005: 0005-tdb-Test-for-readonly-lock-upgrade-bug.patch +Patch0006: 0006-tdbtool-Add-storehex-command.patch +Patch0007: 0007-tdb-runtime-check-for-robust-mutexes-may-hang-in-thr.patch +Patch0008: 0008-tdb-Improve-debugging-when-the-allrecord-lock-fails-.patch +Patch0009: 0009-tdb-Improve-debugging-in-_tdb_transaction_start.patch %description A library that implements a trivial database. @@ -54,6 +63,11 @@ Python bindings for libtdb %prep %setup -q -n tdb-%{version} +for p in %patches ; do + %__patch -p3 -i $p +done + + %build %configure --disable-rpath \ --bundled-libraries=NONE \ @@ -110,9 +124,15 @@ rm -rf $RPM_BUILD_ROOT %postun -n python-tdb -p /sbin/ldconfig %changelog +* Tue May 2 2017 Jakub Hrozek - 1.3.12-2 +- Resolves: rhbz#1441231 - The tdb robust mutexes runtime check is not thread safe and ends in a deadlock + +* Tue Feb 14 2017 Jakub Hrozek - 1.3.12-1 +- Resolves: rhbz#1393812 - Rebase libtevent in RHEL-7.4 to version 4.6.x + * Fri Apr 1 2016 Jakub Hrozek - 1.3.8-1 - Rebase libtdb to 1.3.8 -- Related: rhbz#1322690 +- Related: rhbz#1322691 * Wed Aug 19 2015 Jakub Hrozek - 1.3.6-2 - Resolves: rhbz#1241015 - tdb deadlocks if you acquire allrecord_lock