From a59c819beb4886ee43f16dfd80ec1151fda1abe6 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 24 Aug 2010 16:50:31 -0700 Subject: [PATCH] tar: don't assume size of a sparse file chunk fits in size_t * src/tar.h (struct sp_array): Change numbytes from size_t to off_t. All uses changed. * scripts/xsparse.c (struct sp_array): Likewise. Include , for SIZE_MAX. (expand_sparse): Don't try to allocate a buffer bigger than SIZE_MAX bytes. * src/common.h (SIZE_TO_CHARS, size_to_chars, SIZE_FROM_HEADER): (size_from_header): Remove decls. * src/create.c (size_to_chars): Remove. * src/list.c (size_from_header): Remove. * src/sparse.c (sparse_extract_region, check_data_region): (oldgnu_add_sparse, oldgnu_store_sparse_info, pax_decode_header): Don't assume chunk sizes fit in size_t. (oldgnu_add_sparse): Check for off_t overflow. * src/xheader.c (sparse_numbytes_decoder, sparse_map_decoder): Likewise. --- scripts/xsparse.c | 22 +++++++++++++--------- src/common.h | 4 ---- src/create.c | 6 ------ src/list.c | 7 ------- src/sparse.c | 16 +++++++++------- src/tar.h | 2 +- src/xheader.c | 4 ++-- 7 files changed, 25 insertions(+), 36 deletions(-) diff --git a/scripts/xsparse.c b/scripts/xsparse.c index fd91b48..14d5658 100644 --- a/scripts/xsparse.c +++ b/scripts/xsparse.c @@ -1,7 +1,7 @@ /* xsparse - expands compressed sparse file images extracted from GNU tar archives. - Copyright (C) 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc. Written by Sergey Poznyakoff @@ -20,6 +20,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#include #include #include #include @@ -39,7 +40,7 @@ struct sp_array { off_t offset; - size_t numbytes; + off_t numbytes; }; char *progname; @@ -226,7 +227,7 @@ read_xheader (char *name) } else if (strcmp (kw, "numbytes") == 0) { - sparse_map[i++].numbytes = string_to_size (val, NULL); + sparse_map[i++].numbytes = string_to_off (val, NULL); } else if (strcmp (kw, "map") == 0) { @@ -236,7 +237,7 @@ read_xheader (char *name) if (*val != ',') die (1, "bad GNU.sparse.map: expected `,' but found `%c'", *val); - sparse_map[i].numbytes = string_to_size (val+1, &val); + sparse_map[i].numbytes = string_to_off (val+1, &val); if (*val != ',') { if (!(*val == 0 && i == sparse_map_size-1)) @@ -277,7 +278,7 @@ read_map (FILE *ifp) get_line (nbuf, sizeof nbuf, ifp); sparse_map[i].offset = string_to_off (nbuf, NULL); get_line (nbuf, sizeof nbuf, ifp); - sparse_map[i].numbytes = string_to_size (nbuf, NULL); + sparse_map[i].numbytes = string_to_off (nbuf, NULL); } fseeko (ifp, ((ftell (ifp) + BLOCKSIZE - 1) / BLOCKSIZE) * BLOCKSIZE, @@ -288,12 +289,15 @@ void expand_sparse (FILE *sfp, int ofd) { size_t i; - size_t maxbytes = 0; + off_t max_numbytes = 0; + size_t maxbytes; char *buffer; for (i = 0; i < sparse_map_size; i++) - if (maxbytes < sparse_map[i].numbytes) - maxbytes = sparse_map[i].numbytes; + if (max_numbytes < sparse_map[i].numbytes) + max_numbytes = sparse_map[i].numbytes; + + maxbytes = max_numbytes < SIZE_MAX ? max_numbytes : SIZE_MAX; for (buffer = malloc (maxbytes); !buffer; maxbytes /= 2) if (maxbytes == 0) @@ -301,7 +305,7 @@ expand_sparse (FILE *sfp, int ofd) for (i = 0; i < sparse_map_size; i++) { - size_t size = sparse_map[i].numbytes; + off_t size = sparse_map[i].numbytes; if (size == 0) ftruncate (ofd, sparse_map[i].offset); diff --git a/src/common.h b/src/common.h index 9d0b779..f6f3844 100644 --- a/src/common.h +++ b/src/common.h @@ -467,11 +467,9 @@ enum exclusion_tag_type check_exclusion_tags (const char *dirname, const char **tag_file_name); #define OFF_TO_CHARS(val, where) off_to_chars (val, where, sizeof (where)) -#define SIZE_TO_CHARS(val, where) size_to_chars (val, where, sizeof (where)) #define TIME_TO_CHARS(val, where) time_to_chars (val, where, sizeof (where)) bool off_to_chars (off_t off, char *buf, size_t size); -bool size_to_chars (size_t v, char *buf, size_t size); bool time_to_chars (time_t t, char *buf, size_t size); /* Module diffarch.c. */ @@ -547,11 +545,9 @@ void decode_header (union block *header, struct tar_stat_info *stat_info, char const *tartime (struct timespec t, bool full_time); #define OFF_FROM_HEADER(where) off_from_header (where, sizeof (where)) -#define SIZE_FROM_HEADER(where) size_from_header (where, sizeof (where)) #define UINTMAX_FROM_HEADER(where) uintmax_from_header (where, sizeof (where)) off_t off_from_header (const char *buf, size_t size); -size_t size_from_header (const char *buf, size_t size); uintmax_t uintmax_from_header (const char *buf, size_t size); void list_archive (void); diff --git a/src/create.c b/src/create.c index 0a6bacf..2ca1d6e 100644 --- a/src/create.c +++ b/src/create.c @@ -440,12 +440,6 @@ off_to_chars (off_t v, char *p, size_t s) return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t"); } -bool -size_to_chars (size_t v, char *p, size_t s) -{ - return to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t"); -} - bool time_to_chars (time_t v, char *p, size_t s) { diff --git a/src/list.c b/src/list.c index f0d3d5a..e1e5bf2 100644 --- a/src/list.c +++ b/src/list.c @@ -946,13 +946,6 @@ off_from_header (const char *p, size_t s) (uintmax_t) TYPE_MAXIMUM (off_t), false, false); } -size_t -size_from_header (const char *p, size_t s) -{ - return from_header (p, s, "size_t", (uintmax_t) 0, - (uintmax_t) TYPE_MAXIMUM (size_t), false, false); -} - static time_t time_from_header (const char *p, size_t s) { diff --git a/src/sparse.c b/src/sparse.c index 67e5a85..8af4b47 100644 --- a/src/sparse.c +++ b/src/sparse.c @@ -1,6 +1,7 @@ /* Functions for dealing with sparse files - Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 Free Software + Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -333,7 +334,7 @@ sparse_dump_region (struct tar_sparse_file *file, size_t i) static bool sparse_extract_region (struct tar_sparse_file *file, size_t i) { - size_t write_size; + off_t write_size; if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) return false; @@ -508,7 +509,7 @@ check_sparse_region (struct tar_sparse_file *file, off_t beg, off_t end) static bool check_data_region (struct tar_sparse_file *file, size_t i) { - size_t size_left; + off_t size_left; if (!lseek_or_error (file, file->stat_info->sparse_map[i].offset)) return false; @@ -625,8 +626,9 @@ oldgnu_add_sparse (struct tar_sparse_file *file, struct sparse *s) if (s->numbytes[0] == '\0') return add_finish; sp.offset = OFF_FROM_HEADER (s->offset); - sp.numbytes = SIZE_FROM_HEADER (s->numbytes); + sp.numbytes = OFF_FROM_HEADER (s->numbytes); if (sp.offset < 0 + || sp.offset + sp.numbytes < 0 || file->stat_info->stat.st_size < sp.offset + sp.numbytes || file->stat_info->archive_file_size < 0) return add_fail; @@ -695,8 +697,8 @@ oldgnu_store_sparse_info (struct tar_sparse_file *file, size_t *pindex, { OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].offset, sp->offset); - SIZE_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes, - sp->numbytes); + OFF_TO_CHARS (file->stat_info->sparse_map[*pindex].numbytes, + sp->numbytes); } } @@ -1147,7 +1149,7 @@ pax_decode_header (struct tar_sparse_file *file) } sp.offset = u; COPY_BUF (blk,nbuf,p); - if (!decode_num (&u, nbuf, TYPE_MAXIMUM (size_t))) + if (!decode_num (&u, nbuf, TYPE_MAXIMUM (off_t))) { ERROR ((0, 0, _("%s: malformed sparse archive member"), file->stat_info->orig_file_name)); diff --git a/src/tar.h b/src/tar.h index 08ccab3..fddc83f 100644 --- a/src/tar.h +++ b/src/tar.h @@ -265,7 +265,7 @@ enum archive_format struct sp_array { off_t offset; - size_t numbytes; + off_t numbytes; }; struct xheader diff --git a/src/xheader.c b/src/xheader.c index 42656bf..2284e97 100644 --- a/src/xheader.c +++ b/src/xheader.c @@ -1308,7 +1308,7 @@ sparse_numbytes_decoder (struct tar_stat_info *st, size_t size __attribute__((unused))) { uintmax_t u; - if (decode_num (&u, arg, SIZE_MAX, keyword)) + 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++].numbytes = u; @@ -1356,7 +1356,7 @@ sparse_map_decoder (struct tar_stat_info *st, e.numbytes = u; if (!(u == e.numbytes && errno != ERANGE)) { - out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (size_t)); + out_of_range_header (keyword, arg, 0, TYPE_MAXIMUM (off_t)); return; } if (st->sparse_map_avail < st->sparse_map_size) -- 2.45.2