<<< Date Index >>>     <<< Thread Index >>>

Re: Various potential buffer overflows and format string bugs



On 2004-10-30 02:26:31 +0200, Ulf Härnhammar wrote:

> There are also a whole bunch of strncat() calls with the wrong
> third parameter (it should be the number of characters left in
> the string, not the whole size of the string).

Thanks, too, for noting this one.

I don't like the proposed fix, though, as it implies unnecessarily
walking through the whole string twice.

The attached patch (which is now going into the CVS) introduces new
functions safe_strcat and safe_strncat that take a parameter that
limits the destination's length; safe_strncat takes a second length
parameter that limits the number of characters copied from the
source.

-- 
Thomas Roessler · Personal soap box at <http://log.does-not-exist.org/>.
Index: browser.c
===================================================================
RCS file: /cvs/mutt/mutt/browser.c,v
retrieving revision 3.10
diff -u -p -r3.10 browser.c
--- browser.c   14 Jul 2004 05:45:18 -0000      3.10
+++ browser.c   30 Oct 2004 21:39:11 -0000
@@ -574,8 +574,8 @@ void _mutt_select_file (char *f, size_t 
       else
       {
        getcwd (LastDir, sizeof (LastDir));
-       strcat (LastDir, "/");  /* __STRCAT_CHECKED__ */
-       strncat (LastDir, f, i);
+       safe_strcat (LastDir, sizeof (LastDir), "/");
+       safe_strncat (LastDir, sizeof (LastDir), f, i);
       }
     }
     else
Index: buffy.c
===================================================================
RCS file: /cvs/mutt/mutt/buffy.c,v
retrieving revision 3.9
diff -u -p -r3.9 buffy.c
--- buffy.c     1 Feb 2004 17:50:43 -0000       3.9
+++ buffy.c     30 Oct 2004 21:39:12 -0000
@@ -439,7 +439,7 @@ int mutt_buffy_list (void)
   pos = 0;
   first = 1;
   buffylist[0] = 0;
