mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
MFV r340865:
Sync libarchive with vendor. Relevant vendor changes: PR #1080: Spelling fixes PR #1084: RAR5 reader bugfixes PR #1091: fix use-after-free in delayed newc link processing PR #1092: Fix a few obvious resource leaks and strcpy() misuses MFC after: 1 week
This commit is contained in:
commit
276f481d65
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=340866
@ -755,8 +755,10 @@ file_to_archive(struct cpio *cpio, const char *srcpath)
|
||||
}
|
||||
if (cpio->option_rename)
|
||||
destpath = cpio_rename(destpath);
|
||||
if (destpath == NULL)
|
||||
if (destpath == NULL) {
|
||||
archive_entry_free(entry);
|
||||
return (0);
|
||||
}
|
||||
archive_entry_copy_pathname(entry, destpath);
|
||||
|
||||
/*
|
||||
|
@ -753,8 +753,10 @@ archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
append_entry_w(&wp, prefix, ap->type, ap->tag, flags,
|
||||
wname, ap->permset, id);
|
||||
count++;
|
||||
} else if (r < 0 && errno == ENOMEM)
|
||||
} else if (r < 0 && errno == ENOMEM) {
|
||||
free(ws);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add terminating character */
|
||||
@ -975,8 +977,10 @@ archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
|
||||
prefix = NULL;
|
||||
r = archive_mstring_get_mbs_l(
|
||||
&ap->name, &name, &len, sc);
|
||||
if (r != 0)
|
||||
if (r != 0) {
|
||||
free(s);
|
||||
return (NULL);
|
||||
}
|
||||
if (count > 0)
|
||||
*p++ = separator;
|
||||
if (name == NULL ||
|
||||
|
@ -88,6 +88,7 @@ struct file_header {
|
||||
|
||||
uint8_t solid : 1; /* Is this a solid stream? */
|
||||
uint8_t service : 1; /* Is this file a service data? */
|
||||
uint8_t eof : 1; /* Did we finish unpacking the file? */
|
||||
|
||||
/* Optional time fields. */
|
||||
uint64_t e_mtime;
|
||||
@ -176,7 +177,7 @@ struct comp_state {
|
||||
decompression. */
|
||||
uint8_t* filtered_buf; /* Buffer used when applying filters. */
|
||||
const uint8_t* block_buf; /* Buffer used when merging blocks. */
|
||||
size_t window_mask; /* Convinience field; window_size - 1. */
|
||||
size_t window_mask; /* Convenience field; window_size - 1. */
|
||||
int64_t write_ptr; /* This amount of data has been unpacked in
|
||||
the window buffer. */
|
||||
int64_t last_write_ptr; /* This amount of data has been stored in
|
||||
@ -279,7 +280,7 @@ struct rar5 {
|
||||
int skip_mode;
|
||||
|
||||
/* An offset to QuickOpen list. This is not supported by this unpacker,
|
||||
* becuase we're focusing on streaming interface. QuickOpen is designed
|
||||
* because we're focusing on streaming interface. QuickOpen is designed
|
||||
* to make things quicker for non-stream interfaces, so it's not our
|
||||
* use case. */
|
||||
uint64_t qlist_offset;
|
||||
@ -387,7 +388,7 @@ static void cdeque_pop_front_fast(struct cdeque* d, void** value) {
|
||||
d->size--;
|
||||
}
|
||||
|
||||
/* Pops a front element of this cicrular deque object and returns its value.
|
||||
/* Pops a front element of this circular deque object and returns its value.
|
||||
* This function performs bounds checking. */
|
||||
static int cdeque_pop_front(struct cdeque* d, void** value) {
|
||||
if(!d || !value)
|
||||
@ -400,17 +401,17 @@ static int cdeque_pop_front(struct cdeque* d, void** value) {
|
||||
return CDE_OK;
|
||||
}
|
||||
|
||||
/* Convinience function to cast filter_info** to void **. */
|
||||
/* Convenience function to cast filter_info** to void **. */
|
||||
static void** cdeque_filter_p(struct filter_info** f) {
|
||||
return (void**) (size_t) f;
|
||||
}
|
||||
|
||||
/* Convinience function to cast filter_info* to void *. */
|
||||
/* Convenience function to cast filter_info* to void *. */
|
||||
static void* cdeque_filter(struct filter_info* f) {
|
||||
return (void**) (size_t) f;
|
||||
}
|
||||
|
||||
/* Destroys this circular deque object. Dellocates the memory of the collection
|
||||
/* Destroys this circular deque object. Deallocates the memory of the collection
|
||||
* buffer, but doesn't deallocate the memory of any pointer passed to this
|
||||
* deque as a value. */
|
||||
static void cdeque_free(struct cdeque* d) {
|
||||
@ -434,7 +435,7 @@ static inline struct rar5* get_context(struct archive_read* a) {
|
||||
|
||||
// TODO: make sure these functions return a little endian number
|
||||
|
||||
/* Convinience functions used by filter implementations. */
|
||||
/* Convenience functions used by filter implementations. */
|
||||
|
||||
static uint32_t read_filter_data(struct rar5* rar, uint32_t offset) {
|
||||
uint32_t* dptr = (uint32_t*) &rar->cstate.window_buf[offset];
|
||||
@ -672,7 +673,7 @@ static void push_data(struct archive_read* a, struct rar5* rar,
|
||||
}
|
||||
}
|
||||
|
||||
/* Convinience function that submits the data to the user. It uses the
|
||||
/* Convenience function that submits the data to the user. It uses the
|
||||
* unpack window buffer as a source location. */
|
||||
static void push_window_data(struct archive_read* a, struct rar5* rar,
|
||||
int64_t idx_begin, int64_t idx_end)
|
||||
@ -753,7 +754,7 @@ static void free_filters(struct rar5* rar) {
|
||||
|
||||
/* Free any remaining filters. All filters should be naturally consumed by
|
||||
* the unpacking function, so remaining filters after unpacking normally
|
||||
* mean that unpacking wasn't successfull. But still of course we shouldn't
|
||||
* mean that unpacking wasn't successful. But still of course we shouldn't
|
||||
* leak memory in such case. */
|
||||
|
||||
/* cdeque_size() is a fast operation, so we can use it as a loop
|
||||
@ -885,7 +886,7 @@ static int read_var(struct archive_read* a, uint64_t* pvalue,
|
||||
* it will not have the possibility to advance the file
|
||||
* pointer, because it will not know how many bytes it needs
|
||||
* to consume. This is why we handle such situation here
|
||||
* autmatically. */
|
||||
* automatically. */
|
||||
if(ARCHIVE_OK != consume(a, 1 + i)) {
|
||||
return 0;
|
||||
}
|
||||
@ -918,7 +919,7 @@ static int read_var_sized(struct archive_read* a, size_t* pvalue,
|
||||
size_t* pvalue_len)
|
||||
{
|
||||
uint64_t v;
|
||||
uint64_t v_size;
|
||||
uint64_t v_size = 0;
|
||||
|
||||
const int ret = pvalue_len
|
||||
? read_var(a, &v, &v_size)
|
||||
@ -1218,7 +1219,7 @@ static int process_head_file_extra(struct archive_read* a,
|
||||
ssize_t extra_data_size)
|
||||
{
|
||||
size_t extra_field_size;
|
||||
size_t extra_field_id;
|
||||
size_t extra_field_id = 0;
|
||||
int ret = ARCHIVE_FATAL;
|
||||
size_t var_size;
|
||||
|
||||
@ -1288,7 +1289,7 @@ static int process_head_file(struct archive_read* a, struct rar5* rar,
|
||||
size_t host_os = 0;
|
||||
size_t name_size = 0;
|
||||
uint64_t unpacked_size;
|
||||
uint32_t mtime = 0, crc;
|
||||
uint32_t mtime = 0, crc = 0;
|
||||
int c_method = 0, c_version = 0, is_dir;
|
||||
char name_utf8_buf[2048 * 4];
|
||||
const uint8_t* p;
|
||||
@ -1522,7 +1523,7 @@ static int process_head_main(struct archive_read* a, struct rar5* rar,
|
||||
|
||||
enum MAIN_FLAGS {
|
||||
VOLUME = 0x0001, /* multi-volume archive */
|
||||
VOLUME_NUMBER = 0x0002, /* volume number, first vol doesnt have it */
|
||||
VOLUME_NUMBER = 0x0002, /* volume number, first vol doesn't have it */
|
||||
SOLID = 0x0004, /* solid archive */
|
||||
PROTECT = 0x0008, /* contains Recovery info */
|
||||
LOCK = 0x0010, /* readonly flag, not used */
|
||||
@ -1647,7 +1648,7 @@ static int process_base_block(struct archive_read* a,
|
||||
{
|
||||
struct rar5* rar = get_context(a);
|
||||
uint32_t hdr_crc, computed_crc;
|
||||
size_t raw_hdr_size, hdr_size_len, hdr_size;
|
||||
size_t raw_hdr_size = 0, hdr_size_len, hdr_size;
|
||||
size_t header_id = 0;
|
||||
size_t header_flags = 0;
|
||||
const uint8_t* p;
|
||||
@ -2211,7 +2212,7 @@ static int parse_block_header(struct archive_read* a, const uint8_t* p,
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
/* Convinience function used during filter processing. */
|
||||
/* Convenience function used during filter processing. */
|
||||
static int parse_filter_data(struct rar5* rar, const uint8_t* p,
|
||||
uint32_t* filter_data)
|
||||
{
|
||||
@ -2685,6 +2686,12 @@ static int merge_block(struct archive_read* a, ssize_t block_size,
|
||||
cur_block_size =
|
||||
rar5_min(rar->file.bytes_remaining, block_size - partial_offset);
|
||||
|
||||
if(cur_block_size == 0) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
|
||||
"Encountered block size == 0 during block merge");
|
||||
return ARCHIVE_FATAL;
|
||||
}
|
||||
|
||||
if(!read_ahead(a, cur_block_size, &lp))
|
||||
return ARCHIVE_EOF;
|
||||
|
||||
@ -3116,6 +3123,9 @@ static int do_unstore_file(struct archive_read* a,
|
||||
}
|
||||
|
||||
size_t to_read = rar5_min(rar->file.bytes_remaining, 64 * 1024);
|
||||
if(to_read == 0) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
if(!read_ahead(a, to_read, &p)) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "I/O error "
|
||||
@ -3186,7 +3196,7 @@ static int verify_checksums(struct archive_read* a) {
|
||||
* data and discarding the result). */
|
||||
|
||||
if(!rar->skip_mode) {
|
||||
/* Always check checkums if we're not in skip mode */
|
||||
/* Always check checksums if we're not in skip mode */
|
||||
verify_crc = 1;
|
||||
} else {
|
||||
/* We can override the logic above with a compile-time option
|
||||
@ -3283,8 +3293,13 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
}
|
||||
|
||||
ret = use_data(rar, buff, size, offset);
|
||||
if(ret == ARCHIVE_OK)
|
||||
if(ret == ARCHIVE_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(rar->file.eof == 1) {
|
||||
return ARCHIVE_EOF;
|
||||
}
|
||||
|
||||
ret = do_unpack(a, rar, buff, size, offset);
|
||||
if(ret != ARCHIVE_OK) {
|
||||
@ -3301,6 +3316,7 @@ static int rar5_read_data(struct archive_read *a, const void **buff,
|
||||
* value in the last `archive_read_data` call to signal an error
|
||||
* to the user. */
|
||||
|
||||
rar->file.eof = 1;
|
||||
return verify_global_checksums(a);
|
||||
}
|
||||
|
||||
|
@ -4899,10 +4899,10 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
|
||||
if (p[0] == '/') {
|
||||
if (p[1] == '/')
|
||||
/* Convert '//' --> '/' */
|
||||
strcpy(p, p+1);
|
||||
memmove(p, p+1, strlen(p+1) + 1);
|
||||
else if (p[1] == '.' && p[2] == '/')
|
||||
/* Convert '/./' --> '/' */
|
||||
strcpy(p, p+2);
|
||||
memmove(p, p+2, strlen(p+2) + 1);
|
||||
else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
|
||||
/* Convert 'dir/dir1/../dir2/'
|
||||
* --> 'dir/dir2/'
|
||||
|
@ -1810,10 +1810,10 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
|
||||
if (p[0] == '/') {
|
||||
if (p[1] == '/')
|
||||
/* Convert '//' --> '/' */
|
||||
strcpy(p, p+1);
|
||||
memmove(p, p+1, strlen(p+1) + 1);
|
||||
else if (p[1] == '.' && p[2] == '/')
|
||||
/* Convert '/./' --> '/' */
|
||||
strcpy(p, p+2);
|
||||
memmove(p, p+2, strlen(p+2) + 1);
|
||||
else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
|
||||
/* Convert 'dir/dir1/../dir2/'
|
||||
* --> 'dir/dir2/'
|
||||
|
@ -522,11 +522,13 @@ add_pax_acl(struct archive_write *a,
|
||||
ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s",
|
||||
"Can't translate ", attr, " to UTF-8");
|
||||
return(ARCHIVE_WARN);
|
||||
} else if (*p != '\0') {
|
||||
}
|
||||
|
||||
if (*p != '\0') {
|
||||
add_pax_attr(&(pax->pax_header),
|
||||
attr, p);
|
||||
free(p);
|
||||
}
|
||||
free(p);
|
||||
return(ARCHIVE_OK);
|
||||
}
|
||||
|
||||
|
@ -2120,10 +2120,10 @@ file_gen_utility_names(struct archive_write *a, struct file *file)
|
||||
if (p[0] == '/') {
|
||||
if (p[1] == '/')
|
||||
/* Convert '//' --> '/' */
|
||||
strcpy(p, p+1);
|
||||
memmove(p, p+1, strlen(p+1) + 1);
|
||||
else if (p[1] == '.' && p[2] == '/')
|
||||
/* Convert '/./' --> '/' */
|
||||
strcpy(p, p+2);
|
||||
memmove(p, p+2, strlen(p+2) + 1);
|
||||
else if (p[1] == '.' && p[2] == '.' && p[3] == '/') {
|
||||
/* Convert 'dir/dir1/../dir2/'
|
||||
* --> 'dir/dir2/'
|
||||
@ -3169,8 +3169,10 @@ save_xattrs(struct archive_write *a, struct file *file)
|
||||
checksum_update(&(xar->a_sumwrk),
|
||||
xar->wbuff, size);
|
||||
if (write_to_temp(a, xar->wbuff, size)
|
||||
!= ARCHIVE_OK)
|
||||
!= ARCHIVE_OK) {
|
||||
free(heap);
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
if (r == ARCHIVE_OK) {
|
||||
xar->stream.next_out = xar->wbuff;
|
||||
xar->stream.avail_out = sizeof(xar->wbuff);
|
||||
|
@ -433,7 +433,7 @@ DEFINE_TEST(test_fuzz_tar)
|
||||
{0, fileset9}, /* Exercise lzo decompressor. */
|
||||
#endif
|
||||
#if HAVE_ZSTD_H && HAVE_LIBZSTD
|
||||
{0, fileset10}, /* Excercise zstd decompressor. */
|
||||
{0, fileset10}, /* Exercise zstd decompressor. */
|
||||
#endif
|
||||
{1, NULL}
|
||||
};
|
||||
|
@ -726,3 +726,44 @@ DEFINE_TEST(test_read_format_rar5_extract_win32)
|
||||
assertA(0 == extract_one(a, ae, 0x36A448FF));
|
||||
EPILOGUE();
|
||||
}
|
||||
|
||||
DEFINE_TEST(test_read_format_rar5_block_by_block)
|
||||
{
|
||||
/* This test uses strange buffer sizes intentionally. */
|
||||
|
||||
struct archive_entry *ae;
|
||||
struct archive *a;
|
||||
uint8_t buf[173];
|
||||
int bytes_read;
|
||||
uint32_t computed_crc = 0;
|
||||
|
||||
extract_reference_file("test_read_format_rar5_compressed.rar");
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertA(0 == archive_read_support_filter_all(a));
|
||||
assertA(0 == archive_read_support_format_all(a));
|
||||
assertA(0 == archive_read_open_filename(a, "test_read_format_rar5_compressed.rar", 130));
|
||||
assertA(0 == archive_read_next_header(a, &ae));
|
||||
assertEqualString("test.bin", archive_entry_pathname(ae));
|
||||
assertEqualInt(1200, archive_entry_size(ae));
|
||||
|
||||
/* File size is 1200 bytes, we're reading it using a buffer of 173 bytes.
|
||||
* Libarchive is configured to use a buffer of 130 bytes. */
|
||||
|
||||
while(1) {
|
||||
/* archive_read_data should return one of:
|
||||
* a) 0, if there is no more data to be read,
|
||||
* b) negative value, if there was an error,
|
||||
* c) positive value, meaning how many bytes were read.
|
||||
*/
|
||||
|
||||
bytes_read = archive_read_data(a, buf, sizeof(buf));
|
||||
assertA(bytes_read >= 0);
|
||||
if(bytes_read <= 0)
|
||||
break;
|
||||
|
||||
computed_crc = crc32(computed_crc, buf, bytes_read);
|
||||
}
|
||||
|
||||
assertEqualInt(computed_crc, 0x7CCA70CD);
|
||||
EPILOGUE();
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ DEFINE_TEST(test_write_disk_perms)
|
||||
failure("dir_overwrite_0744: st.st_mode=%o", st.st_mode);
|
||||
assertEqualInt(st.st_mode & 0777, 0744);
|
||||
|
||||
/* For dir, the owner should get left when not overwritting. */
|
||||
/* For dir, the owner should get left when not overwriting. */
|
||||
assertMakeDir("dir_owner", 0744);
|
||||
|
||||
if (getuid() == 0) {
|
||||
|
@ -540,8 +540,7 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
|
||||
lafe_warnc(archive_errno(disk),
|
||||
"%s", archive_error_string(disk));
|
||||
bsdtar->return_value = 1;
|
||||
archive_entry_free(entry);
|
||||
continue;
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -557,15 +556,14 @@ write_archive(struct archive *a, struct bsdtar *bsdtar)
|
||||
"%s", archive_error_string(disk));
|
||||
if (r == ARCHIVE_FATAL)
|
||||
bsdtar->return_value = 1;
|
||||
else
|
||||
archive_read_close(disk);
|
||||
archive_entry_free(entry);
|
||||
continue;
|
||||
archive_read_close(disk);
|
||||
goto next_entry;
|
||||
}
|
||||
|
||||
write_file(bsdtar, a, entry);
|
||||
archive_entry_free(entry);
|
||||
archive_read_close(disk);
|
||||
next_entry:
|
||||
archive_entry_free(entry);
|
||||
entry = NULL;
|
||||
archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user