summaryrefslogtreecommitdiff
path: root/lib/tar
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-13 13:52:33 +0100
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-12-13 13:52:33 +0100
commit7ab411dbd2cb066652f5f51a1bc6cc793b7cafad (patch)
tree39378c7700247c5a5b2163d26695c4e00f97a1ca /lib/tar
parentba04f24b3cab65081facdb2c726f023bdb9e7b48 (diff)
Make the PAX header parser more strict
Actually parse the length field and insist it matches the line length, then use the length field to advance to the next line. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/tar')
-rw-r--r--lib/tar/read_header.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/lib/tar/read_header.c b/lib/tar/read_header.c
index 7ec1333..845afc3 100644
--- a/lib/tar/read_header.c
+++ b/lib/tar/read_header.c
@@ -80,29 +80,45 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax,
sparse_map_t *sparse_last = NULL, *sparse;
sqfs_u64 field, offset = 0, num_bytes = 0;
char *buffer, *line, *key, *ptr, *value;
+ sqfs_u64 i, start, len;
tar_xattr_t *xattr;
- sqfs_u64 i;
+ int digit;
buffer = record_to_memory(fp, entsize);
if (buffer == NULL)
return -1;
- for (i = 0; i < entsize; ++i) {
- while (i < entsize && isspace(buffer[i]))
- ++i;
- while (i < entsize && isdigit(buffer[i]))
- ++i;
+ for (i = 0; i < entsize; i += len) {
+ start = i;
+
+ if (!isdigit(buffer[i]))
+ goto fail_malformed;
+
+ for (len = 0; i < entsize && isdigit(buffer[i]); ++i) {
+ digit = buffer[i] - '0';
+
+ if (len > (entsize - digit) / 10)
+ goto fail_ov;
+
+ len = len * 10 + digit;
+ }
+
+ if (!isspace(buffer[i]))
+ goto fail_malformed;
+
while (i < entsize && isspace(buffer[i]))
++i;
- if (i >= entsize)
- break;
- line = buffer + i;
+ if (i >= entsize || (i - start) >= len)
+ goto fail_ov;
- while (i < entsize && buffer[i] != '\n')
- ++i;
+ len -= i - start;
- buffer[i] = '\0';
+ if (i + len > entsize)
+ goto fail_ov;
+
+ line = buffer + i;
+ line[len - 1] = '\0';
if (!strncmp(line, "uid=", 4)) {
if (pax_read_decimal(line + 4, &field))
@@ -214,6 +230,12 @@ static int read_pax_header(FILE *fp, sqfs_u64 entsize, unsigned int *set_by_pax,
free(buffer);
return 0;
+fail_malformed:
+ fputs("Found a malformed PAX header.\n", stderr);
+ goto fail;
+fail_ov:
+ fputs("Numeric overflow in PAX header.\n", stderr);
+ goto fail;
fail_errno:
perror("reading pax header");
goto fail;