diff options
author | Neal H. Walfield <neal@g10code.com> | 2015-12-15 20:05:20 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@g10code.com> | 2015-12-22 15:03:51 +0100 |
commit | dc417bf0c555a7416d0aedde6645fd1087660f92 (patch) | |
tree | 4cee54836db3b65ea727a6528625b461d6995515 /g10/keydb.c | |
parent | Only add the user supplied CFLAGS after running any autoconf tests. (diff) | |
download | gnupg2-dc417bf0c555a7416d0aedde6645fd1087660f92.tar.xz gnupg2-dc417bf0c555a7416d0aedde6645fd1087660f92.zip |
gpg: Fix TOCTTOU when updating keyblocks.
* g10/keydb.c (keydb_update_keyblock): Don't replace the record at the
current offset. After taking the lock, extract the fingerprint from
the keyblock, find it and then replace it.
--
Signed-off-by: Neal H. Walfield <neal@g10code.com>
GnuPG-bug-id: 2193
Between locating the record to update and actually updating the
keyblock, it is possible that another process modifies the keyring,
which causes the update to corrupt the keyring. This is due to a time
of check to time of use bug. The fix is straightforward: both
operations must be done while holding the lock. This changes the
semantics of the function slightly, but no callers need to be
modified. Further, it now becomes impossible to replace key A with B;
this function will only ever update B.
Diffstat (limited to 'g10/keydb.c')
-rw-r--r-- | g10/keydb.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/g10/keydb.c b/g10/keydb.c index b30819963..fb4966c27 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -1386,6 +1386,12 @@ gpg_error_t keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) { gpg_error_t err; + PKT_public_key *pk = kb->pkt->pkt.public_key; + KEYDB_SEARCH_DESC desc; + size_t len; + + assert (kb); + assert (kb->pkt->pkttype == PKT_PUBLIC_KEY); if (!hd) return gpg_error (GPG_ERR_INV_ARG); @@ -1393,9 +1399,6 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) kid_not_found_flush (); keyblock_cache_clear (hd); - if (hd->found < 0 || hd->found >= hd->used) - return gpg_error (GPG_ERR_VALUE_NOT_FOUND); - if (opt.dry_run) return 0; @@ -1403,6 +1406,19 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) if (err) return err; + memset (&desc, 0, sizeof (desc)); + fingerprint_from_pk (pk, desc.u.fpr, &len); + if (len == 20) + desc.mode = KEYDB_SEARCH_MODE_FPR20; + else + log_bug ("%s: Unsupported key length: %zd\n", __func__, len); + + keydb_search_reset (hd); + err = keydb_search (hd, &desc, 1, NULL); + if (err) + return gpg_error (GPG_ERR_VALUE_NOT_FOUND); + assert (hd->found >= 0 && hd->found < hd->used); + switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: |