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>
diff --git a/libsparse/backed_block.cpp b/libsparse/backed_block.cpp
index f3d8022..6229e7c 100644
--- a/libsparse/backed_block.cpp
+++ b/libsparse/backed_block.cpp
@@ -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 @@
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 @@
}
/* 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 @@
}
/* 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 @@
/* 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 @@
}
/* 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) {
diff --git a/libsparse/backed_block.h b/libsparse/backed_block.h
index 3a75460..71a8969 100644
--- a/libsparse/backed_block.h
+++ b/libsparse/backed_block.h
@@ -29,18 +29,18 @@
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);
diff --git a/libsparse/include/sparse/sparse.h b/libsparse/include/sparse/sparse.h
index 3d5fb0c..2f75349 100644
--- a/libsparse/include/sparse/sparse.h
+++ b/libsparse/include/sparse/sparse.h
@@ -75,8 +75,7 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index b883c13..b2c5407 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -65,9 +65,9 @@
};
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 @@
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 @@
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 @@
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 @@
.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 @@
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 @@
}
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 @@
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 @@
}
/* 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 @@
}
/* 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 @@
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);
}
diff --git a/libsparse/output_file.h b/libsparse/output_file.h
index 278430b..ecbcdf3 100644
--- a/libsparse/output_file.h
+++ b/libsparse/output_file.h
@@ -30,11 +30,11 @@
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);
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index 8622b4c..396e7eb 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -50,21 +50,21 @@
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);
}