diff --git a/tar-1.15.1-hugeSparse.patch b/tar-1.15.1-hugeSparse.patch new file mode 100644 index 0000000..9b4ef2b --- /dev/null +++ b/tar-1.15.1-hugeSparse.patch @@ -0,0 +1,350 @@ +--- tar-1.15.1/src/sparse.c.hugeSparse 2006-03-22 13:18:53.000000000 -0500 ++++ tar-1.15.1/src/sparse.c 2006-03-22 13:24:54.000000000 -0500 +@@ -47,9 +47,9 @@ + { + int fd; /* File descriptor */ + bool seekable; /* Is fd seekable? */ +- size_t offset; /* Current offset in fd if seekable==false. ++ off_t offset; /* Current offset in fd if seekable==false. + Otherwise unused */ +- size_t dumped_size; /* Number of bytes actually written ++ off_t dumped_size; /* Number of bytes actually written + to the archive */ + struct tar_stat_info *stat_info; /* Information about the file */ + struct tar_sparse_optab *optab; +@@ -59,35 +59,34 @@ + + /* Dump zeros to file->fd until offset is reached. It is used instead of + lseek if the output file is not seekable */ +-static long ++static bool + dump_zeros (struct tar_sparse_file *file, off_t offset) + { +- char buf[BLOCKSIZE]; +- +- if (offset - file->offset < 0) ++ static char const zero_buf[BLOCKSIZE]; ++ ++ if (offset < file->offset) + { + errno = EINVAL; +- return -1; ++ return false; + } + +- memset (buf, 0, sizeof buf); + while (file->offset < offset) + { +- size_t size = offset - file->offset; +- size_t wrbytes; +- +- if (size > sizeof buf) +- size = sizeof buf; +- wrbytes = write (file->fd, buf, size); ++ size_t size = (BLOCKSIZE < offset - file->offset ++ ? BLOCKSIZE ++ : offset - file->offset); ++ ssize_t wrbytes; ++ ++ wrbytes = write (file->fd, zero_buf, size); + if (wrbytes <= 0) + { + if (wrbytes == 0) + errno = EINVAL; +- return -1; ++ return false; + } + file->offset += wrbytes; + } +- return file->offset; ++ return true; + } + + static bool +@@ -168,14 +167,9 @@ + static bool + lseek_or_error (struct tar_sparse_file *file, off_t offset) + { +- off_t off; +- +- if (file->seekable) +- off = lseek (file->fd, offset, SEEK_SET); +- else +- off = dump_zeros (file, offset); +- +- if (off < 0) ++ if (file->seekable ++ ? lseek (file->fd, offset, SEEK_SET) < 0 ++ : ! dump_zeros (file, offset)) + { + seek_diag_details (file->stat_info->orig_file_name, offset); + return false; +@@ -187,7 +181,7 @@ + it's made *entirely* of zeros, returning a 0 the instant it finds + something that is a nonzero, i.e., useful data. */ + static bool +-zero_block_p (char *buffer, size_t size) ++zero_block_p (char const *buffer, size_t size) + { + while (size--) + if (*buffer++) +@@ -195,50 +189,36 @@ + return true; + } + +-#define clear_block(p) memset (p, 0, BLOCKSIZE); +- +-#define SPARSES_INIT_COUNT SPARSES_IN_SPARSE_HEADER +- + static void +-sparse_add_map (struct tar_sparse_file *file, struct sp_array *sp) ++sparse_add_map (struct tar_stat_info *st, struct sp_array const *sp) + { +- if (file->stat_info->sparse_map == NULL) +- { +- file->stat_info->sparse_map = +- xmalloc (SPARSES_INIT_COUNT * sizeof file->stat_info->sparse_map[0]); +- file->stat_info->sparse_map_size = SPARSES_INIT_COUNT; +- } +- else if (file->stat_info->sparse_map_avail == file->stat_info->sparse_map_size) +- { +- file->stat_info->sparse_map_size *= 2; +- file->stat_info->sparse_map = +- xrealloc (file->stat_info->sparse_map, +- file->stat_info->sparse_map_size +- * sizeof file->stat_info->sparse_map[0]); +- } +- file->stat_info->sparse_map[file->stat_info->sparse_map_avail++] = *sp; ++ struct sp_array *sparse_map = st->sparse_map; ++ size_t avail = st->sparse_map_avail; ++ if (avail == st->sparse_map_size) ++ st->sparse_map = sparse_map = ++ x2nrealloc (sparse_map, &st->sparse_map_size, sizeof *sparse_map); ++ sparse_map[avail] = *sp; ++ st->sparse_map_avail = avail + 1; + } + + /* Scan the sparse file and create its map */ + static bool + sparse_scan_file (struct tar_sparse_file *file) + { +- static char buffer[BLOCKSIZE]; ++ struct tar_stat_info *st = file->stat_info; ++ int fd = file->fd; ++ char buffer[BLOCKSIZE]; + size_t count; + off_t offset = 0; + struct sp_array sp = {0, 0}; + + if (!lseek_or_error (file, 0)) + return false; +- clear_block (buffer); +- +- file->stat_info->sparse_map_avail = 0; +- file->stat_info->archive_file_size = 0; + + if (!tar_sparse_scan (file, scan_begin, NULL)) + return false; + +- while ((count = safe_read (file->fd, buffer, sizeof buffer)) != 0 ++ while ((count = safe_read (fd, buffer, sizeof buffer)) != 0 + && count != SAFE_READ_ERROR) + { + /* Analize the block */ +@@ -246,7 +226,7 @@ + { + if (sp.numbytes) + { +- sparse_add_map (file, &sp); ++ sparse_add_map (st, &sp); + sp.numbytes = 0; + if (!tar_sparse_scan (file, scan_block, NULL)) + return false; +@@ -257,26 +237,25 @@ + if (sp.numbytes == 0) + sp.offset = offset; + sp.numbytes += count; +- file->stat_info->archive_file_size += count; ++ st->archive_file_size += count; + if (!tar_sparse_scan (file, scan_block, buffer)) + return false; + } + + offset += count; +- clear_block (buffer); + } + + if (sp.numbytes == 0) + sp.offset = offset; + +- sparse_add_map (file, &sp); +- file->stat_info->archive_file_size += count; ++ sparse_add_map (st, &sp); ++ st->archive_file_size += count; + return tar_sparse_scan (file, scan_end, NULL); + } + +-static struct tar_sparse_optab oldgnu_optab; +-static struct tar_sparse_optab star_optab; +-static struct tar_sparse_optab pax_optab; ++static struct tar_sparse_optab const oldgnu_optab; ++static struct tar_sparse_optab const star_optab; ++static struct tar_sparse_optab const pax_optab; + + static bool + sparse_select_optab (struct tar_sparse_file *file) +@@ -321,18 +300,18 @@ + size_t bytes_read; + + blk = find_next_block (); +- memset (blk->buffer, 0, BLOCKSIZE); + bytes_read = safe_read (file->fd, blk->buffer, bufsize); + if (bytes_read == SAFE_READ_ERROR) + { + read_diag_details (file->stat_info->orig_file_name, +- file->stat_info->sparse_map[i].offset +- + file->stat_info->sparse_map[i].numbytes +- - bytes_left, +- bufsize); ++ (file->stat_info->sparse_map[i].offset ++ + file->stat_info->sparse_map[i].numbytes ++ - bytes_left), ++ bufsize); + return false; + } + ++ memset (blk->buffer + bytes_read, 0, BLOCKSIZE - bytes_read); + bytes_left -= bytes_read; + file->dumped_size += bytes_read; + set_next_block_after (blk); +@@ -389,12 +368,11 @@ + sparse_dump_file (int fd, struct tar_stat_info *st) + { + bool rc; +- struct tar_sparse_file file; ++ struct tar_sparse_file file = { 0, }; + + file.stat_info = st; + file.fd = fd; + file.seekable = true; /* File *must* be seekable for dump to work */ +- file.offset = 0; + + if (!sparse_select_optab (&file) + || !tar_sparse_init (&file)) +@@ -456,15 +434,14 @@ + struct tar_sparse_file file; + size_t i; + ++ if (!tar_sparse_init (&file)) ++ return dump_status_not_implemented; ++ + file.stat_info = st; + file.fd = fd; + file.seekable = lseek (fd, 0, SEEK_SET) == 0; + file.offset = 0; + +- if (!sparse_select_optab (&file) +- || !tar_sparse_init (&file)) +- return dump_status_not_implemented; +- + rc = tar_sparse_decode_header (&file); + for (i = 0; rc && i < file.stat_info->sparse_map_avail; i++) + rc = tar_sparse_extract_region (&file, i); +@@ -491,8 +468,6 @@ + } + + +-static char diff_buffer[BLOCKSIZE]; +- + static bool + check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end) + { +@@ -502,11 +477,9 @@ + while (beg < end) + { + size_t bytes_read; +- size_t rdsize = end - beg; ++ size_t rdsize = BLOCKSIZE < end - beg ? BLOCKSIZE : end - beg; ++ char diff_buffer[BLOCKSIZE]; + +- if (rdsize > BLOCKSIZE) +- rdsize = BLOCKSIZE; +- clear_block (diff_buffer); + bytes_read = safe_read (file->fd, diff_buffer, rdsize); + if (bytes_read == SAFE_READ_ERROR) + { +@@ -539,6 +512,7 @@ + { + size_t bytes_read; + size_t rdsize = (size_left > BLOCKSIZE) ? BLOCKSIZE : size_left; ++ char diff_buffer[BLOCKSIZE]; + + union block *blk = find_next_block (); + if (!blk) +@@ -551,9 +525,9 @@ + if (bytes_read == SAFE_READ_ERROR) + { + read_diag_details (file->stat_info->orig_file_name, +- file->stat_info->sparse_map[i].offset +- + file->stat_info->sparse_map[i].numbytes +- - size_left, ++ (file->stat_info->sparse_map[i].offset ++ + file->stat_info->sparse_map[i].numbytes ++ - size_left), + rdsize); + return false; + } +@@ -647,7 +621,7 @@ + || file->stat_info->archive_file_size < 0) + return add_fail; + +- sparse_add_map (file, &sp); ++ sparse_add_map (file->stat_info, &sp); + return add_ok; + } + +@@ -669,7 +643,7 @@ + size_t i; + union block *h = current_header; + int ext_p; +- static enum oldgnu_add_status rc; ++ enum oldgnu_add_status rc; + + file->stat_info->sparse_map_avail = 0; + for (i = 0; i < SPARSES_IN_OLDGNU_HEADER; i++) +@@ -756,7 +730,7 @@ + return true; + } + +-static struct tar_sparse_optab oldgnu_optab = { ++static struct tar_sparse_optab const oldgnu_optab = { + NULL, /* No init function */ + NULL, /* No done function */ + oldgnu_sparse_member_p, +@@ -795,7 +769,7 @@ + size_t i; + union block *h = current_header; + int ext_p; +- static enum oldgnu_add_status rc; ++ enum oldgnu_add_status rc; + + file->stat_info->sparse_map_avail = 0; + +@@ -837,7 +811,7 @@ + } + + +-static struct tar_sparse_optab star_optab = { ++static struct tar_sparse_optab const star_optab = { + NULL, /* No init function */ + NULL, /* No done function */ + star_sparse_member_p, +@@ -890,7 +864,7 @@ + return true; + } + +-static struct tar_sparse_optab pax_optab = { ++static struct tar_sparse_optab const pax_optab = { + NULL, /* No init function */ + NULL, /* No done function */ + pax_sparse_member_p, diff --git a/tar.spec b/tar.spec index 6123d48..9fcc25c 100644 --- a/tar.spec +++ b/tar.spec @@ -1,7 +1,7 @@ Summary: A GNU file archiving program. Name: tar Version: 1.15.1 -Release: 13 +Release: 14 License: GPL Group: Applications/Archiving URL: http://www.gnu.org/software/tar/ @@ -18,6 +18,7 @@ Patch13: tar-1.15.1-newerOption.patch Patch14: tar-1.15.1-padCorrectly.patch Patch15: tar-1.15.1-vfatTruncate.patch Patch16: tar-1.15.1-heapOverflow.patch +Patch17: tar-1.15.1-hugeSparse.patch Prereq: info BuildRequires: autoconf automake gzip @@ -47,6 +48,7 @@ the rmt package. %patch14 -p1 -b .padCorrectly %patch15 -p1 -b .vfatTruncate %patch16 -p0 -b .heapOverflow +%patch17 -p1 -b .hugeSparse %build @@ -117,6 +119,9 @@ fi %{_infodir}/tar.info* %changelog +* Wed Mar 22 2006 Peter Vrabec 1.15.1-14 +- fix problems with extracting large sparse archive members (#185460) + * Fri Feb 17 2006 Peter Vrabec 1.15.1-13 - fix heap overlfow bug CVE-2006-0300 (#181773)