libsparse: Fix overflow of merged sparse chunk length

Merging sparse chunk can make sparse map block bigger than 4GiB,
that can't be covered by unsigned integer type. Fix this by
changing unsigned int to uint64_t type.

Test: sparse build
Bug: 162808120
Change-Id: Id4d3f88f9d531c25c3937c99b2c81efb915605ee
Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
Cc: hyeongseok.kim <hyeongseok.kim@lge.com>
This commit is contained in:
Hyeongseok Kim 2020-08-10 12:11:57 +09:00
parent 52c8422ea1
commit e8d02c50d7
6 changed files with 47 additions and 48 deletions

View file

@ -25,7 +25,7 @@
struct backed_block {
unsigned int block;
unsigned int len;
uint64_t len;
enum backed_block_type type;
union {
struct {
@ -60,7 +60,7 @@ struct backed_block* backed_block_iter_next(struct backed_block* bb) {
return bb->next;
}
unsigned int backed_block_len(struct backed_block* bb) {
uint64_t backed_block_len(struct backed_block* bb) {
return bb->len;
}
@ -270,7 +270,7 @@ static int queue_bb(struct backed_block_list* bbl, struct backed_block* new_bb)
}
/* Queues a fill block of memory to be written to the specified data blocks */
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
@ -287,7 +287,7 @@ int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val,
}
/* Queues a block of memory to be written to the specified data blocks */
int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
@ -305,7 +305,7 @@ int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned in
/* Queues a chunk of a file on disk to be written to the specified data blocks */
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
unsigned int len, unsigned int block) {
uint64_t len, unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {
return -ENOMEM;
@ -322,7 +322,7 @@ int backed_block_add_file(struct backed_block_list* bbl, const char* filename, i
}
/* Queues a chunk of a fd to be written to the specified data blocks */
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
unsigned int block) {
struct backed_block* bb = reinterpret_cast<backed_block*>(calloc(1, sizeof(struct backed_block)));
if (bb == nullptr) {

View file

@ -29,18 +29,18 @@ enum backed_block_type {
BACKED_BLOCK_FILL,
};
int backed_block_add_data(struct backed_block_list* bbl, void* data, unsigned int len,
int backed_block_add_data(struct backed_block_list* bbl, void* data, uint64_t len,
unsigned int block);
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, unsigned int len,
int backed_block_add_fill(struct backed_block_list* bbl, unsigned int fill_val, uint64_t len,
unsigned int block);
int backed_block_add_file(struct backed_block_list* bbl, const char* filename, int64_t offset,
unsigned int len, unsigned int block);
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, unsigned int len,
uint64_t len, unsigned int block);
int backed_block_add_fd(struct backed_block_list* bbl, int fd, int64_t offset, uint64_t len,
unsigned int block);
struct backed_block* backed_block_iter_new(struct backed_block_list* bbl);
struct backed_block* backed_block_iter_next(struct backed_block* bb);
unsigned int backed_block_len(struct backed_block* bb);
uint64_t backed_block_len(struct backed_block* bb);
unsigned int backed_block_block(struct backed_block* bb);
void* backed_block_data(struct backed_block* bb);
const char* backed_block_filename(struct backed_block* bb);

View file

@ -75,8 +75,7 @@ void sparse_file_destroy(struct sparse_file *s);
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_data(struct sparse_file *s,
void *data, unsigned int len, unsigned int block);
int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block);
/**
* sparse_file_add_fill - associate a fill chunk with a sparse file
@ -93,8 +92,8 @@ int sparse_file_add_data(struct sparse_file *s,
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_fill(struct sparse_file *s,
uint32_t fill_val, unsigned int len, unsigned int block);
int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
@ -116,9 +115,8 @@ int sparse_file_add_fill(struct sparse_file *s,
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_file(struct sparse_file *s,
const char *filename, int64_t file_offset, unsigned int len,
unsigned int block);
int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
uint64_t len, unsigned int block);
/**
* sparse_file_add_file - associate a chunk of a file with a sparse file
@ -143,8 +141,8 @@ int sparse_file_add_file(struct sparse_file *s,
*
* Returns 0 on success, negative errno on error.
*/
int sparse_file_add_fd(struct sparse_file *s,
int fd, int64_t file_offset, unsigned int len, unsigned int block);
int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
unsigned int block);
/**
* sparse_file_write - write a sparse file to a file

View file

@ -65,9 +65,9 @@ struct output_file_ops {
};
struct sparse_file_ops {
int (*write_data_chunk)(struct output_file* out, unsigned int len, void* data);
int (*write_fill_chunk)(struct output_file* out, unsigned int len, uint32_t fill_val);
int (*write_skip_chunk)(struct output_file* out, int64_t len);
int (*write_data_chunk)(struct output_file* out, uint64_t len, void* data);
int (*write_fill_chunk)(struct output_file* out, uint64_t len, uint32_t fill_val);
int (*write_skip_chunk)(struct output_file* out, uint64_t len);
int (*write_end_chunk)(struct output_file* out);
};
@ -316,7 +316,7 @@ int read_all(int fd, void* buf, size_t len) {
return 0;
}
static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
static int write_sparse_skip_chunk(struct output_file* out, uint64_t skip_len) {
chunk_header_t chunk_header;
int ret;
@ -340,9 +340,10 @@ static int write_sparse_skip_chunk(struct output_file* out, int64_t skip_len) {
return 0;
}
static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
static int write_sparse_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
chunk_header_t chunk_header;
int rnd_up_len, count;
uint64_t rnd_up_len;
int count;
int ret;
/* Round up the fill length to a multiple of the block size */
@ -370,9 +371,9 @@ static int write_sparse_fill_chunk(struct output_file* out, unsigned int len, ui
return 0;
}
static int write_sparse_data_chunk(struct output_file* out, unsigned int len, void* data) {
static int write_sparse_data_chunk(struct output_file* out, uint64_t len, void* data) {
chunk_header_t chunk_header;
int rnd_up_len, zero_len;
uint64_t rnd_up_len, zero_len;
int ret;
/* Round up the data length to a multiple of the block size */
@ -437,9 +438,9 @@ static struct sparse_file_ops sparse_file_ops = {
.write_end_chunk = write_sparse_end_chunk,
};
static int write_normal_data_chunk(struct output_file* out, unsigned int len, void* data) {
static int write_normal_data_chunk(struct output_file* out, uint64_t len, void* data) {
int ret;
unsigned int rnd_up_len = ALIGN(len, out->block_size);
uint64_t rnd_up_len = ALIGN(len, out->block_size);
ret = out->ops->write(out, data, len);
if (ret < 0) {
@ -453,10 +454,10 @@ static int write_normal_data_chunk(struct output_file* out, unsigned int len, vo
return ret;
}
static int write_normal_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
static int write_normal_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
int ret;
unsigned int i;
unsigned int write_len;
uint64_t write_len;
/* Initialize fill_buf with the fill_val */
for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
@ -464,7 +465,7 @@ static int write_normal_fill_chunk(struct output_file* out, unsigned int len, ui
}
while (len) {
write_len = std::min(len, out->block_size);
write_len = std::min(len, (uint64_t)out->block_size);
ret = out->ops->write(out, out->fill_buf, write_len);
if (ret < 0) {
return ret;
@ -476,7 +477,7 @@ static int write_normal_fill_chunk(struct output_file* out, unsigned int len, ui
return 0;
}
static int write_normal_skip_chunk(struct output_file* out, int64_t len) {
static int write_normal_skip_chunk(struct output_file* out, uint64_t len) {
return out->ops->skip(out, len);
}
@ -639,16 +640,16 @@ struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t
}
/* Write a contiguous region of data blocks from a memory buffer */
int write_data_chunk(struct output_file* out, unsigned int len, void* data) {
int write_data_chunk(struct output_file* out, uint64_t len, void* data) {
return out->sparse_ops->write_data_chunk(out, len, data);
}
/* Write a contiguous region of data blocks with a fill value */
int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val) {
int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val) {
return out->sparse_ops->write_fill_chunk(out, len, fill_val);
}
int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset) {
int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset) {
auto m = android::base::MappedFile::FromFd(fd, offset, len, PROT_READ);
if (!m) return -errno;
@ -656,7 +657,7 @@ int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t of
}
/* Write a contiguous region of data blocks from a file */
int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset) {
int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset) {
int ret;
int file_fd = open(file, O_RDONLY | O_BINARY);
@ -671,6 +672,6 @@ int write_file_chunk(struct output_file* out, unsigned int len, const char* file
return ret;
}
int write_skip_chunk(struct output_file* out, int64_t len) {
int write_skip_chunk(struct output_file* out, uint64_t len) {
return out->sparse_ops->write_skip_chunk(out, len);
}

View file

@ -30,11 +30,11 @@ struct output_file* output_file_open_fd(int fd, unsigned int block_size, int64_t
struct output_file* output_file_open_callback(int (*write)(void*, const void*, size_t), void* priv,
unsigned int block_size, int64_t len, int gz,
int sparse, int chunks, int crc);
int write_data_chunk(struct output_file* out, unsigned int len, void* data);
int write_fill_chunk(struct output_file* out, unsigned int len, uint32_t fill_val);
int write_file_chunk(struct output_file* out, unsigned int len, const char* file, int64_t offset);
int write_fd_chunk(struct output_file* out, unsigned int len, int fd, int64_t offset);
int write_skip_chunk(struct output_file* out, int64_t len);
int write_data_chunk(struct output_file* out, uint64_t len, void* data);
int write_fill_chunk(struct output_file* out, uint64_t len, uint32_t fill_val);
int write_file_chunk(struct output_file* out, uint64_t len, const char* file, int64_t offset);
int write_fd_chunk(struct output_file* out, uint64_t len, int fd, int64_t offset);
int write_skip_chunk(struct output_file* out, uint64_t len);
void output_file_close(struct output_file* out);
int read_all(int fd, void* buf, size_t len);

View file

@ -50,21 +50,21 @@ void sparse_file_destroy(struct sparse_file* s) {
free(s);
}
int sparse_file_add_data(struct sparse_file* s, void* data, unsigned int len, unsigned int block) {
int sparse_file_add_data(struct sparse_file* s, void* data, uint64_t len, unsigned int block) {
return backed_block_add_data(s->backed_block_list, data, len, block);
}
int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, unsigned int len,
int sparse_file_add_fill(struct sparse_file* s, uint32_t fill_val, uint64_t len,
unsigned int block) {
return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
}
int sparse_file_add_file(struct sparse_file* s, const char* filename, int64_t file_offset,
unsigned int len, unsigned int block) {
uint64_t len, unsigned int block) {
return backed_block_add_file(s->backed_block_list, filename, file_offset, len, block);
}
int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, unsigned int len,
int sparse_file_add_fd(struct sparse_file* s, int fd, int64_t file_offset, uint64_t len,
unsigned int block) {
return backed_block_add_fd(s->backed_block_list, fd, file_offset, len, block);
}