patches for easier mirroring, to eliminate a special copy, to make www.freebsd.org/security a full copy of security.freebsd.org and be eventually be the same. For now files are just sitting there. The symlinks are missing. Discussed on: www (repository location) Discussed with: simon (so)
231 lines
6.5 KiB
Diff
231 lines
6.5 KiB
Diff
Index: lib/libarchive/archive_read_support_format_tar.c
|
|
===================================================================
|
|
RCS file: /home/ncvs/src/lib/libarchive/archive_read_support_format_tar.c,v
|
|
retrieving revision 1.32.2.2
|
|
diff -u -I__FBSDID -I$FreeBSD -r1.32.2.2 archive_read_support_format_tar.c
|
|
--- lib/libarchive/archive_read_support_format_tar.c 5 Sep 2006 05:23:51 -0000 1.32.2.2
|
|
+++ lib/libarchive/archive_read_support_format_tar.c 10 Jul 2007 09:10:24 -0000
|
|
@@ -670,7 +670,13 @@
|
|
}
|
|
}
|
|
--tar->header_recursion_depth;
|
|
- return (err);
|
|
+ /* We return warnings or success as-is. Anything else is fatal. */
|
|
+ if (err == ARCHIVE_WARN || err == ARCHIVE_OK)
|
|
+ return (err);
|
|
+ if (err == ARCHIVE_EOF)
|
|
+ /* EOF when recursively reading a header is bad. */
|
|
+ archive_set_error(a, EINVAL, "Damaged tar archive");
|
|
+ return (ARCHIVE_FATAL);
|
|
}
|
|
|
|
/*
|
|
@@ -741,32 +747,55 @@
|
|
header_Solaris_ACL(struct archive *a, struct tar *tar,
|
|
struct archive_entry *entry, struct stat *st, const void *h)
|
|
{
|
|
- int err, err2;
|
|
- char *p;
|
|
+ const struct archive_entry_header_ustar *header;
|
|
+ size_t size;
|
|
+ int err;
|
|
+ char *acl, *p;
|
|
wchar_t *wp;
|
|
|
|
+ /*
|
|
+ * read_body_to_string adds a NUL terminator, but we need a little
|
|
+ * more to make sure that we don't overrun acl_text later.
|
|
+ */
|
|
+ header = (const struct archive_entry_header_ustar *)h;
|
|
+ size = tar_atol(header->size, sizeof(header->size));
|
|
err = read_body_to_string(a, tar, &(tar->acl_text), h);
|
|
- err2 = tar_read_header(a, tar, entry, st);
|
|
- err = err_combine(err, err2);
|
|
-
|
|
- /* XXX Ensure p doesn't overrun acl_text */
|
|
+ if (err != ARCHIVE_OK)
|
|
+ return (err);
|
|
+ err = tar_read_header(a, tar, entry, st);
|
|
+ if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
|
|
+ return (err);
|
|
|
|
/* Skip leading octal number. */
|
|
/* XXX TODO: Parse the octal number and sanity-check it. */
|
|
- p = tar->acl_text.s;
|
|
- while (*p != '\0')
|
|
+ p = acl = tar->acl_text.s;
|
|
+ while (*p != '\0' && p < acl + size)
|
|
p++;
|
|
p++;
|
|
|
|
- wp = malloc((strlen(p) + 1) * sizeof(wchar_t));
|
|
- if (wp != NULL) {
|
|
- utf8_decode(wp, p, strlen(p));
|
|
- err2 = __archive_entry_acl_parse_w(entry, wp,
|
|
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
|
- err = err_combine(err, err2);
|
|
- free(wp);
|
|
+ if (p >= acl + size) {
|
|
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
|
+ "Malformed Solaris ACL attribute");
|
|
+ return(ARCHIVE_WARN);
|
|
}
|
|
|
|
+ /* Skip leading octal number. */
|
|
+ size -= (p - acl);
|
|
+ acl = p;
|
|
+
|
|
+ while (*p != '\0' && p < acl + size)
|
|
+ p++;
|
|
+
|
|
+ wp = malloc((p - acl + 1) * sizeof(wchar_t));
|
|
+ if (wp == NULL) {
|
|
+ archive_set_error(a, ENOMEM,
|
|
+ "Can't allocate work buffer for ACL parsing");
|
|
+ return (ARCHIVE_FATAL);
|
|
+ }
|
|
+ utf8_decode(wp, acl, p - acl);
|
|
+ err = __archive_entry_acl_parse_w(entry, wp,
|
|
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
|
+ free(wp);
|
|
return (err);
|
|
}
|
|
|
|
@@ -777,15 +806,17 @@
|
|
header_longlink(struct archive *a, struct tar *tar,
|
|
struct archive_entry *entry, struct stat *st, const void *h)
|
|
{
|
|
- int err, err2;
|
|
+ int err;
|
|
|
|
err = read_body_to_string(a, tar, &(tar->longlink), h);
|
|
- err2 = tar_read_header(a, tar, entry, st);
|
|
- if (err == ARCHIVE_OK && err2 == ARCHIVE_OK) {
|
|
- /* Set symlink if symlink already set, else hardlink. */
|
|
- archive_entry_set_link(entry, tar->longlink.s);
|
|
- }
|
|
- return (err_combine(err, err2));
|
|
+ if (err != ARCHIVE_OK)
|
|
+ return (err);
|
|
+ err = tar_read_header(a, tar, entry, st);
|
|
+ if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
|
|
+ return (err);
|
|
+ /* Set symlink if symlink already set, else hardlink. */
|
|
+ archive_entry_set_link(entry, tar->longlink.s);
|
|
+ return (ARCHIVE_OK);
|
|
}
|
|
|
|
/*
|
|
@@ -795,14 +826,17 @@
|
|
header_longname(struct archive *a, struct tar *tar,
|
|
struct archive_entry *entry, struct stat *st, const void *h)
|
|
{
|
|
- int err, err2;
|
|
+ int err;
|
|
|
|
err = read_body_to_string(a, tar, &(tar->longname), h);
|
|
+ if (err != ARCHIVE_OK)
|
|
+ return (err);
|
|
/* Read and parse "real" header, then override name. */
|
|
- err2 = tar_read_header(a, tar, entry, st);
|
|
- if (err == ARCHIVE_OK && err2 == ARCHIVE_OK)
|
|
- archive_entry_set_pathname(entry, tar->longname.s);
|
|
- return (err_combine(err, err2));
|
|
+ err = tar_read_header(a, tar, entry, st);
|
|
+ if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
|
|
+ return (err);
|
|
+ archive_entry_set_pathname(entry, tar->longname.s);
|
|
+ return (ARCHIVE_OK);
|
|
}
|
|
|
|
|
|
@@ -836,12 +870,20 @@
|
|
header = h;
|
|
size = tar_atol(header->size, sizeof(header->size));
|
|
|
|
+ /* Sanity check. */
|
|
+ if ((size > 1048576) || (size < 0)) {
|
|
+ archive_set_error(a, EINVAL, "Special header too large");
|
|
+ return (ARCHIVE_FATAL);
|
|
+ }
|
|
+
|
|
/* Read the body into the string. */
|
|
archive_string_ensure(as, size+1);
|
|
padded_size = (size + 511) & ~ 511;
|
|
dest = as->s;
|
|
while (padded_size > 0) {
|
|
bytes_read = (a->compression_read_ahead)(a, &src, padded_size);
|
|
+ if (bytes_read == 0)
|
|
+ return (ARCHIVE_EOF);
|
|
if (bytes_read < 0)
|
|
return (ARCHIVE_FATAL);
|
|
if (bytes_read > padded_size)
|
|
@@ -1027,11 +1069,13 @@
|
|
header_pax_global(struct archive *a, struct tar *tar,
|
|
struct archive_entry *entry, struct stat *st, const void *h)
|
|
{
|
|
- int err, err2;
|
|
+ int err;
|
|
|
|
err = read_body_to_string(a, tar, &(tar->pax_global), h);
|
|
- err2 = tar_read_header(a, tar, entry, st);
|
|
- return (err_combine(err, err2));
|
|
+ if (err != ARCHIVE_OK)
|
|
+ return (err);
|
|
+ err = tar_read_header(a, tar, entry, st);
|
|
+ return (err);
|
|
}
|
|
|
|
static int
|
|
@@ -1040,10 +1084,14 @@
|
|
{
|
|
int err, err2;
|
|
|
|
- read_body_to_string(a, tar, &(tar->pax_header), h);
|
|
+ err = read_body_to_string(a, tar, &(tar->pax_header), h);
|
|
+ if (err != ARCHIVE_OK)
|
|
+ return (err);
|
|
|
|
/* Parse the next header. */
|
|
err = tar_read_header(a, tar, entry, st);
|
|
+ if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
|
|
+ return (err);
|
|
|
|
/*
|
|
* TODO: Parse global/default options into 'entry' struct here
|
|
@@ -1141,8 +1189,11 @@
|
|
l--;
|
|
break;
|
|
}
|
|
- if (*p < '0' || *p > '9')
|
|
- return (-1);
|
|
+ if (*p < '0' || *p > '9') {
|
|
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
|
+ "Ignoring malformed pax extended attributes");
|
|
+ return (ARCHIVE_WARN);
|
|
+ }
|
|
line_length *= 10;
|
|
line_length += *p - '0';
|
|
if (line_length > 999999) {
|
|
@@ -1154,8 +1205,19 @@
|
|
l--;
|
|
}
|
|
|
|
- if (line_length > attr_length)
|
|
- return (0);
|
|
+ /*
|
|
+ * Parsed length must be no bigger than available data,
|
|
+ * at least 1, and the last character of the line must
|
|
+ * be '\n'.
|
|
+ */
|
|
+ if (line_length > attr_length
|
|
+ || line_length < 1
|
|
+ || attr[line_length - 1] != '\n')
|
|
+ {
|
|
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
|
|
+ "Ignoring malformed pax extended attribute");
|
|
+ return (ARCHIVE_WARN);
|
|
+ }
|
|
|
|
/* Ensure pax_entry buffer is big enough. */
|
|
if (tar->pax_entry_length <= line_length) {
|