]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
libarchive/{b64,uu}: Improve atol8 checks 2911/head
authorTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 16 Mar 2026 15:00:30 +0000 (16:00 +0100)
committerTobias Stoeckmann <tobias@stoeckmann.org>
Mon, 16 Mar 2026 15:53:29 +0000 (16:53 +0100)
Make sure that supplied values cannot overflow int64_t, which would be
an undefined behavior. Also do not accept empty strings as numbers.

Last but not least, check values before casting them to target data
types to avoid truncations.

Signed-off-by: Tobias Stoeckmann <tobias@stoeckmann.org>
libarchive/archive_write_add_filter_b64encode.c
libarchive/archive_write_add_filter_uuencode.c

index dbedf9d305c30d304afe330b9e4703d47ea61fdb..d2c4742d2ef6bdea38c43eccdcd7ac94ba4083e3 100644 (file)
@@ -28,6 +28,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -116,12 +119,20 @@ archive_filter_b64encode_options(struct archive_write_filter *f, const char *key
        struct private_b64encode *state = (struct private_b64encode *)f->data;
 
        if (strcmp(key, "mode") == 0) {
+               int64_t val;
+
                if (value == NULL) {
                        archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
                            "mode option requires octal digits");
                        return (ARCHIVE_FAILED);
                }
-               state->mode = (int)atol8(value, strlen(value)) & 0777;
+               val = atol8(value, strlen(value));
+               if (val < 0 || val > INT_MAX) {
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "invalid mode option");
+                       return (ARCHIVE_FAILED);
+               }
+               state->mode = (int)val & 0777;
                return (ARCHIVE_OK);
        } else if (strcmp(key, "name") == 0) {
                if (value == NULL) {
@@ -286,14 +297,19 @@ atol8(const char *p, size_t char_cnt)
 {
        int64_t l;
        int digit;
-        
+
+       if (char_cnt == 0)
+               return (-1);
+
        l = 0;
        while (char_cnt-- > 0) {
                if (*p >= '0' && *p <= '7')
                        digit = *p - '0';
                else
-                       break;
+                       return (-1);
                p++;
+               if (l > (INT64_MAX >> 3))
+                       return (-1);
                l <<= 3;
                l |= digit;
        }
index 99c7a2cb7a7ece680404b471fbd383e3035980eb..d25236fa9b26fb3b53eb3a759971413a3508523e 100644 (file)
@@ -28,6 +28,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
 #endif
@@ -105,12 +108,20 @@ archive_filter_uuencode_options(struct archive_write_filter *f, const char *key,
        struct private_uuencode *state = (struct private_uuencode *)f->data;
 
        if (strcmp(key, "mode") == 0) {
+               int64_t val;
+
                if (value == NULL) {
                        archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
                            "mode option requires octal digits");
                        return (ARCHIVE_FAILED);
                }
-               state->mode = (int)atol8(value, strlen(value)) & 0777;
+               val = atol8(value, strlen(value));
+               if (val < 0 || val > INT_MAX) {
+                       archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+                           "invalid mode option");
+                       return (ARCHIVE_FAILED);
+               }
+               state->mode = (int)val & 0777;
                return (ARCHIVE_OK);
        } else if (strcmp(key, "name") == 0) {
                if (value == NULL) {
@@ -277,14 +288,19 @@ atol8(const char *p, size_t char_cnt)
 {
        int64_t l;
        int digit;
-        
+
+       if (char_cnt == 0)
+               return (-1);
+
        l = 0;
        while (char_cnt-- > 0) {
                if (*p >= '0' && *p <= '7')
                        digit = *p - '0';
                else
-                       break;
+                       return (-1);
                p++;
+               if (l > (INT64_MAX >> 3))
+                       return (-1);
                l <<= 3;
                l |= digit;
        }