gpg: Extend free_packet to handle a packet parser context.
authorWerner Koch <wk@gnupg.org>
Wed, 29 Mar 2017 09:57:40 +0000 (11:57 +0200)
committerWerner Koch <wk@gnupg.org>
Wed, 29 Mar 2017 10:08:31 +0000 (12:08 +0200)
* g10/packet.h (struct parse_packet_ctx_s): Add fields LAST_PKT and
FREE_LAST_PKT.
(init_parse_packet): Clear them.
(deinit_parse_packet): New macro.  Change all users if
init_parse_packet to also call this macro.
* g10/free-packet.c (free_packet): Add arg PARSECTX and handle shallow
packet copies in the context.  Change all callers.
* g10/parse-packet.c (parse): Store certain packets in the parse
context.
--

Signed-off-by: Werner Koch <wk@gnupg.org>
12 files changed:
g10/encrypt.c
g10/free-packet.c
g10/import.c
g10/kbnode.c
g10/keydb.c
g10/keyedit.c
g10/keygen.c
g10/keyring.c
g10/mainproc.c
g10/packet.h
g10/parse-packet.c
g10/sign.c

index 0a892c2..a79a470 100644 (file)
@@ -394,7 +394,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
     }
   if (pt)
     pt->buf = NULL;
-  free_packet (&pkt);
+  free_packet (&pkt, NULL);
   xfree (cfx.dek);
   xfree (s2k);
   release_armor_context (afx);
@@ -755,7 +755,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
     }
   if (pt)
     pt->buf = NULL;
-  free_packet (&pkt);
+  free_packet (&pkt, NULL);
   xfree (cfx.dek);
   xfree (symkey_dek);
   xfree (symkey_s2k);
index 4cf80a4..535a17f 100644 (file)
@@ -394,18 +394,40 @@ free_plaintext( PKT_plaintext *pt )
   xfree (pt);
 }
 
+
 /****************
  * Free the packet in PKT.
  */
 void
-free_packet (PACKET *pkt)
+free_packet (PACKET *pkt, parse_packet_ctx_t parsectx)
 {
   if (!pkt || !pkt->pkt.generic)
-    return;
+    {
+      if (parsectx && parsectx->last_pkt)
+        {
+          if (parsectx->free_last_pkt)
+            {
+              free_packet (parsectx->last_pkt, NULL);
+              parsectx->free_last_pkt = 0;
+            }
+          parsectx->last_pkt = NULL;
+        }
+      return;
+    }
 
   if (DBG_MEMORY)
     log_debug ("free_packet() type=%d\n", pkt->pkttype);
 
+  /* If we have a parser context holding PKT then do not free the
+   * packet but set a flag that the packet in the parser context is
+   * now a deep copy.  */
+  if (parsectx && parsectx->last_pkt == pkt && !parsectx->free_last_pkt)
+    {
+      parsectx->free_last_pkt = 1;
+      pkt->pkt.generic = NULL;
+      return;
+    }
+
   switch (pkt->pkttype)
     {
     case PKT_SIGNATURE:
index 9aa6c8b..3321a7e 100644 (file)
@@ -790,7 +790,7 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
         {
           in_v3key = 1;
           ++*r_v3keys;
-          free_packet (pkt);
+          free_packet (pkt, &parsectx);
           init_packet (pkt);
           continue;
         }
@@ -804,7 +804,7 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
               rc = GPG_ERR_INV_KEYRING;
               goto ready;
             }
-          free_packet( pkt );
+          free_packet (pkt, &parsectx);
           init_packet(pkt);
           continue;
        }
@@ -812,7 +812,7 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
         if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
                           || pkt->pkttype == PKT_SECRET_KEY))
           {
-           free_packet( pkt );
+           free_packet (pkt, &parsectx);
            init_packet(pkt);
            continue;
           }
@@ -843,7 +843,7 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
                pkt->pkt.compressed->buf = NULL;
                push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1);
              }
-           free_packet( pkt );
+           free_packet (pkt, &parsectx);
            init_packet(pkt);
            break;
 
@@ -851,7 +851,7 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
             /* Skip those packets unless we are in restore mode.  */
             if ((opt.import_options & IMPORT_RESTORE))
               goto x_default;
-           free_packet( pkt );
+           free_packet (pkt, &parsectx);
            init_packet(pkt);
             break;
 
@@ -887,7 +887,8 @@ read_block( IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
     release_kbnode( root );
   else
     *ret_root = root;
-  free_packet( pkt );
+  free_packet (pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
   xfree( pkt );
   return rc;
 }
index b8c31b7..c2aaacd 100644 (file)
@@ -117,8 +117,8 @@ release_kbnode( KBNODE n )
     while( n ) {
        n2 = n->next;
        if( !is_cloned_kbnode(n) ) {
-           free_packet( n->pkt );
-           xfree( n->pkt );
+            free_packet (n->pkt, NULL);
+            xfree( n->pkt );
        }
        free_node( n );
        n = n2;
@@ -288,7 +288,7 @@ commit_kbnode( KBNODE *root )
            else
                nl->next = n->next;
            if( !is_cloned_kbnode(n) ) {
-               free_packet( n->pkt );
+                free_packet (n->pkt, NULL);
                xfree( n->pkt );
            }
            free_node( n );
@@ -312,7 +312,7 @@ remove_kbnode( KBNODE *root, KBNODE node )
            else
                nl->next = n->next;
            if( !is_cloned_kbnode(n) ) {
-               free_packet( n->pkt );
+                free_packet (n->pkt, NULL);
                xfree( n->pkt );
            }
            free_node( n );
index c0bc9f5..1bbda35 100644 (file)
@@ -1180,7 +1180,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
     {
       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
         {
-          free_packet (pkt);
+          free_packet (pkt, &parsectx);
           init_packet (pkt);
           continue;
        }
@@ -1209,7 +1209,7 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
              the other GPG specific packets don't make sense either.  */
           log_error ("skipped packet of type %d in keybox\n",
                      (int)pkt->pkttype);
-          free_packet(pkt);
+          free_packet(pkt, &parsectx);
           init_packet(pkt);
           continue;
         }
@@ -1311,7 +1311,8 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
     release_kbnode (keyblock);
   else
     *r_keyblock = keyblock;
-  free_packet (pkt);
+  free_packet (pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
   xfree (pkt);
   return err;
 }
index 76d1889..9a61126 100644 (file)
@@ -2467,7 +2467,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
            init_packet (pkt);
             init_parse_packet (&parsectx, a);
            err = parse_packet (&parsectx, pkt);
-           iobuf_close (a);
+           deinit_parse_packet (&parsectx);
+            iobuf_close (a);
            iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname);
            if (!err && pkt->pkttype != PKT_SECRET_KEY
                && pkt->pkttype != PKT_SECRET_SUBKEY)
@@ -2477,7 +2478,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
                 tty_printf (_("Error reading backup key from '%s': %s\n"),
                             fname, gpg_strerror (err));
                 xfree (fname);
-                free_packet (pkt);
+                free_packet (pkt, NULL);
                 xfree (pkt);
                 break;
               }
@@ -5008,7 +5009,7 @@ menu_expire (kbnode_t pub_keyblock, int force_mainkey, u32 newexpiration)
              newpkt = xmalloc_clear (sizeof *newpkt);
              newpkt->pkttype = PKT_SIGNATURE;
              newpkt->pkt.signature = newsig;
-             free_packet (node->pkt);
+             free_packet (node->pkt, NULL);
              xfree (node->pkt);
              node->pkt = newpkt;
              sub_pk = NULL;
@@ -5114,7 +5115,7 @@ menu_changeusage (kbnode_t keyblock)
              newpkt = xmalloc_clear (sizeof *newpkt);
              newpkt->pkttype = PKT_SIGNATURE;
              newpkt->pkt.signature = newsig;
-             free_packet (node->pkt);
+             free_packet (node->pkt, NULL);
              xfree (node->pkt);
              node->pkt = newpkt;
              sub_pk = NULL;
@@ -5213,7 +5214,7 @@ menu_backsign (KBNODE pub_keyblock)
              newpkt = xmalloc_clear (sizeof (*newpkt));
              newpkt->pkttype = PKT_SIGNATURE;
              newpkt->pkt.signature = newsig;
-             free_packet (sig_pk->pkt);
+             free_packet (sig_pk->pkt, NULL);
              xfree (sig_pk->pkt);
              sig_pk->pkt = newpkt;
 
@@ -5371,7 +5372,7 @@ menu_set_primary_uid (KBNODE pub_keyblock)
                      newpkt = xmalloc_clear (sizeof *newpkt);
                      newpkt->pkttype = PKT_SIGNATURE;
                      newpkt->pkt.signature = newsig;
-                     free_packet (node->pkt);
+                     free_packet (node->pkt, NULL);
                      xfree (node->pkt);
                      node->pkt = newpkt;
                      modified = 1;
@@ -5460,7 +5461,7 @@ menu_set_preferences (KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
@@ -5596,7 +5597,7 @@ menu_set_keyserver_url (const char *url, KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
@@ -5797,7 +5798,7 @@ menu_set_notation (const char *string, KBNODE pub_keyblock)
                  newpkt = xmalloc_clear (sizeof *newpkt);
                  newpkt->pkttype = PKT_SIGNATURE;
                  newpkt->pkt.signature = newsig;
-                 free_packet (node->pkt);
+                 free_packet (node->pkt, NULL);
                  xfree (node->pkt);
                  node->pkt = newpkt;
                  modified = 1;
index 44f139a..78c35a2 100644 (file)
@@ -867,7 +867,7 @@ make_backsig (PKT_signature *sig, PKT_public_key *pk,
       backsig_pkt.pkttype = PKT_SIGNATURE;
       backsig_pkt.pkt.signature = backsig;
       err = build_packet (backsig_out, &backsig_pkt);
-      free_packet (&backsig_pkt);
+      free_packet (&backsig_pkt, NULL);
       if (err)
        log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err));
       else
index e4fc111..2210df9 100644 (file)
@@ -415,7 +415,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
     while ((rc=parse_packet (&parsectx, pkt)) != -1) {
         hd->found.n_packets++;
         if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET) {
-           free_packet (pkt);
+           free_packet (pkt, &parsectx);
            init_packet (pkt);
            continue;
        }
@@ -461,7 +461,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
           default:
            log_error ("skipped packet of type %d in keyring\n",
                        (int)pkt->pkttype);
-           free_packet(pkt);
+           free_packet(pkt, &parsectx);
            init_packet(pkt);
            continue;
           }
@@ -490,7 +490,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
             /* Reset LASTNODE, so that we set the cache status only from
              * the ring trust packet immediately following a signature. */
             lastnode = NULL;
-           free_packet(pkt);
+           free_packet(pkt, &parsectx);
            init_packet(pkt);
            continue;
           }
@@ -542,7 +542,8 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
         }
        *ret_kb = keyblock;
     }
-    free_packet (pkt);
+    free_packet (pkt, &parsectx);
+    deinit_parse_packet (&parsectx);
     xfree (pkt);
     iobuf_close(a);
 
@@ -1132,7 +1133,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       rc = search_packet (&parsectx, &pkt, &offset, need_uid);
       if (ignore_legacy && gpg_err_code (rc) == GPG_ERR_LEGACY_KEY)
         {
-          free_packet (&pkt);
+          free_packet (&pkt, &parsectx);
           continue;
         }
       if (rc)
@@ -1146,7 +1147,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
       if (initial_skip)
         {
-          free_packet (&pkt);
+          free_packet (&pkt, &parsectx);
           continue;
         }
 
@@ -1228,7 +1229,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
             goto found;
           }
        }
-      free_packet (&pkt);
+      free_packet (&pkt, &parsectx);
       continue;
     found:
       if (rc)
@@ -1255,7 +1256,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
         }
       if (n == ndesc)
         goto real_found;
-      free_packet (&pkt);
+      free_packet (&pkt, &parsectx);
     }
  real_found:
   if (!rc)
@@ -1309,7 +1310,8 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
       hd->current.error = rc;
     }
 
-  free_packet(&pkt);
+  free_packet (&pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
   set_packet_list_mode(save_mode);
   return rc;
 }
index 30d9b18..8581104 100644 (file)
@@ -358,7 +358,7 @@ proc_symkey_enc (CTX c, PACKET *pkt)
 
  leave:
   c->symkeys++;
-  free_packet (pkt);
+  free_packet (pkt, NULL);
 }
 
 
@@ -456,7 +456,7 @@ proc_pubkey_enc (ctrl_t ctrl, CTX c, PACKET *pkt)
         log_info (_("public key encrypted data: good DEK\n"));
     }
 
-  free_packet(pkt);
+  free_packet(pkt, NULL);
 }
 
 
@@ -657,7 +657,7 @@ proc_encrypted (CTX c, PACKET *pkt)
 
   xfree (c->dek);
   c->dek = NULL;
-  free_packet (pkt);
+  free_packet (pkt, NULL);
   c->last_was_session_key = 0;
   write_status (STATUS_END_DECRYPTION);
 }
@@ -774,7 +774,7 @@ proc_plaintext( CTX c, PACKET *pkt )
   if (rc)
     log_error ("handle plaintext failed: %s\n", gpg_strerror (rc));
 
-  free_packet(pkt);
+  free_packet (pkt, NULL);
   c->last_was_session_key = 0;
 
   /* We add a marker control packet instead of the plaintext packet.
@@ -837,7 +837,7 @@ proc_compressed (CTX c, PACKET *pkt)
   else if (rc)
     log_error ("uncompressing failed: %s\n", gpg_strerror (rc));
 
-  free_packet(pkt);
+  free_packet (pkt, NULL);
   c->last_was_session_key = 0;
   return rc;
 }
@@ -1348,7 +1348,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
       any_data = 1;
       if (rc)
         {
-          free_packet (pkt);
+          free_packet (pkt, &parsectx);
           /* Stop processing when an invalid packet has been encountered
            * but don't do so when we are doing a --list-packets.  */
           if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
@@ -1466,7 +1466,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
           init_packet (pkt);
        }
       else
-        free_packet(pkt);
+        free_packet (pkt, &parsectx);
     }
 
   if (rc == GPG_ERR_INV_PACKET)
@@ -1481,7 +1481,8 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
  leave:
   release_list (c);
   xfree(c->dek);
-  free_packet (pkt);
+  free_packet (pkt, &parsectx);
+  deinit_parse_packet (&parsectx);
   xfree (pkt);
   free_md_filter_context (&c->mfx);
   return rc;
index ffa1fe9..ad6f317 100644 (file)
@@ -596,13 +596,22 @@ int set_packet_list_mode( int mode );
 /* A context used with parse_packet.  */
 struct parse_packet_ctx_s
 {
-  iobuf_t inp; /* The input stream with the packets.  */
+  iobuf_t inp;       /* The input stream with the packets.  */
+  PACKET *last_pkt;  /* The last parsed packet.  */
+  int free_last_pkt; /* Indicates that LAST_PKT must be freed.  */
 };
 typedef struct parse_packet_ctx_s *parse_packet_ctx_t;
 
-#define init_parse_packet(a,i) do { (a)->inp = (i);    \
-    /**/                       } while (0)
+#define init_parse_packet(a,i) do { \
+    (a)->inp = (i);                 \
+    (a)->last_pkt = NULL;           \
+    (a)->free_last_pkt = 0;         \
+  } while (0)
 
+#define deinit_parse_packet(a) do { \
+    if ((a)->free_last_pkt)         \
+      free_packet (NULL, (a));      \
+  } while (0)
 
 
 #if DEBUG_PARSE_PACKET
@@ -803,7 +812,7 @@ void free_public_key( PKT_public_key *key );
 void free_attributes(PKT_user_id *uid);
 void free_user_id( PKT_user_id *uid );
 void free_comment( PKT_comment *rem );
-void free_packet( PACKET *pkt );
+void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
 prefitem_t *copy_prefs (const prefitem_t *prefs);
 PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
 PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
index 7766a45..ab273a5 100644 (file)
@@ -352,6 +352,9 @@ dbg_copy_all_packets (iobuf_t inp, iobuf_t out, const char *dbg_f, int dbg_l)
         (rc =
          parse (&parsectx, &pkt, 0, NULL, &skip, out, 0, "copy",
                  dbg_f, dbg_l)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
@@ -372,6 +375,9 @@ copy_all_packets (iobuf_t inp, iobuf_t out)
       init_packet (&pkt);
     }
   while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -397,11 +403,17 @@ dbg_copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff,
   do
     {
       if (iobuf_tell (inp) >= stopoff)
-       return 0;
+        {
+          deinit_parse_packet (&parsectx);
+          return 0;
+        }
       init_packet (&pkt);
     }
   while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0,
                       "some", dbg_f, dbg_l)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
@@ -418,10 +430,16 @@ copy_some_packets (iobuf_t inp, iobuf_t out, off_t stopoff)
   do
     {
       if (iobuf_tell (inp) >= stopoff)
-       return 0;
+        {
+          deinit_parse_packet (&parsectx);
+          return 0;
+        }
       init_packet (&pkt);
     }
   while (!(rc = parse (&parsectx, &pkt, 0, NULL, &skip, out, 0)));
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -447,6 +465,9 @@ dbg_skip_some_packets (iobuf_t inp, unsigned n, const char *dbg_f, int dbg_l)
       rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1, "skip",
                   dbg_f, dbg_l);
     }
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #else /*!DEBUG_PARSE_PACKET*/
@@ -465,6 +486,9 @@ skip_some_packets (iobuf_t inp, unsigned int n)
       init_packet (&pkt);
       rc = parse (&parsectx, &pkt, 0, NULL, &skip, NULL, 1);
     }
+
+  deinit_parse_packet (&parsectx);
+
   return rc;
 }
 #endif /*!DEBUG_PARSE_PACKET*/
@@ -804,6 +828,16 @@ parse (parse_packet_ctx_t ctx, PACKET *pkt, int onlykeypkts, off_t * retpos,
       break;
     }
 
+  /* Store a shallow copy of certain packets in the context.  */
+  if (!rc && (pkttype == PKT_PUBLIC_KEY
+              || pkttype == PKT_SECRET_KEY
+              || pkttype == PKT_USER_ID
+              || pkttype == PKT_ATTRIBUTE
+              || pkttype == PKT_SIGNATURE))
+    ctx->last_pkt = pkt;
+  else
+    ctx->last_pkt = NULL;
+
  leave:
   /* FIXME: We leak in case of an error (see the xmalloc's above).  */
   if (!rc && iobuf_error (inp))
index 801c809..9bb1f44 100644 (file)
@@ -575,7 +575,7 @@ write_onepass_sig_packets (SK_LIST sk_list, IOBUF out, int sigclass )
         pkt.pkttype = PKT_ONEPASS_SIG;
         pkt.pkt.onepass_sig = ops;
         rc = build_packet (out, &pkt);
-        free_packet (&pkt);
+        free_packet (&pkt, NULL);
         if (rc) {
             log_error ("build onepass_sig packet failed: %s\n",
                        gpg_strerror (rc));
@@ -645,7 +645,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
             log_error ("build_packet(PLAINTEXT) failed: %s\n",
                        gpg_strerror (rc) );
         pt->buf = NULL;
-        free_packet (&pkt);
+        free_packet (&pkt, NULL);
     }
     else {
         byte copy_buffer[4096];
@@ -732,7 +732,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
           rc = build_packet (out, &pkt);
           if (!rc && is_status_enabled())
             print_status_sig_created (pk, sig, status_letter);
-          free_packet (&pkt);
+          free_packet (&pkt, NULL);
           if (rc)
             log_error ("build signature packet failed: %s\n",
                        gpg_strerror (rc));