diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-12-20 20:30:58 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-12-21 13:54:11 +0200 |
commit | c7c59b57faa7bd60063f38d3517a8ad50fe1c430 (patch) | |
tree | 5ae2e28de412b5e759ec019572b51ff8e2df7556 | |
parent | eae48289c0848c5812644f20dbb1b39fb117a8f6 (diff) | |
download | tar-c7c59b57faa7bd60063f38d3517a8ad50fe1c430.tar.gz tar-c7c59b57faa7bd60063f38d3517a8ad50fe1c430.tar.bz2 |
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
-rw-r--r-- | src/xheader.c | 70 |
1 files changed, 39 insertions, 31 deletions
diff --git a/src/xheader.c b/src/xheader.c index 6d97131d..980f0504 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); |