diff options
author | Werner Koch <wk@gnupg.org> | 2018-03-26 16:57:04 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2018-03-26 16:57:04 +0200 |
commit | 456a3a8e93ea14f821e0e98fb515f284ece98685 (patch) | |
tree | fcef497177f57770b933ddbd7e06182a11baa2ba /g10/tdbio.c | |
parent | gpg: Disable unused code parts in tdbio.c (diff) | |
download | gnupg2-456a3a8e93ea14f821e0e98fb515f284ece98685.tar.xz gnupg2-456a3a8e93ea14f821e0e98fb515f284ece98685.zip |
gpg: Fix trustdb updates without lock held.
* g10/tdbio.c (is_locked): Turn into a counter.
(take_write_lock, release_write_lock): Implement recursive locks.
--
On trustdb creation we have this call sequence:
init_trustdb -> takes lock
tdbio_set_dbname
create_version_record
tdbio_write_record
put_record_into_cache -> takes lock
put_record_into_cache -> releases lock
init_trustdb -> releases lock
The second take lock does noting but the first release lock has
already released the lock and the second release lock is a thus a NOP.
This is likely the cause for the corrupted trustdb as reported in
GnuPG-bug-id: 3839
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'g10/tdbio.c')
-rw-r--r-- | g10/tdbio.c | 39 |
1 files changed, 29 insertions, 10 deletions
diff --git a/g10/tdbio.c b/g10/tdbio.c index fb3cf1504..4940c5ce2 100644 --- a/g10/tdbio.c +++ b/g10/tdbio.c @@ -105,10 +105,11 @@ struct cmp_xdir_struct /* The name of the trustdb file. */ static char *db_name; -/* The handle for locking the trustdb file and a flag to record - whether a lock has been taken. */ +/* The handle for locking the trustdb file and a counter to record how + * often this lock has been taken. That counter is required becuase + * dotlock does not implemen recursive locks. */ static dotlock_t lockhandle; -static int is_locked; +static unsigned int is_locked; /* The file descriptor of the trustdb. */ static int db_fd = -1; @@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type); static int take_write_lock (void) { + int rc; + if (!lockhandle) lockhandle = dotlock_create (db_name, 0); if (!lockhandle) @@ -144,12 +147,16 @@ take_write_lock (void) { if (dotlock_take (lockhandle, -1) ) log_fatal ( _("can't lock '%s'\n"), db_name ); - else - is_locked = 1; - return 0; + rc = 0; } else - return 1; + rc = 1; + + if (opt.lock_once) + is_locked = 1; + else + is_locked++; + return rc; } @@ -160,10 +167,22 @@ take_write_lock (void) static void release_write_lock (void) { - if (!opt.lock_once) - if (!dotlock_release (lockhandle)) - is_locked = 0; + if (opt.lock_once) + return; /* Don't care; here IS_LOCKED is fixed to 1. */ + + if (!is_locked) + { + log_error ("Ooops, tdbio:release_write_lock with no lock held\n"); + return; + } + if (--is_locked) + return; + + if (dotlock_release (lockhandle)) + log_error ("Oops, tdbio:release_write_locked failed\n"); } + + /************************************* ************* record cache ********** |