From c7c59b57faa7bd60063f38d3517a8ad50fe1c430 Mon Sep 17 00:00:00 2001
From: Sergey Poznyakoff <gray@gnu.org>
Date: Thu, 20 Dec 2018 20:30:58 +0200
Subject: [PATCH 33/58] Fix buffer overflow

Bug reported in
  http://lists.gnu.org/archive/html/bug-tar/2018-12/msg00011.html

* src/xheader.c (xheader_format_name): fix length calculation
---
 src/xheader.c | 70 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 39 insertions(+), 31 deletions(-)

diff --git a/src/xheader.c b/src/xheader.c
index 6d97131..980f050 100644
--- a/src/xheader.c
+++ b/src/xheader.c
@@ -255,7 +255,7 @@ char *
 xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
 {
   char *buf;
-  size_t len = strlen (fmt);
+  size_t len;
   char *q;
   const char *p;
   char *dirp = NULL;
@@ -266,43 +266,51 @@ xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
   char nbuf[UINTMAX_STRSIZE_BOUND];
   char const *nptr = NULL;
 
-  for (p = fmt; *p && (p = strchr (p, '%')); )
+  len = 0;
+  for (p = fmt; *p; p++)
     {
-      switch (p[1])
+      if (*p == '%' && p[1])
 	{
-	case '%':
-	  len--;
-	  break;
-
-	case 'd':
-	  if (st)
+	  switch (*++p)
 	    {
-	      if (!dirp)
-		dirp = dir_name (st->orig_file_name);
-	      dir = safer_name_suffix (dirp, false, absolute_names_option);
-	      len += strlen (dir) - 2;
-	    }
-	  break;
+	    case '%':
+	      len++;
+	      break;
 
-	case 'f':
-	  if (st)
-	    {
-	      base = last_component (st->orig_file_name);
-	      len += strlen (base) - 2;
-	    }
-	  break;
+	    case 'd':
+	      if (st)
+		{
+		  if (!dirp)
+		    dirp = dir_name (st->orig_file_name);
+		  dir = safer_name_suffix (dirp, false, absolute_names_option);
+		  len += strlen (dir);
+		}
+	      break;
 
-	case 'p':
-	  pptr = umaxtostr (getpid (), pidbuf);
-	  len += pidbuf + sizeof pidbuf - 1 - pptr - 2;
-	  break;
+	    case 'f':
+	      if (st)
+		{
+		  base = last_component (st->orig_file_name);
+		  len += strlen (base);
+		}
+	      break;
 
-	case 'n':
-	  nptr = umaxtostr (n, nbuf);
-	  len += nbuf + sizeof nbuf - 1 - nptr - 2;
-	  break;
+	    case 'p':
+	      pptr = umaxtostr (getpid (), pidbuf);
+	      len += pidbuf + sizeof pidbuf - 1 - pptr;
+	      break;
+
+	    case 'n':
+	      nptr = umaxtostr (n, nbuf);
+	      len += nbuf + sizeof nbuf - 1 - nptr;
+	      break;
+	      
+	    default:
+	      len += 2;
+	    }
 	}
-      p++;
+      else
+	len++;
     }
 
   buf = xmalloc (len + 1);
-- 
2.19.1