-  pos += strlen (strncat (buffylist, _("New mail in "), sizeof (buffylist) - 1 
- pos));
+  pos += strlen (strncat (buffylist, _("New mail in "), sizeof (buffylist) - 1 
- pos)); /* __STRNCAT_CHECKED__ */
   for (tmp = Incoming; tmp; tmp = tmp->next)
   {
     /* Is there new mail in this mailbox? */
@@ -453,21 +453,21 @@ int mutt_buffy_list (void)
       break;
     
     if (!first)
-      pos += strlen (strncat(buffylist + pos, ", ", sizeof(buffylist)-1-pos));
+      pos += strlen (strncat(buffylist + pos, ", ", sizeof(buffylist)-1-pos)); 
/* __STRNCAT_CHECKED__ */
 
     /* Prepend an asterisk to mailboxes not already notified */
     if (!tmp->notified)
     {
-      /* pos += strlen (strncat(buffylist + pos, "*", 
sizeof(buffylist)-1-pos)); */
+      /* pos += strlen (strncat(buffylist + pos, "*", 
sizeof(buffylist)-1-pos));  __STRNCAT_CHECKED__ */
       tmp->notified = 1;
       BuffyNotify--;
     }
-    pos += strlen (strncat(buffylist + pos, path, sizeof(buffylist)-1-pos));
+    pos += strlen (strncat(buffylist + pos, path, sizeof(buffylist)-1-pos)); 
/* __STRNCAT_CHECKED__ */
     first = 0;
   }
   if (!first && tmp)
   {
-    strncat (buffylist + pos, ", ...", sizeof (buffylist) - 1 - pos);
+    strncat (buffylist + pos, ", ...", sizeof (buffylist) - 1 - pos); /* 
__STRNCAT_CHECKED__ */
   }
   if (!first)
   {
Index: check_sec.sh
===================================================================
RCS file: /cvs/mutt/mutt/check_sec.sh,v
retrieving revision 3.1
diff -u -p -r3.1 check_sec.sh
--- check_sec.sh        1 May 2002 23:20:56 -0000       3.1
+++ check_sec.sh        30 Oct 2004 21:39:12 -0000
@@ -34,6 +34,7 @@ do_check '\<fopen.*'\"'.*w' __FOPEN_CHEC
 do_check '\<(mutt_)?strcpy' __STRCPY_CHECKED__ "Alert: Unchecked strcpy calls."
 do_check '\<strcat' __STRCAT_CHECKED__ "Alert: Unchecked strcat calls."
 do_check '\<sprintf.*%s' __SPRINTF_CHECKED__ "Alert: Unchecked sprintf calls."
+do_check '\<strncat' __STRNCAT_CHECKED__ "You probably meant safe_strcat here."
 
 # don't do this check on others' code.
 do_check_files '\<(malloc|realloc|free|strdup)[        ]*\(' __MEM_CHECKED__ 
"Alert: Use of traditional memory management calls." \
Index: commands.c
===================================================================
RCS file: /cvs/mutt/mutt/commands.c,v
retrieving revision 3.25
diff -u -p -r3.25 commands.c
--- commands.c  14 Jul 2004 04:16:58 -0000      3.25
+++ commands.c  30 Oct 2004 21:39:15 -0000
@@ -282,10 +282,10 @@ void ci_bounce_message (HEADER *h, int *
     mutt_format_string (prompt, sizeof (prompt),
                        0, COLS-extra_space, 0, 0,
                        prompt, sizeof (prompt), 0);
-    strncat (prompt, "...?", sizeof (prompt));
+    safe_strcat (prompt, sizeof (prompt), "...?");
   }
   else
-    strncat (prompt, "?", sizeof (prompt));
+    safe_strcat (prompt, sizeof (prompt), "?");
 
   if (query_quadoption (OPT_BOUNCE, prompt) != M_YES)
   {
Index: edit.c
===================================================================
RCS file: /cvs/mutt/mutt/edit.c,v
retrieving revision 3.3
diff -u -p -r3.3 edit.c
--- edit.c      19 Sep 2003 13:03:25 -0000      3.3
+++ edit.c      30 Oct 2004 21:39:16 -0000
@@ -463,7 +463,7 @@ int mutt_builtin_editor (const char *pat
       done = 1;
     else
     {
-      strncat (tmp, "\n", sizeof(tmp)); tmp[sizeof(tmp) - 1] = '\0';
+      safe_strcat (tmp, sizeof (tmp), "\n");
       if (buflen == bufmax)
        safe_realloc (&buf, sizeof (char *) * (bufmax += 25));
       buf[buflen++] = safe_strdup (tmp[1] == '~' ? tmp + 1 : tmp);
Index: lib.c
===================================================================
RCS file: /cvs/mutt/mutt/lib.c,v
retrieving revision 3.14
diff -u -p -r3.14 lib.c
--- lib.c       29 Sep 2004 11:27:33 -0000      3.14
+++ lib.c       30 Oct 2004 21:39:17 -0000
@@ -153,6 +153,45 @@ char *safe_strdup (const char *s)
   return (p);
 }
 
+char *safe_strcat (char *d, size_t l, const char *s)
+{
+  char *p = d;
+
+  if (!l) 
+    return d;
+
+  l--; /* Space for the trailing '\0'. */
+  
+  for (; *d && l; l--)
+    d++;
+  for (; *s && l; l--)
+    *d++ = *s++;
+
+  *d = '\0';
+  
+  return p;
+}
+
+char *safe_strncat (char *d, size_t l, const char *s, size_t sl)
+{
+  char *p = d;
+
+  if (!l)
+    return d;
+  
+  l--; /* Space for the trailing '\0'. */
+  
+  for (; *d && l; l--)
+    d++;
+  for (; *s && l && sl; l--, sl--)
+    *d++ = *s++;
+
+  *d = '\0';
+  
+  return p;
+}
+
+
 void mutt_str_replace (char **p, const char *s)
 {
   FREE (p);
Index: lib.h
===================================================================
RCS file: /cvs/mutt/mutt/lib.h,v
retrieving revision 3.8
diff -u -p -r3.8 lib.h
--- lib.h       4 Oct 2003 20:34:59 -0000       3.8
+++ lib.h       30 Oct 2004 21:39:17 -0000
@@ -115,6 +115,8 @@ char *mutt_skip_whitespace (char *);
 char *mutt_strlower (char *);
 char *mutt_substrcpy (char *, const char *, const char *, size_t);
 char *mutt_substrdup (const char *, const char *);
+char *safe_strcat (char *, size_t, const char *);
+char *safe_strncat (char *, size_t, const char *, size_t);
 char *safe_strdup (const char *);
 
 const char *mutt_stristr (const char *, const char *);
Index: mutt_ssl.c
===================================================================
RCS file: /cvs/mutt/mutt/mutt_ssl.c,v
retrieving revision 3.4
diff -u -p -r3.4 mutt_ssl.c
--- mutt_ssl.c  30 Aug 2004 20:05:40 -0000      3.4
+++ mutt_ssl.c  30 Oct 2004 21:39:19 -0000
@@ -417,7 +417,7 @@ static void x509_fingerprint (char *s, i
     {
       char ch[8];
       snprintf (ch, 8, "%02X%s", md[j], (j % 2 ? " " : ""));
-      strncat (s, ch, l);
+      safe_strcat (s, l, ch);
     }
   }
 }
@@ -629,9 +629,9 @@ static int ssl_check_certificate (sslsoc
   
   helpstr[0] = '\0';
   mutt_make_help (buf, sizeof (buf), _("Exit  "), MENU_GENERIC, OP_EXIT);
-  strncat (helpstr, buf, sizeof (helpstr));
+  safe_strcat (helpstr, sizeof (helpstr), buf);
   mutt_make_help (buf, sizeof (buf), _("Help"), MENU_GENERIC, OP_HELP);
-  strncat (helpstr, buf, sizeof (helpstr));
+  safe_strcat (helpstr, sizeof (helpstr), buf);
   menu->help = helpstr;
 
   done = 0;
Index: muttlib.c
===================================================================
RCS file: /cvs/mutt/mutt/muttlib.c,v
retrieving revision 3.24
diff -u -p -r3.24 muttlib.c
--- muttlib.c   30 Aug 2004 19:52:03 -0000      3.24
+++ muttlib.c   30 Oct 2004 21:39:21 -0000
@@ -815,8 +815,8 @@ void mutt_expand_fmt (char *dest, size_t
   
   if (!found && destlen > 0)
   {
-    strncat (dest, " ", destlen);
-    strncat (dest, src, destlen-1);
+    safe_strcat (dest, destlen, " ");
+    safe_strcat (dest, destlen, src);
   }
   
 }
Index: recvcmd.c
===================================================================
RCS file: /cvs/mutt/mutt/recvcmd.c,v
retrieving revision 3.6
diff -u -p -r3.6 recvcmd.c
--- recvcmd.c   9 Apr 2003 08:21:59 -0000       3.6
+++ recvcmd.c   30 Oct 2004 21:39:22 -0000
@@ -180,10 +180,10 @@ void mutt_attach_bounce (FILE * fp, HEAD
     mutt_format_string (prompt, sizeof (prompt) - 4,
                        0, COLS-extra_space, 0, 0,
                        prompt, sizeof (prompt), 0);
-    strncat (prompt, "...?", sizeof (prompt));
+    safe_strcat (prompt, sizeof (prompt), "...?");
   }
   else
-    strncat (prompt, "?", sizeof (prompt));
+    safe_strcat (prompt, sizeof (prompt), "?");
 
   if (query_quadoption (OPT_BOUNCE, prompt) != M_YES)
   {
Index: url.c
===================================================================
RCS file: /cvs/mutt/mutt/url.c,v
retrieving revision 3.5
diff -u -p -r3.5 url.c
--- url.c       20 Jul 2004 08:17:21 -0000      3.5
+++ url.c       30 Oct 2004 21:39:24 -0000
@@ -166,8 +166,11 @@ int url_parse_ciss (ciss_url_t *ciss, ch
 }
 
 /* url_ciss_tostring: output the URL string for a given CISS object. */
+
 int url_ciss_tostring (ciss_url_t* ciss, char* dest, size_t len, int flags)
 {
+  size_t l;
+
   if (ciss->scheme == U_UNKNOWN)
     return -1;
 
@@ -175,25 +178,26 @@ int url_ciss_tostring (ciss_url_t* ciss,
 
   if (ciss->host)
   {
-    strncat (dest, "//", len - strlen (dest));
+    safe_strcat (dest, len, "//");
+    len -= (l = strlen (dest)); dest += l;
+    
     if (ciss->user) {
       if (flags & U_DECODE_PASSWD && ciss->pass)
-       snprintf (dest + strlen (dest), len - strlen (dest), "%s:%s@",
-                 ciss->user, ciss->pass);
+       snprintf (dest, len, "%s:%s@", ciss->user, ciss->pass);
       else
-       snprintf (dest + strlen (dest), len - strlen (dest), "%s@",
-                 ciss->user);
+       snprintf (dest, len, "%s@", ciss->user);
+
+      len -= (l = strlen (dest)); dest += l;
     }
 
     if (ciss->port)
-      snprintf (dest + strlen (dest), len - strlen (dest), "%s:%hu/",
-               ciss->host, ciss->port);
+      snprintf (dest, len, "%s:%hu/", ciss->host, ciss->port);
     else
-      snprintf (dest + strlen (dest), len - strlen (dest), "%s/", ciss->host);
+      snprintf (dest, len, "%s/", ciss->host);
   }
 
   if (ciss->path)
-    strncat (dest, ciss->path, len - strlen (dest));
+    safe_strcat (dest, len, ciss->path);
 
   return 0;
 }
Index: imap/auth_cram.c
===================================================================
RCS file: /cvs/mutt/mutt/imap/auth_cram.c,v
retrieving revision 3.0
diff -u -p -r3.0 auth_cram.c
--- imap/auth_cram.c    24 Jan 2002 13:35:57 -0000      3.0
+++ imap/auth_cram.c    30 Oct 2004 21:39:25 -0000
@@ -104,7 +104,7 @@ imap_auth_res_t imap_auth_cram_md5 (IMAP
   
   mutt_to_base64 ((unsigned char*) ibuf, (unsigned char*) obuf, strlen (obuf),
                  sizeof (ibuf) - 2);
-  strncat (ibuf, "\r\n", sizeof (ibuf));
+  safe_strcat (ibuf, sizeof (ibuf), "\r\n");
   mutt_socket_write (idata->conn, ibuf);
 
   do
Index: imap/auth_gss.c
===================================================================
RCS file: /cvs/mutt/mutt/imap/auth_gss.c,v
retrieving revision 3.1
diff -u -p -r3.1 auth_gss.c
--- imap/auth_gss.c     12 Nov 2002 08:20:11 -0000      3.1
+++ imap/auth_gss.c     30 Oct 2004 21:39:25 -0000
@@ -122,7 +122,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA
   mutt_to_base64 ((unsigned char*) buf1, send_token.value, send_token.length,
     sizeof (buf1) - 2);
   gss_release_buffer (&min_stat, &send_token);
-  strncat (buf1, "\r\n", sizeof (buf1));
+  safe_strcat (buf1, sizeof (buf1), "\r\n");
   mutt_socket_write (idata->conn, buf1);
 
   while (maj_stat == GSS_S_CONTINUE_NEEDED)
@@ -158,7 +158,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA
     mutt_to_base64 ((unsigned char*) buf1, send_token.value,
       send_token.length, sizeof (buf1) - 2);
     gss_release_buffer (&min_stat, &send_token);
-    strncat (buf1, "\r\n", sizeof (buf1));
+    safe_strcat (buf1, sizeof (buf1), "\r\n");
     mutt_socket_write (idata->conn, buf1);
   }
 
@@ -226,7 +226,7 @@ imap_auth_res_t imap_auth_gss (IMAP_DATA
                  sizeof (buf1) - 2);
   dprint (2, (debugfile, "Requesting authorisation as %s\n",
     idata->conn->account.user));
-  strncat (buf1, "\r\n", sizeof (buf1));
+  safe_strcat (buf1, sizeof (buf1), "\r\n");
   mutt_socket_write (idata->conn, buf1);
 
   /* Joy of victory or agony of defeat? */
Index: imap/imap.c
===================================================================
RCS file: /cvs/mutt/mutt/imap/imap.c,v
retrieving revision 3.15
diff -u -p -r3.15 imap.c
--- imap/imap.c 16 Aug 2004 21:36:38 -0000      3.15
+++ imap/imap.c 30 Oct 2004 21:39:29 -0000
@@ -791,7 +791,7 @@ static void imap_set_flag (IMAP_DATA* id
 {
   if (mutt_bit_isset (idata->rights, aclbit))
     if (flag)
-      strncat (flags, str, flsize);
+      safe_strcat (flags, flsize, str);
 }
 
 /* imap_make_msg_set: make an IMAP4rev1 UID message set out of a set of
Index: imap/message.c
===================================================================
RCS file: /cvs/mutt/mutt/imap/message.c,v
retrieving revision 3.9
diff -u -p -r3.9 message.c
--- imap/message.c      22 Jul 2004 01:10:55 -0000      3.9
+++ imap/message.c      30 Oct 2004 21:39:30 -0000
@@ -663,8 +663,8 @@ void imap_add_keywords (char* s, HEADER*
   {
     if (msg_has_flag (mailbox_flags, keywords->data))
     {
-      strncat (s, keywords->data, slen);
-      strncat (s, " ", slen);
+      safe_strcat (s, slen, keywords->data);
+      safe_strcat (s, slen, " ");
     }
     keywords = keywords->next;
   }

Attachment: pgpLvlu30hqNt.pgp
Description: PGP signature