]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Handle all negative int64_t values in mtree/tar 1542/head
authorSamanta Navarro <ferivoz@riseup.net>
Tue, 1 Jun 2021 11:25:03 +0000 (11:25 +0000)
committerSamanta Navarro <ferivoz@riseup.net>
Tue, 1 Jun 2021 11:25:03 +0000 (11:25 +0000)
The variable last_digit_limit is negative since INT64_MIN itself is
negative as well. This means that the last digit after "limit" always
leads to maxval.

Turning last_digit_limit positive in itself is not sufficient because
it would lead to a signed integer overflow during shift operation.

If limit is reached and the last digit is last_digit_limit, the number
is at least maxval. The already existing if condition for even larger
(or smaller) values can be reused to prevent the last shift.

In my humble opinion it might make sense to reduce duplicated code and
keep it separated in a utility source file for shared use.

libarchive/archive_read_support_format_mtree.c
libarchive/archive_read_support_format_tar.c

index c5ce01853c84cfee214b66dd9c3d55421ab92ba0..94ecc9b7958e37776d36c12bc6700165757a6b3e 100644 (file)
@@ -2035,13 +2035,13 @@ mtree_atol(char **p, int base)
 
        if (**p == '-') {
                limit = INT64_MIN / base;
-               last_digit_limit = INT64_MIN % base;
+               last_digit_limit = -(INT64_MIN % base);
                ++(*p);
 
                l = 0;
                digit = parsedigit(**p);
                while (digit >= 0 && digit < base) {
-                       if (l < limit || (l == limit && digit > last_digit_limit))
+                       if (l < limit || (l == limit && digit >= last_digit_limit))
                                return INT64_MIN;
                        l = (l * base) - digit;
                        digit = parsedigit(*++(*p));
index 96d8101844fb59279a948ae87d3d7d8dd84708c3..44dca01e20c2777f57f4cb45146b2cd30808ae58 100644 (file)
@@ -2643,14 +2643,14 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
 
                maxval = INT64_MIN;
                limit = -(INT64_MIN / base);
-               last_digit_limit = INT64_MIN % base;
+               last_digit_limit = -(INT64_MIN % base);
        }
 
        l = 0;
        if (char_cnt != 0) {
                digit = *p - '0';
                while (digit >= 0 && digit < base  && char_cnt != 0) {
-                       if (l>limit || (l == limit && digit > last_digit_limit)) {
+                       if (l>limit || (l == limit && digit >= last_digit_limit)) {
                                return maxval; /* Truncate on overflow. */
                        }
                        l = (l * base) + digit;