aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-25 23:35:15 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-07-25 23:35:15 +0200
commitba82a3812d39acf6c865478f72d7e68838c14f69 (patch)
tree4e558c02e997e97b41b1b353cf15f67c660b968c
parent935131744634f9a29e5d53a06a411dbb455cb1ae (diff)
Enforce reasonable upper and low bounds on the size of tar headers
Since they are read directly into memory, blindly allocating the size from the tar ball is probably a bad idea. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--lib/tar/internal.h6
-rw-r--r--lib/tar/read_header.c18
2 files changed, 24 insertions, 0 deletions
diff --git a/lib/tar/internal.h b/lib/tar/internal.h
index 6ac8d99..d59be14 100644
--- a/lib/tar/internal.h
+++ b/lib/tar/internal.h
@@ -32,6 +32,12 @@ enum {
ETV_POSIX,
};
+
+#define TAR_MAX_SYMLINK_LEN (65536)
+#define TAR_MAX_PATH_LEN (65536)
+#define TAR_MAX_PAX_LEN (65536)
+
+
int read_octal(const char *str, int digits, uint64_t *out);
int read_binary(const char *str, int digits, uint64_t *out);
diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c
index a083c2f..58e0230 100644
--- a/lib/tar/read_header.c
+++ b/lib/tar/read_header.c
@@ -386,6 +386,8 @@ int read_header(int fd, tar_header_decoded_t *out)
case TAR_TYPE_GNU_SLINK:
if (read_number(hdr.size, sizeof(hdr.size), &pax_size))
goto fail;
+ if (pax_size < 1 || pax_size > TAR_MAX_SYMLINK_LEN)
+ goto fail_slink_len;
free(out->link_target);
out->link_target = record_to_memory(fd, pax_size);
if (out->link_target == NULL)
@@ -395,6 +397,8 @@ int read_header(int fd, tar_header_decoded_t *out)
case TAR_TYPE_GNU_PATH:
if (read_number(hdr.size, sizeof(hdr.size), &pax_size))
goto fail;
+ if (pax_size < 1 || pax_size > TAR_MAX_PATH_LEN)
+ goto fail_path_len;
free(out->name);
out->name = record_to_memory(fd, pax_size);
if (out->name == NULL)
@@ -405,6 +409,8 @@ int read_header(int fd, tar_header_decoded_t *out)
clear_header(out);
if (read_number(hdr.size, sizeof(hdr.size), &pax_size))
goto fail;
+ if (pax_size < 1 || pax_size > TAR_MAX_PAX_LEN)
+ goto fail_pax_len;
set_by_pax = 0;
if (read_pax_header(fd, pax_size, &set_by_pax, out))
goto fail;
@@ -436,6 +442,18 @@ int read_header(int fd, tar_header_decoded_t *out)
out_eof:
clear_header(out);
return 1;
+fail_slink_len:
+ fprintf(stderr, "rejecting GNU symlink header with size %zu\n",
+ pax_size);
+ goto fail;
+fail_path_len:
+ fprintf(stderr, "rejecting GNU long path header with size %zu\n",
+ pax_size);
+ goto fail;
+fail_pax_len:
+ fprintf(stderr, "rejecting PAX header with size %zu\n",
+ pax_size);
+ goto fail;
fail_magic:
fputs("input is not a ustar tar archive!\n", stderr);
goto fail;