[Pkg-gnupg-commit] [gnupg2] 54/159: gpg: Fix TOCTTOU when updating keyblocks.

Daniel Kahn Gillmor dkg at fifthhorseman.net
Wed Jan 27 13:23:53 UTC 2016


This is an automated email from the git hooks/post-receive script.

dkg pushed a commit to branch master
in repository gnupg2.

commit dc417bf0c555a7416d0aedde6645fd1087660f92
Author: Neal H. Walfield <neal at g10code.com>
Date:   Tue Dec 15 20:05:20 2015 +0100

    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 at 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.
---
 g10/keydb.c | 22 +++++++++++++++++++---
 g10/keydb.h | 15 ++++++++++++---
 2 files changed, 31 insertions(+), 6 deletions(-)

diff --git a/g10/keydb.c b/g10/keydb.c
index b308199..fb4966c 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:
diff --git a/g10/keydb.h b/g10/keydb.h
index 4164767..0425e74 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -255,12 +255,21 @@ const char *keydb_get_resource_name (KEYDB_HANDLE hd);
    for the user ID node.  */
 gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb);
 
-/* Replace the currently selected keyblock (i.e., the last result
-   returned by keydb_search) with the key block in KB.
+/* Update the keyblock KB (i.e., extract the fingerprint and find the
+   corresponding keyblock in the keyring).
 
    This doesn't do anything if --dry-run was specified.
 
-   Returns 0 on success.  Otherwise, it returns an error code.  */
+   Returns 0 on success.  Otherwise, it returns an error code.  Note:
+   if there isn't a keyblock in the keyring corresponding to KB, then
+   this function returns GPG_ERR_VALUE_NOT_FOUND.
+
+   This function selects the matching record and modifies the current
+   file position to point to the record just after the selected entry.
+   Thus, if you do a subsequent search using HD, you should first do a
+   keydb_search_reset.  Further, if the selected record is important,
+   you should use keydb_push_found_state and keydb_pop_found_state to
+   save and restore it.  */
 gpg_error_t keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb);
 
 /* Insert a keyblock into one of the underlying keyrings or keyboxes.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-gnupg/gnupg2.git



More information about the Pkg-gnupg-commit mailing list