mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
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.
This commit is contained in:
parent
02eb9fc9d5
commit
dc417bf0c5
2 changed files with 31 additions and 6 deletions
22
g10/keydb.c
22
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue