gpg: Fix DoS while parsing mangled secret key packets.
authorWerner Koch <wk@gnupg.org>
Sun, 5 Apr 2015 10:48:14 +0000 (12:48 +0200)
committerWerner Koch <wk@gnupg.org>
Sun, 5 Apr 2015 10:49:26 +0000 (12:49 +0200)
* g10/parse-packet.c (parse_key): Check PKTLEN before calling mpi_read
et al.
--

Due to the missing length checks PKTLEN may turn negative.  Because
PKTLEN is an unsigned int the malloc in read_rest would try to malloc
a too large number and terminate the process with "error reading rest
of packet: Cannot allocate memory".

Reported-by: Hanno Böck.
Signed-off-by: Werner Koch <wk@gnupg.org>
g10/parse-packet.c

index d6a6d10..c80b7df 100644 (file)
@@ -2103,6 +2103,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       byte temp[16];
       size_t snlen = 0;
 
+      if (pktlen < 1)
+        {
+          err = gpg_error (GPG_ERR_INV_PACKET);
+          goto leave;
+        }
+
       pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
       if (!pk->seckey_info)
         {
@@ -2303,6 +2309,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
        }
       else if (ski->is_protected)
        {
+         if (pktlen < 2) /* At least two bytes for the length.  */
+           {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+             goto leave;
+           }
+
          /* Ugly: The length is encrypted too, so we read all stuff
           * up to the end of the packet into the first SKEY
           * element.  */
@@ -2323,7 +2335,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
           /* Not encrypted.  */
          for (i = npkey; i < nskey; i++)
            {
-              unsigned int n = pktlen;
+              unsigned int n;
+
+              if (pktlen < 2) /* At least two bytes for the length.  */
+                {
+                  err = gpg_error (GPG_ERR_INV_PACKET);
+                  goto leave;
+                }
+              n = pktlen;
               pk->pkey[i] = mpi_read (inp, &n, 0);
               pktlen -= n;
               if (list_mode)
@@ -2339,6 +2358,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
          if (err)
            goto leave;
 
+         if (pktlen < 2)
+           {
+              err = gpg_error (GPG_ERR_INV_PACKET);
+             goto leave;
+           }
          ski->csum = read_16 (inp);
          pktlen -= 2;
          if (list_mode)