From 5c2c79eafdaffd172c20dd2cebc96f3dea266b96 Mon Sep 17 00:00:00 2001 From: kientzle Date: Tue, 13 Apr 2004 23:45:37 +0000 Subject: * Plug a buffer overrun in ACL parsing. (archive_entry.c) * Re-use a single buffer for shar output formatting rather than hammering the heap. (archive_write_set_format_shar.c) * Fix a handful of minor memory leaks and clean up some of the memory-management code. --- lib/libarchive/archive_entry.c | 7 ++++ lib/libarchive/archive_entry.h | 1 + lib/libarchive/archive_read.c | 6 +-- lib/libarchive/archive_read_open_file.c | 5 ++- lib/libarchive/archive_read_open_filename.c | 5 ++- lib/libarchive/archive_read_support_format_cpio.c | 9 ++++- lib/libarchive/archive_read_support_format_tar.c | 34 ++++++++--------- lib/libarchive/archive_write.c | 4 +- lib/libarchive/archive_write_set_format_cpio.c | 5 +++ lib/libarchive/archive_write_set_format_pax.c | 10 +++-- lib/libarchive/archive_write_set_format_shar.c | 46 ++++++++++++++++------- lib/libarchive/archive_write_set_format_ustar.c | 18 +++++---- 12 files changed, 99 insertions(+), 51 deletions(-) (limited to 'lib/libarchive') diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c index be261f5..7ea63fc 100644 --- a/lib/libarchive/archive_entry.c +++ b/lib/libarchive/archive_entry.c @@ -481,6 +481,12 @@ archive_entry_set_hardlink(struct archive_entry *entry, const char *target) } void +archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) +{ + aes_copy_mbs(&entry->ae_hardlink, target); +} + +void archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) { aes_copy_wcs(&entry->ae_hardlink, target); @@ -1111,6 +1117,7 @@ __archive_entry_acl_parse_w(struct archive_entry *entry, malloc(namebuff_length * sizeof(wchar_t)); } wmemcpy(namebuff, name_start, name_end - name_start); + namebuff[name_end - name_start] = L'\0'; archive_entry_acl_add_entry_w(entry, type, permset, tag, id, namebuff); } diff --git a/lib/libarchive/archive_entry.h b/lib/libarchive/archive_entry.h index 385850b..733a60d 100644 --- a/lib/libarchive/archive_entry.h +++ b/lib/libarchive/archive_entry.h @@ -97,6 +97,7 @@ void archive_entry_set_gid(struct archive_entry *, gid_t); void archive_entry_set_gname(struct archive_entry *, const char *); void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); void archive_entry_set_hardlink(struct archive_entry *, const char *); +void archive_entry_copy_hardlink(struct archive_entry *, const char *); void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); void archive_entry_set_link(struct archive_entry *, const char *); void archive_entry_set_mode(struct archive_entry *, mode_t); diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c index ae2c8d8..7af242a 100644 --- a/lib/libarchive/archive_read.c +++ b/lib/libarchive/archive_read.c @@ -428,8 +428,8 @@ archive_read_finish(struct archive *a) /* Casting a pointer to int allows us to remove 'const.' */ free((void *)(uintptr_t)(const void *)a->nulls); - if (a->extract_mkdirpath.s != NULL) - free(a->extract_mkdirpath.s); + archive_string_free(&a->extract_mkdirpath); + archive_string_free(&a->error_string); if (a->entry) archive_entry_free(a->entry); a->magic = 0; @@ -455,7 +455,7 @@ __archive_read_register_format(struct archive *a, for (i = 0; i < number_slots; i++) { if (a->formats[i].bid == bid) - return (0); /* We've already installed */ + return (ARCHIVE_WARN); /* We've already installed */ if (a->formats[i].bid == NULL) { a->formats[i].bid = bid; a->formats[i].read_header = read_header; diff --git a/lib/libarchive/archive_read_open_file.c b/lib/libarchive/archive_read_open_file.c index f26a362..fa30bbb 100644 --- a/lib/libarchive/archive_read_open_file.c +++ b/lib/libarchive/archive_read_open_file.c @@ -68,7 +68,7 @@ archive_read_open_file(struct archive *a, const char *filename, strcpy(mine->filename, filename); } mine->block_size = block_size; - mine->buffer = malloc(mine->block_size); + mine->buffer = NULL; mine->fd = -1; return (archive_read_open(a, mine, file_open, file_read, file_close)); } @@ -78,6 +78,7 @@ file_open(struct archive *a, void *client_data) { struct read_file_data *mine = client_data; + mine->buffer = malloc(mine->block_size); if (*mine->filename != 0) mine->fd = open(mine->filename, O_RDONLY); else @@ -108,6 +109,8 @@ file_close(struct archive *a, void *client_data) (void)a; /* UNUSED */ if (mine->fd >= 0) close(mine->fd); + if (mine->buffer != NULL) + free(mine->buffer); free(mine); return (ARCHIVE_OK); } diff --git a/lib/libarchive/archive_read_open_filename.c b/lib/libarchive/archive_read_open_filename.c index f26a362..fa30bbb 100644 --- a/lib/libarchive/archive_read_open_filename.c +++ b/lib/libarchive/archive_read_open_filename.c @@ -68,7 +68,7 @@ archive_read_open_file(struct archive *a, const char *filename, strcpy(mine->filename, filename); } mine->block_size = block_size; - mine->buffer = malloc(mine->block_size); + mine->buffer = NULL; mine->fd = -1; return (archive_read_open(a, mine, file_open, file_read, file_close)); } @@ -78,6 +78,7 @@ file_open(struct archive *a, void *client_data) { struct read_file_data *mine = client_data; + mine->buffer = malloc(mine->block_size); if (*mine->filename != 0) mine->fd = open(mine->filename, O_RDONLY); else @@ -108,6 +109,8 @@ file_close(struct archive *a, void *client_data) (void)a; /* UNUSED */ if (mine->fd >= 0) close(mine->fd); + if (mine->buffer != NULL) + free(mine->buffer); free(mine); return (ARCHIVE_OK); } diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c index 5ddc4f1..9abeeca 100644 --- a/lib/libarchive/archive_read_support_format_cpio.c +++ b/lib/libarchive/archive_read_support_format_cpio.c @@ -83,16 +83,21 @@ int archive_read_support_format_cpio(struct archive *a) { struct cpio *cpio; + int r; cpio = malloc(sizeof(*cpio)); memset(cpio, 0, sizeof(*cpio)); cpio->magic = CPIO_MAGIC; - return (__archive_read_register_format(a, + r = __archive_read_register_format(a, cpio, archive_read_format_cpio_bid, archive_read_format_cpio_read_header, - archive_read_format_cpio_cleanup)); + archive_read_format_cpio_cleanup); + + if (r != ARCHIVE_OK) + free(cpio); + return (ARCHIVE_OK); } diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c index 8f6d521..b91162d 100644 --- a/lib/libarchive/archive_read_support_format_tar.c +++ b/lib/libarchive/archive_read_support_format_tar.c @@ -131,15 +131,19 @@ int archive_read_support_format_tar(struct archive *a) { struct tar *tar; + int r; tar = malloc(sizeof(*tar)); memset(tar, 0, sizeof(*tar)); - return (__archive_read_register_format(a, - tar, + r = __archive_read_register_format(a, tar, archive_read_format_tar_bid, archive_read_format_tar_read_header, - archive_read_format_tar_cleanup)); + archive_read_format_tar_cleanup); + + if (r != ARCHIVE_OK) + free(tar); + return (ARCHIVE_OK); } static int @@ -148,19 +152,15 @@ archive_read_format_tar_cleanup(struct archive *a) struct tar *tar; tar = *(a->pformat_data); - if (tar->entry_name.s != NULL) - free(tar->entry_name.s); - if (tar->entry_linkname.s != NULL) - free(tar->entry_linkname.s); - if (tar->entry_uname.s != NULL) - free(tar->entry_uname.s); - if (tar->entry_gname.s != NULL) - free(tar->entry_gname.s); - if (tar->pax_header.s != NULL) - free(tar->pax_header.s); - if (tar->pax_global.s != NULL) - free(tar->pax_global.s); - + archive_string_free(&tar->acl_text); + archive_string_free(&tar->entry_name); + archive_string_free(&tar->entry_linkname); + archive_string_free(&tar->entry_uname); + archive_string_free(&tar->entry_gname); + archive_string_free(&tar->pax_global); + archive_string_free(&tar->pax_header); + if (tar->pax_entry != NULL) + free(tar->pax_entry); free(tar); *(a->pformat_data) = NULL; return (ARCHIVE_OK); @@ -822,7 +822,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry, /* Ensure pax_entry buffer is big enough. */ if (tar->pax_entry_length <= line_length) { if (tar->pax_entry_length <= 0) - tar->pax_entry_length = 256; + tar->pax_entry_length = 1024; while (tar->pax_entry_length <= line_length + 1) tar->pax_entry_length *= 2; diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c index 2230dae..7b41e53 100644 --- a/lib/libarchive/archive_write.c +++ b/lib/libarchive/archive_write.c @@ -165,8 +165,8 @@ archive_write_finish(struct archive *a) /* Release various dynamic buffers. */ free((void *)(uintptr_t)(const void *)a->nulls); - if (a->extract_mkdirpath.s != NULL) - free(a->extract_mkdirpath.s); + archive_string_free(&a->extract_mkdirpath); + archive_string_free(&a->error_string); a->magic = 0; free(a); } diff --git a/lib/libarchive/archive_write_set_format_cpio.c b/lib/libarchive/archive_write_set_format_cpio.c index 83e88ab..91f8283 100644 --- a/lib/libarchive/archive_write_set_format_cpio.c +++ b/lib/libarchive/archive_write_set_format_cpio.c @@ -207,10 +207,12 @@ format_octal_recursive(int64_t v, char *p, int s) static int archive_write_cpio_finish(struct archive *a) { + struct cpio *cpio; struct stat st; int er; struct archive_entry *trailer; + cpio = a->format_data; trailer = archive_entry_new(); memset(&st, 0, sizeof(st)); st.st_nlink = 1; @@ -218,6 +220,9 @@ archive_write_cpio_finish(struct archive *a) archive_entry_set_pathname(trailer, "TRAILER!!!"); er = archive_write_cpio_header(a, trailer); archive_entry_free(trailer); + + free(cpio); + a->format_data = NULL; return (er); } diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c index 503062c..efa38e2 100644 --- a/lib/libarchive/archive_write_set_format_pax.c +++ b/lib/libarchive/archive_write_set_format_pax.c @@ -611,7 +611,7 @@ archive_write_pax_header(struct archive *a, pax_attr_entry, 'x'); archive_entry_free(pax_attr_entry); - free(pax_entry_name.s); + archive_string_free(&pax_entry_name); /* Note that the 'x' header shouldn't ever fail to format */ if (ret != 0) { @@ -765,12 +765,16 @@ static int archive_write_pax_finish(struct archive *a) { struct pax *pax; + int r; + + r = ARCHIVE_OK; pax = a->format_data; if (pax->written && a->compression_write != NULL) - return (write_nulls(a, 512 * 2)); + r = write_nulls(a, 512 * 2); + archive_string_free(&pax->pax_header); free(pax); a->format_data = NULL; - return (ARCHIVE_OK); + return (r); } static int diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c index 76fa398..f063e21 100644 --- a/lib/libarchive/archive_write_set_format_shar.c +++ b/lib/libarchive/archive_write_set_format_shar.c @@ -38,16 +38,6 @@ __FBSDID("$FreeBSD$"); #include "archive_entry.h" #include "archive_private.h" -static int archive_write_shar_finish(struct archive *); -static int archive_write_shar_header(struct archive *, - struct archive_entry *); -static int archive_write_shar_data_sed(struct archive *, - const void * buff, size_t); -static int archive_write_shar_data_uuencode(struct archive *, - const void * buff, size_t); -static int archive_write_shar_finish_entry(struct archive *); -static int shar_printf(struct archive *, const char *fmt, ...); - struct shar { int dump; int end_of_line; @@ -60,19 +50,43 @@ struct shar { int uuavail; char uubuffer[3]; int wrote_header; + char *work; + size_t work_len; }; +static int archive_write_shar_finish(struct archive *); +static int archive_write_shar_header(struct archive *, + struct archive_entry *); +static int archive_write_shar_data_sed(struct archive *, + const void * buff, size_t); +static int archive_write_shar_data_uuencode(struct archive *, + const void * buff, size_t); +static int archive_write_shar_finish_entry(struct archive *); +static int shar_printf(struct archive *, const char *fmt, ...); +static void uuencode_group(struct shar *); + static int shar_printf(struct archive *a, const char *fmt, ...) { + struct shar *shar; va_list ap; - char *p; + int required; int ret; + shar = a->format_data; + if (shar->work_len <= 0) { + shar->work_len = 1024; + shar->work = malloc(shar->work_len); + } + va_start(ap, fmt); - vasprintf(&p, fmt, ap); - ret = ((a->compression_write)(a, p, strlen(p))); - free(p); + required = vsnprintf(shar->work, shar->work_len, fmt, ap); + if ((size_t)required >= shar->work_len) { + shar->work_len = required + 256; + realloc(shar->work, shar->work_len); + required = vsnprintf(shar->work, shar->work_len, fmt, ap); + } + ret = ((a->compression_write)(a, shar->work, strlen(shar->work))); va_end(ap); return (ret); } @@ -261,6 +275,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry) return (ARCHIVE_OK); } +/* XXX TODO: This could be more efficient XXX */ static int archive_write_shar_data_sed(struct archive *a, const void *buff, size_t length) { @@ -297,6 +312,7 @@ archive_write_shar_data_sed(struct archive *a, const void *buff, size_t length) #define UUENC(c) (((c)!=0) ? ((c) & 077) + ' ': '`') +/* XXX This could be a lot more efficient. XXX */ static void uuencode_group(struct shar *shar) { @@ -443,6 +459,8 @@ archive_write_shar_finish(struct archive *a) archive_entry_free(shar->entry); if (shar->last_dir != NULL) free(shar->last_dir); + if (shar->work != NULL) + free(shar->work); free(shar); a->format_data = NULL; return (ARCHIVE_OK); diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c index 931f658..7d3c4a0 100644 --- a/lib/libarchive/archive_write_set_format_ustar.c +++ b/lib/libarchive/archive_write_set_format_ustar.c @@ -373,19 +373,20 @@ static int archive_write_ustar_finish(struct archive *a) { struct ustar *ustar; + int r; + r = ARCHIVE_OK; ustar = a->format_data; /* * Suppress end-of-archive if nothing else was ever written. - * This fixes a problem where setting one format, then another ends up - * attempting to write a gratuitous end-of-archive marker. + * This fixes a problem where setting one format, then another + * ends up writing a gratuitous end-of-archive marker. */ if (ustar->written && a->compression_write != NULL) - if (write_nulls(a, 512*2) < 512*2) - return (ARCHIVE_FATAL); - free(a->format_data); + r = write_nulls(a, 512*2); + free(ustar); a->format_data = NULL; - return (ARCHIVE_OK); + return (r); } static int @@ -409,10 +410,11 @@ write_nulls(struct archive *a, size_t padding) while (padding > 0) { to_write = padding < a->null_length ? padding : a->null_length; ret = (a->compression_write)(a, a->nulls, to_write); - if (ret < to_write) return (-1); + if (ret < to_write) + return (ARCHIVE_FATAL); padding -= to_write; } - return (0); + return (ARCHIVE_OK); } static int -- cgit v1.1