diff -Naur libarchive-3.7.7/libarchive/archive_read_support_format_tar.c libarchive-3.7.7-patch/libarchive/archive_read_support_format_tar.c --- libarchive-3.7.7/libarchive/archive_read_support_format_tar.c 2026-08-18 08:43:36.246102967 +0200 +++ libarchive-3.7.7-patch/libarchive/archive_read_support_format_tar.c 2026-08-18 08:49:13.860883568 +0200 @@ -42,6 +42,7 @@ #include "archive_acl_private.h" /* For ACL parsing routines. */ #include "archive_entry.h" #include "archive_entry_locale.h" +#include "archive_integer.h" #include "archive_private.h" #include "archive_read_private.h" @@ -3246,13 +3247,10 @@ return (ARCHIVE_FATAL); tar->sparse_last->hole = hole; } - if (length == 0 || *e == '\n') { - if (length == 0 && *e == '\n') { - return (ARCHIVE_OK); - } else { - return (ARCHIVE_WARN); - } - } + if (length == 0) + return (ARCHIVE_OK); + if (*e == '\n') + return (ARCHIVE_WARN); p = e + 1; length--; hole = hole == 0; @@ -3296,13 +3294,9 @@ static int64_t tar_atol_base_n(const char *p, size_t char_cnt, int base) { - int64_t l, maxval, limit, last_digit_limit; + int64_t l; int digit, sign; - maxval = INT64_MAX; - limit = INT64_MAX / base; - last_digit_limit = INT64_MAX % base; - /* the pointer will not be dereferenced if char_cnt is zero * due to the way the && operator is evaluated. */ @@ -3316,25 +3310,22 @@ sign = -1; p++; char_cnt--; - - maxval = INT64_MIN; - limit = -(INT64_MIN / base); - last_digit_limit = -(INT64_MIN % base); } l = 0; - if (char_cnt != 0) { + while (char_cnt != 0) { digit = *p - '0'; - while (digit >= 0 && digit < base && char_cnt != 0) { - if (l>limit || (l == limit && digit >= last_digit_limit)) { - return maxval; /* Truncate on overflow. */ - } - l = (l * base) + digit; - digit = *++p - '0'; - char_cnt--; + if (digit < 0 || digit >= base) + break; + if (archive_ckd_mul_i64(&l, l, base) || + archive_ckd_add_i64(&l, l, sign * digit)) { + /* Truncate on overflow. */ + return sign < 0 ? INT64_MIN : INT64_MAX; } + p++; + char_cnt--; } - return (sign < 0) ? -l : l; + return l; } static int64_t