diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-13 13:52:33 +0100 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-12-13 13:52:33 +0100 |
commit | 7ab411dbd2cb066652f5f51a1bc6cc793b7cafad (patch) | |
tree | 39378c7700247c5a5b2163d26695c4e00f97a1ca /lib/tar | |
parent | ba04f24b3cab65081facdb2c726f023bdb9e7b48 (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.c | 46 |
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; |