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 <stdint.h>, 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.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
16
src/sparse.c
16
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));
|
||||
|
||||
@@ -265,7 +265,7 @@ enum archive_format
|
||||
struct sp_array
|
||||
{
|
||||
off_t offset;
|
||||
size_t numbytes;
|
||||
off_t numbytes;
|
||||
};
|
||||
|
||||
struct xheader
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user