diff options
author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-24 00:55:03 +0200 |
---|---|---|
committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2019-07-24 01:03:42 +0200 |
commit | d6f15cb9b054ed76b5bee2e6924d4b0b2a5e52ae (patch) | |
tree | 04bd67a5893cb4c2790a01fe14f93ca69dc97e1c /lib/tar/checksum.c | |
parent | e6c869ab1753986b032463f2e0bd5fad7bc70e0f (diff) |
libtar: more lenient tar checksum verification
Until now, the tar checksum verification simply copied the header,
recomputed the checksum and compared it byte-for-byte with the
original.
However, not all implementations store the checksum the same way. For
instance, git-archive generates tar balls that use the same format as
for other octal numbers.
This patch makes the checksum verification more lenient by parsing the
checksum from the header and comparing it with the computed value
instead of copying the entire block and insisting on byte-for-byte
equivalence.
The result is better interoperabillity with existing tools and perhaps
slightly faster processing since the block doesn't have to be copied.
Reported-by: Matt Turner <mattst88@gmail.com>
Suggested-by: René Scharfe <l.s.r@web.de>
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/tar/checksum.c')
-rw-r--r-- | lib/tar/checksum.c | 31 |
1 files changed, 22 insertions, 9 deletions
diff --git a/lib/tar/checksum.c b/lib/tar/checksum.c index a2a101a..af94ab4 100644 --- a/lib/tar/checksum.c +++ b/lib/tar/checksum.c @@ -1,15 +1,27 @@ /* SPDX-License-Identifier: GPL-3.0-or-later */ #include "internal.h" -void update_checksum(tar_header_t *hdr) +static unsigned int get_checksum(const tar_header_t *hdr) { + const unsigned char *header_start = (const unsigned char *)hdr; + const unsigned char *chksum_start = (const unsigned char *)hdr->chksum; + const unsigned char *header_end = header_start + sizeof(*hdr); + const unsigned char *chksum_end = chksum_start + sizeof(hdr->chksum); + const unsigned char *p; unsigned int chksum = 0; - size_t i; - memset(hdr->chksum, ' ', sizeof(hdr->chksum)); + for (p = header_start; p < chksum_start; p++) + chksum += *p; + for (; p < chksum_end; p++) + chksum += ' '; + for (; p < header_end; p++) + chksum += *p; + return chksum; +} - for (i = 0; i < sizeof(*hdr); ++i) - chksum += ((unsigned char *)hdr)[i]; +void update_checksum(tar_header_t *hdr) +{ + unsigned int chksum = get_checksum(hdr); sprintf(hdr->chksum, "%06o", chksum); hdr->chksum[6] = '\0'; @@ -18,9 +30,10 @@ void update_checksum(tar_header_t *hdr) bool is_checksum_valid(const tar_header_t *hdr) { - tar_header_t copy; + unsigned int calculated_chksum = get_checksum(hdr); + uint64_t read_chksum; - memcpy(©, hdr, sizeof(*hdr)); - update_checksum(©); - return memcmp(hdr, ©, sizeof(*hdr)) == 0; + if (read_octal(hdr->chksum, sizeof(hdr->chksum), &read_chksum)) + return 0; + return read_chksum == calculated_chksum; } |