From d0201294c0978972fa1ce303d4b56de5cef48ee3 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Sat, 24 Jun 2006 16:49:33 +0000 Subject: [PATCH] (xhdr_tab.decoder): pass keyword as a second argument. All callers changed. (decode_record): Check for numeric overflow (xheader_string_end): Return boolean value. Check for possible numeric overflow --- src/xheader.c | 170 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 117 insertions(+), 53 deletions(-) diff --git a/src/xheader.c b/src/xheader.c index 0896043..f5e1199 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -430,7 +430,7 @@ struct xhdr_tab char const *keyword; void (*coder) (struct tar_stat_info const *, char const *, struct xheader *, void const *data); - void (*decoder) (struct tar_stat_info *, char const *, size_t); + void (*decoder) (struct tar_stat_info *, char const *, char const *, size_t); bool protect; }; @@ -484,7 +484,8 @@ decode_record (char **ptr, { char *start = *ptr; char *p = start; - unsigned long int len; + uintmax_t u; + size_t len; char *len_lim; char const *keyword; char *nextp; @@ -501,8 +502,13 @@ decode_record (char **ptr, } errno = 0; - len = strtoul (p, &len_lim, 10); - + len = u = strtoumax (p, &len_lim, 10); + if (len != u || errno == ERANGE) + { + ERROR ((0, 0, _("Extended header length is out of allowed range"))); + return false; + } + if (len_max < len) { int len_len = len_lim - p; @@ -551,7 +557,7 @@ run_override_list (struct keyword_list *kp, struct tar_stat_info *st) { struct xhdr_tab const *t = locate_handler (kp->pattern); if (t) - t->decoder (st, kp->value, strlen (kp->value)); + t->decoder (st, t->keyword, kp->value, strlen (kp->value)); } } @@ -567,7 +573,7 @@ decx (void *data, char const *keyword, char const *value, size_t size) t = locate_handler (keyword); if (t) - t->decoder (st, value, size); + t->decoder (st, keyword, value, size); else ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"), keyword)); @@ -746,18 +752,19 @@ xheader_string_add (char const *s) x_obstack_grow (&extended_header, s, strlen (s)); } -void +bool xheader_string_end (char const *keyword) { - size_t len; - size_t p; - size_t n = 0; + uintmax_t len; + uintmax_t p; + uintmax_t n = 0; + size_t size; char nbuf[UINTMAX_STRSIZE_BOUND]; char const *np; char *cp; if (extended_header.buffer) - return; + return false; extended_header_init (); len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */ @@ -771,6 +778,15 @@ xheader_string_end (char const *keyword) while (n != p); p = strlen (keyword) + n + 2; + size = p; + if (size != p) + { + ERROR ((0, 0, + _("Generated keyword/value pair is too long (keyword=%s, length=%s"), + keyword, nbuf)); + obstack_free (extended_header.stk, obstack_finish (extended_header.stk)); + return false; + } x_obstack_blank (&extended_header, p); x_obstack_1grow (&extended_header, '\n'); cp = obstack_next_free (extended_header.stk) - string_length - p - 1; @@ -779,6 +795,7 @@ xheader_string_end (char const *keyword) *cp++ = ' '; cp = stpcpy (cp, keyword); *cp++ = '='; + return true; } @@ -983,6 +1000,7 @@ dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)), static void dummy_decoder (struct tar_stat_info *st __attribute__ ((unused)), + char const *keyword __attribute__ ((unused)), char const *arg __attribute__ ((unused)), size_t size __attribute__((unused))) { @@ -996,11 +1014,13 @@ atime_coder (struct tar_stat_info const *st, char const *keyword, } static void -atime_decoder (struct tar_stat_info *st, char const *arg, +atime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "atime")) + if (decode_time (&ts, arg, keyword)) st->atime = ts; } @@ -1012,11 +1032,13 @@ gid_coder (struct tar_stat_info const *st, char const *keyword, } static void -gid_decoder (struct tar_stat_info *st, char const *arg, +gid_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), "gid")) + if (decode_num (&u, arg, TYPE_MAXIMUM (gid_t), keyword)) st->stat.st_gid = u; } @@ -1028,7 +1050,9 @@ gname_coder (struct tar_stat_info const *st, char const *keyword, } static void -gname_decoder (struct tar_stat_info *st, char const *arg, +gname_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->gname, arg); @@ -1042,7 +1066,9 @@ linkpath_coder (struct tar_stat_info const *st, char const *keyword, } static void -linkpath_decoder (struct tar_stat_info *st, char const *arg, +linkpath_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->link_name, arg); @@ -1056,11 +1082,13 @@ ctime_coder (struct tar_stat_info const *st, char const *keyword, } static void -ctime_decoder (struct tar_stat_info *st, char const *arg, +ctime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "ctime")) + if (decode_time (&ts, arg, keyword)) st->ctime = ts; } @@ -1072,11 +1100,13 @@ mtime_coder (struct tar_stat_info const *st, char const *keyword, } static void -mtime_decoder (struct tar_stat_info *st, char const *arg, +mtime_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { struct timespec ts; - if (decode_time (&ts, arg, "mtime")) + if (decode_time (&ts, arg, keyword)) st->mtime = ts; } @@ -1088,7 +1118,9 @@ path_coder (struct tar_stat_info const *st, char const *keyword, } static void -path_decoder (struct tar_stat_info *st, char const *arg, +path_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->orig_file_name, arg); @@ -1104,11 +1136,13 @@ size_coder (struct tar_stat_info const *st, char const *keyword, } static void -size_decoder (struct tar_stat_info *st, char const *arg, +size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) st->stat.st_size = u; } @@ -1120,11 +1154,13 @@ uid_coder (struct tar_stat_info const *st, char const *keyword, } static void -uid_decoder (struct tar_stat_info *st, char const *arg, +uid_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), "uid")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uid_t), keyword)) st->stat.st_uid = u; } @@ -1136,7 +1172,9 @@ uname_coder (struct tar_stat_info const *st, char const *keyword, } static void -uname_decoder (struct tar_stat_info *st, char const *arg, +uname_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size __attribute__((unused))) { decode_string (&st->uname, arg); @@ -1150,11 +1188,13 @@ sparse_size_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_size_decoder (struct tar_stat_info *st, char const *arg, +sparse_size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) st->stat.st_size = u; } @@ -1167,11 +1207,13 @@ sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_numblocks_decoder (struct tar_stat_info *st, char const *arg, +sparse_numblocks_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numblocks")) + if (decode_num (&u, arg, SIZE_MAX, keyword)) { st->sparse_map_size = u; st->sparse_map = xcalloc (u, sizeof st->sparse_map[0]); @@ -1188,11 +1230,13 @@ sparse_offset_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_offset_decoder (struct tar_stat_info *st, char const *arg, +sparse_offset_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), "GNU.sparse.offset")) + if (decode_num (&u, arg, TYPE_MAXIMUM (off_t), keyword)) { if (st->sparse_map_avail < st->sparse_map_size) st->sparse_map[st->sparse_map_avail].offset = u; @@ -1211,26 +1255,29 @@ sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_numbytes_decoder (struct tar_stat_info *st, char const *arg, +sparse_numbytes_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, SIZE_MAX, "GNU.sparse.numbytes")) + if (decode_num (&u, arg, SIZE_MAX, keyword)) { if (st->sparse_map_avail < st->sparse_map_size) st->sparse_map[st->sparse_map_avail++].numbytes = u; else ERROR ((0, 0, _("Malformed extended header: excess %s=%s"), - "GNU.sparse.numbytes", arg)); + keyword, arg)); } } static void -sparse_map_decoder (struct tar_stat_info *st, char const *arg, +sparse_map_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size __attribute__((unused))) { int offset = 1; - static char *keyword = "GNU.sparse.map"; st->sparse_map_avail = 0; while (1) @@ -1304,7 +1351,9 @@ dumpdir_coder (struct tar_stat_info const *st, char const *keyword, } static void -dumpdir_decoder (struct tar_stat_info *st, char const *arg, +dumpdir_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, size_t size) { st->dumpdir = xmalloc (size); @@ -1319,7 +1368,10 @@ volume_label_coder (struct tar_stat_info const *st, char const *keyword, } static void -volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_label_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, + size_t size __attribute__((unused))) { decode_string (&volume_label, arg); } @@ -1333,10 +1385,12 @@ volume_size_coder (struct tar_stat_info const *st, char const *keyword, } static void -volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_size_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword)) continued_file_size = u; } @@ -1350,16 +1404,20 @@ volume_offset_coder (struct tar_stat_info const *st, char const *keyword, } static void -volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size) +volume_offset_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset")) + if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), keyword)) continued_file_offset = u; } static void -volume_filename_decoder (struct tar_stat_info *st, char const *arg, - size_t size) +volume_filename_decoder (struct tar_stat_info *st, + char const *keyword __attribute__((unused)), + char const *arg, + size_t size __attribute__((unused))) { decode_string (&continued_file_name, arg); } @@ -1372,11 +1430,13 @@ sparse_major_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_major_decoder (struct tar_stat_info *st, char const *arg, +sparse_major_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.major")) + if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword)) st->sparse_major = u; } @@ -1388,11 +1448,13 @@ sparse_minor_coder (struct tar_stat_info const *st, char const *keyword, } static void -sparse_minor_decoder (struct tar_stat_info *st, char const *arg, +sparse_minor_decoder (struct tar_stat_info *st, + char const *keyword, + char const *arg, size_t size) { uintmax_t u; - if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.minor")) + if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword)) st->sparse_minor = u; } @@ -1417,11 +1479,13 @@ struct xhdr_tab const xhdr_tab[] = { true }, { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder, true }, - { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, true }, - - { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, + { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, + true }, { "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder, true }, + + /* tar 1.14 - 1.15.90 keywords. */ + { "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true }, /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x' headers, and each of them was meaningful. It confilcted with POSIX specs, which requires that "when extended header records conflict, the last one -- 2.45.2