Fix potential heap corruption in "gpg -v --version".
authorWerner Koch <wk@gnupg.org>
Sat, 15 Dec 2012 10:28:00 +0000 (11:28 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 22 Apr 2013 18:25:35 +0000 (20:25 +0200)
* g10/gpg.c (build_list): Rewrite to cope with buffer overflow in
certain locales.
--

This fixes an obvious bug in locales where the translated string is
longer than the original.  The bug could be exhibited by using
LANG=ru_RU.utf8 gpg -v --version.

En passant we also removed the trailing white space on continued
lines.

Reported-by: Dmitry V. Levin" <ldv at altlinux.org>
(cherry picked from commit e33e74e3a4b2b4a0341f933410ddd5db7a12515e)

Note that this version uses utf8_charcount to get the indentation
mostly right.

Signed-off-by: Werner Koch <wk@gnupg.org>
g10/gpg.c

index 6e55b44..b773099 100644 (file)
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -40,6 +40,7 @@
 #include "packet.h"
 #include "../common/iobuf.h"
 #include "util.h"
+#include "membuf.h"
 #include "main.h"
 #include "options.h"
 #include "keydb.h"
@@ -884,57 +885,53 @@ my_strusage( int level )
 
 
 static char *
-build_listconst char *text, char letter,
-           const char * (*mapf)(int), int (*chkf)(int) )
+build_list (const char *text, char letter,
+           const char * (*mapf)(int), int (*chkf)(int))
 {
-    int i;
-    const char *s;
-    size_t n=strlen(text)+2;
-    char *list, *p, *line=NULL;
-
-    if (maybe_setuid)
-      gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
-
-    for(i=0; i <= 110; i++ )
-       if( !chkf(i) && (s=mapf(i)) )
-           n += strlen(s) + 7 + 2;
-    list = xmalloc( 21 + n ); *list = 0;
-    for(p=NULL, i=0; i <= 110; i++ ) {
-       if( !chkf(i) && (s=mapf(i)) ) {
-           if( !p ) {
-               p = stpcpy( list, text );
-               line=p;
-           }
-           else
-               p = stpcpy( p, ", ");
+  membuf_t mb;
+  int indent;
+  int i, j, len;
+  const char *s;
+  char *string;
 
-           if(strlen(line)>60) {
-             int spaces=strlen(text);
+  if (maybe_setuid)
+    gcry_control (GCRYCTL_INIT_SECMEM, 0, 0);  /* Drop setuid. */
 
-             list=xrealloc(list,n+spaces+1);
-             /* realloc could move the block, so find the end again */
-             p=list;
-             while(*p)
-               p++;
+  indent = utf8_charcount (text);
+  len = 0;
+  init_membuf (&mb, 512);
 
-             p=stpcpy(p, "\n");
-             line=p;
-             for(;spaces;spaces--)
-               p=stpcpy(p, " ");
+  for (i=0; i <= 110; i++ )
+    {
+      if (!chkf (i) && (s = mapf (i)))
+        {
+          if (mb.len - len > 60)
+            {
+              put_membuf_str (&mb, ",\n");
+              len = mb.len;
+              for (j=0; j < indent; j++)
+                put_membuf_str (&mb, " ");
            }
+          else if (mb.len)
+            put_membuf_str (&mb, ", ");
+          else
+            put_membuf_str (&mb, text);
 
-           p = stpcpy(p, s );
-           if(opt.verbose && letter)
-             {
-               char num[8];
-               sprintf(num," (%c%d)",letter,i);
-               p = stpcpy(p,num);
-             }
+          put_membuf_str (&mb, s);
+          if (opt.verbose && letter)
+            {
+              char num[20];
+              snprintf (num, sizeof num, " (%c%d)", letter, i);
+              put_membuf_str (&mb, num);
+            }
        }
     }
-    if( p )
-       p = stpcpy(p, "\n" );
-    return list;
+  if (mb.len)
+    put_membuf_str (&mb, "\n");
+  put_membuf (&mb, "", 1);
+
+  string = get_membuf (&mb, NULL);
+  return xrealloc (string, strlen (string)+1);
 }