From 1241138f64ccfe518e2768dd6ae9b6a61dc4654a Mon Sep 17 00:00:00 2001 From: Daniel Handzus Date: Fri, 14 Aug 2026 14:54:50 +0200 Subject: [PATCH] Fix for CVE-2026-15028 and CVE-2026-16517 Patches in the upstream archive_integer.h library, which both CVE fixes depend on. Resolves: RHEL-215400 Resolves: RHEL-215640 --- 0009-add-archive-integer-library.patch | 295 +++++++++++++++++++++++++ 0010-Fix-CVE-2026-15028.patch | 80 +++++++ 0011-Fix-CVE-2026-16517.patch | 37 ++++ libarchive.spec | 13 +- 4 files changed, 424 insertions(+), 1 deletion(-) create mode 100644 0009-add-archive-integer-library.patch create mode 100644 0010-Fix-CVE-2026-15028.patch create mode 100644 0011-Fix-CVE-2026-16517.patch diff --git a/0009-add-archive-integer-library.patch b/0009-add-archive-integer-library.patch new file mode 100644 index 0000000..e832443 --- /dev/null +++ b/0009-add-archive-integer-library.patch @@ -0,0 +1,295 @@ +diff -Naur libarchive-3.7.7/build/cmake/config.h.in libarchive-3.7.7-patch/build/cmake/config.h.in +--- libarchive-3.7.7/build/cmake/config.h.in 2024-10-13 10:11:23.000000000 +0200 ++++ libarchive-3.7.7-patch/build/cmake/config.h.in 2026-08-14 11:15:24.888782201 +0200 +@@ -675,6 +675,9 @@ + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_ICONV_H 1 + ++/* Define to 1 if you have the header file. */ ++#cmakedefine HAVE_INTSAFE_H 1 ++ + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_INTTYPES_H 1 + +@@ -1007,6 +1010,9 @@ + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_STDARG_H 1 + ++/* Define to 1 if you have the header file. */ ++#cmakedefine HAVE_STDCKDINT_H 1 ++ + /* Define to 1 if you have the header file. */ + #cmakedefine HAVE_STDINT_H 1 + +diff -Naur libarchive-3.7.7/CMakeLists.txt libarchive-3.7.7-patch/CMakeLists.txt +--- libarchive-3.7.7/CMakeLists.txt 2024-10-13 10:11:23.000000000 +0200 ++++ libarchive-3.7.7-patch/CMakeLists.txt 2026-08-14 11:15:21.584802470 +0200 +@@ -736,6 +736,7 @@ + #include + int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS) + ++LA_CHECK_INCLUDE_FILE("intsafe.h" HAVE_INTSAFE_H) + LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H) + LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H) + LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H) +@@ -750,6 +751,7 @@ + LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H) + LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H) + LA_CHECK_INCLUDE_FILE("stdarg.h" HAVE_STDARG_H) ++LA_CHECK_INCLUDE_FILE("stdckdint.h" HAVE_STDCKDINT_H) + LA_CHECK_INCLUDE_FILE("stdint.h" HAVE_STDINT_H) + LA_CHECK_INCLUDE_FILE("stdlib.h" HAVE_STDLIB_H) + LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H) +diff -Naur libarchive-3.7.7/configure.ac libarchive-3.7.7-patch/configure.ac +--- libarchive-3.7.7/configure.ac 2026-08-14 11:14:36.768077404 +0200 ++++ libarchive-3.7.7-patch/configure.ac 2026-08-14 11:15:26.649771398 +0200 +@@ -363,9 +363,9 @@ + [AC_DEFINE_UNQUOTED([HAVE_WORKING_FS_IOC_GETFLAGS], [1], + [Define to 1 if you have a working FS_IOC_GETFLAGS])]) + +-AC_CHECK_HEADERS([locale.h membership.h paths.h poll.h pthread.h pwd.h]) +-AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h]) +-AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h]) ++AC_CHECK_HEADERS([intsafe.h locale.h membership.h paths.h poll.h pthread.h]) ++AC_CHECK_HEADERS([pwd.h readpassphrase.h signal.h spawn.h]) ++AC_CHECK_HEADERS([stdarg.h stdckdint.h stdint.h stdlib.h string.h]) + AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/ea.h sys/extattr.h]) + AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h]) + AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h]) +diff -Naur libarchive-3.7.7/libarchive/archive_integer.h libarchive-3.7.7-patch/libarchive/archive_integer.h +--- libarchive-3.7.7/libarchive/archive_integer.h 1970-01-01 01:00:00.000000000 +0100 ++++ libarchive-3.7.7-patch/libarchive/archive_integer.h 2026-08-14 11:15:01.283882136 +0200 +@@ -0,0 +1,211 @@ ++/*- ++ * Copyright (c) 2026 Tobias Stoeckmann ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE ++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ * SUCH DAMAGE. ++ */ ++ ++#ifndef ARCHIVE_INTEGER_H_INCLUDED ++#define ARCHIVE_INTEGER_H_INCLUDED ++ ++#include "archive_platform.h" ++ ++/* Note: This is a purely internal header! */ ++/* Do not use this outside of libarchive internal code! */ ++ ++#ifndef __LIBARCHIVE_BUILD ++#error This header is only to be used internally to libarchive. ++#endif ++ ++#ifdef HAVE_INTSAFE_H ++#define ENABLE_INTSAFE_SIGNED_FUNCTIONS ++#include ++#endif ++#ifdef HAVE_LIMITS_H ++#include ++#endif ++#ifdef HAVE_STDCKDINT_H ++#include ++#endif ++#ifdef HAVE_STDINT_H ++#include ++#endif ++#ifdef HAVE_UNISTD_H ++#include ++#endif ++ ++#ifndef __has_builtin ++#define __has_builtin(x) 0 ++#endif ++ ++#ifdef HAVE_STDCKDINT_H ++#define USE_STDCKDINT 1 ++#elif (__GNUC__ >= 5 && !defined(__INTEL_COMPILER)) ++#define USE_BUILTIN 1 ++#elif __has_builtin(__builtin_add_overflow) ++#define USE_BUILTIN 1 ++#elif defined HAVE_INTSAFE_H ++#define USE_INTSAFE 1 ++#endif ++ ++/* ++ * Disabling inline keyword for compilers known to choke on it: ++ * - Watcom C++ in C code. (For any version?) ++ * - SGI MIPSpro ++ * - Microsoft Visual C++ 6.0 (supposedly newer versions too) ++ * - IBM VisualAge 6 (XL v6) ++ * - Sun WorkShop C (SunPro) before 5.9 ++ */ ++#if defined(__WATCOMC__) || defined(__sgi) || defined(__hpux) || defined(__BORLANDC__) ++#define inline ++#elif defined(__IBMC__) && __IBMC__ < 700 ++#define inline ++#elif defined(__SUNPRO_C) && __SUNPRO_C < 0x590 ++#define inline ++#elif defined(_MSC_VER) || defined(__osf__) ++#define inline __inline ++#endif ++ ++/* Returns 0 on success, a non-zero value otherwise. */ ++static inline int ++archive_ckd_add_i64(int64_t *result, int64_t a, int64_t b) ++{ ++#if USE_STDCKDINT ++ return ckd_add(result, a, b); ++#elif USE_BUILTIN ++ return __builtin_add_overflow(a, b, result); ++#elif USE_INTSAFE ++ LONGLONG res; ++ int ret; ++ ++ ret = LongLongAdd(a, b, &res); ++ *result = (int64_t)res; ++ return ret; ++#else ++ if ((b > 0 && a > INT64_MAX - b) || ++ (b < 0 && a < INT64_MIN - b)) ++ return 1; ++ ++ *result = a + b; ++ return 0; ++#endif ++} ++ ++/* Returns 0 on success, a non-zero value otherwise. */ ++static inline int ++archive_ckd_add_u64(uint64_t *result, uint64_t a, uint64_t b) ++{ ++#if USE_STDCKDINT ++ return ckd_add(result, a, b); ++#elif USE_BUILTIN ++ return __builtin_add_overflow(a, b, result); ++#elif USE_INTSAFE ++ ULONGLONG res; ++ int ret; ++ ++ ret = ULongLongAdd(a, b, &res); ++ *result = (uint64_t)res; ++ return ret; ++#else ++ if (a > UINT64_MAX - b) ++ return 1; ++ *result = a + b; ++ return 0; ++#endif ++} ++ ++/* Returns 0 on success, a non-zero value otherwise. */ ++static inline int ++archive_ckd_mul_i64(int64_t *result, int64_t a, int64_t b) ++{ ++#if USE_STDCKDINT ++ return ckd_mul(result, a, b); ++#elif USE_BUILTIN ++ return __builtin_mul_overflow(a, b, result); ++#elif USE_INTSAFE ++ LONGLONG res; ++ int ret; ++ ++ ret = LongLongMult(a, b, &res); ++ *result = (int64_t)res; ++ return ret; ++#else ++ if ((a > 0 && b > 0 && a > INT64_MAX / b) || ++ (a < 0 && b > 0 && a < INT64_MIN / b) || ++ (a > 0 && b < 0 && b < INT64_MIN / a) || ++ (a < 0 && b < 0 && a < INT64_MAX / b)) ++ return 1; ++ ++ *result = a * b; ++ return 0; ++#endif ++} ++ ++/* Returns 0 on success, a non-zero value otherwise. */ ++static inline int ++archive_ckd_mul_u64(uint64_t *result, uint64_t a, uint64_t b) ++{ ++#if USE_STDCKDINT ++ return ckd_mul(result, a, b); ++#elif USE_BUILTIN ++ return __builtin_mul_overflow(a, b, result); ++#elif USE_INTSAFE ++ ULONGLONG res; ++ int ret; ++ ++ ret = ULongLongMult(a, b, &res); ++ *result = (uint64_t)res; ++ return ret; ++#else ++ if (b != 0 && a > UINT64_MAX / b) ++ return 1; ++ *result = a * b; ++ return 0; ++#endif ++} ++ ++/* Returns 0 on success, a non-zero value otherwise. */ ++static inline int ++archive_ckd_sub_i64(int64_t *result, int64_t a, int64_t b) ++{ ++#if USE_STDCKDINT ++ return ckd_sub(result, a, b); ++#elif USE_BUILTIN ++ return __builtin_sub_overflow(a, b, result); ++#elif USE_INTSAFE ++ LONGLONG res; ++ int ret; ++ ++ ret = LongLongSub(a, b, &res); ++ *result = (int64_t)res; ++ return ret; ++#else ++ if ((b > 0 && a < INT64_MIN + b) || ++ (b < 0 && a > INT64_MAX + b)) ++ return 1; ++ ++ *result = a - b; ++ return 0; ++#endif ++} ++ ++#endif +diff -Naur libarchive-3.7.7/libarchive/CMakeLists.txt libarchive-3.7.7-patch/libarchive/CMakeLists.txt +--- libarchive-3.7.7/libarchive/CMakeLists.txt 2024-10-13 10:11:23.000000000 +0200 ++++ libarchive-3.7.7-patch/libarchive/CMakeLists.txt 2026-08-14 11:15:17.963824683 +0200 +@@ -42,6 +42,7 @@ + archive_getdate.h + archive_hmac.c + archive_hmac_private.h ++ archive_integer.h + archive_match.c + archive_openssl_evp_private.h + archive_openssl_hmac_private.h +diff -Naur libarchive-3.7.7/Makefile.am libarchive-3.7.7-patch/Makefile.am +--- libarchive-3.7.7/Makefile.am 2026-08-14 11:14:36.789077275 +0200 ++++ libarchive-3.7.7-patch/Makefile.am 2026-08-14 11:15:16.857831468 +0200 +@@ -122,6 +122,7 @@ + libarchive/archive_getdate.h \ + libarchive/archive_hmac.c \ + libarchive/archive_hmac_private.h \ ++ libarchive/archive_integer.h \ + libarchive/archive_match.c \ + libarchive/archive_openssl_evp_private.h \ + libarchive/archive_openssl_hmac_private.h \ diff --git a/0010-Fix-CVE-2026-15028.patch b/0010-Fix-CVE-2026-15028.patch new file mode 100644 index 0000000..7b24775 --- /dev/null +++ b/0010-Fix-CVE-2026-15028.patch @@ -0,0 +1,80 @@ +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 diff --git a/0011-Fix-CVE-2026-16517.patch b/0011-Fix-CVE-2026-16517.patch new file mode 100644 index 0000000..b38fe1d --- /dev/null +++ b/0011-Fix-CVE-2026-16517.patch @@ -0,0 +1,37 @@ +diff --git a/libarchive/archive_write_set_format_zip.c b/libarchive/archive_write_set_format_zip.c +index a9f2877..e267736 100644 +--- a/libarchive/archive_write_set_format_zip.c ++++ b/libarchive/archive_write_set_format_zip.c +@@ -53,6 +53,7 @@ + #include "archive_entry.h" + #include "archive_entry_locale.h" + #include "archive_hmac_private.h" ++#include "archive_integer.h" + #include "archive_private.h" + #include "archive_random_private.h" + #include "archive_write_private.h" +@@ -714,8 +715,13 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) + default: + break; + } +- if (zip->entry_compression == COMPRESSION_STORE) +- zip->entry_compressed_size += additional_size; ++ if (zip->entry_compression == COMPRESSION_STORE && ++ archive_ckd_add_i64(&zip->entry_compressed_size, ++ zip->entry_compressed_size, additional_size)) { ++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, ++ "File size too large for encrypted ZIP entry"); ++ return (ARCHIVE_FAILED); ++ } + } + + /* +@@ -729,7 +735,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) + * (compression might make file larger) + */ + if ((zip->flags & ZIP_FLAG_FORCE_ZIP64) +- || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX) ++ || (zip->entry_uncompressed_size > ZIP_4GB_MAX - additional_size) + || (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED + && zip->entry_compression != COMPRESSION_STORE)) { + MIN_VERSION_NEEDED(45); diff --git a/libarchive.spec b/libarchive.spec index 4cb910f..e80bc33 100644 --- a/libarchive.spec +++ b/libarchive.spec @@ -2,7 +2,7 @@ Name: libarchive Version: 3.7.7 -Release: 10%{?dist} +Release: 11%{?dist} Summary: A library for handling streaming archive formats # Licenses: @@ -59,6 +59,14 @@ Patch0006: 0006-Fix-CVE-2026-4424.patch Patch0007: 0007-Fix-CVE-2026-14164_part1.patch # Source: https://github.com/libarchive/libarchive/pull/3071/changes/1c914cdfef533cbee1ae3aa21a89ba02ed4d5f61 Patch0008: 0008-Fix-CVE-2026-14164_part2.patch +# Source: https://github.com/libarchive/libarchive/commit/16be3385236bb37bb3a2b6f9fa80aac98fd12e78 +# library necessary for CVE fixes in patch0010 and patch0011 +Patch0009: 0009-add-archive-integer-library.patch +# Source: https://github.com/libarchive/libarchive/pull/3253/changes/f93abd161ec37326c566f4f0efcd44fe7a66dd95 +# and https://github.com/libarchive/libarchive/pull/3252/changes/40b92de1def08e4fc319d55702785f82cedb7ef2 +Patch0010: 0010-Fix-CVE-2026-15028.patch +# Source: https://github.com/libarchive/libarchive/pull/3228/changes/1c6e7b491f60fce335c20a9692f870d1f1ca39aa +Patch0011: 0011-Fix-CVE-2026-16517.patch %description Libarchive is a programming library that can create and read several different @@ -268,6 +276,9 @@ run_testsuite %changelog +* Wed Aug 12 2026 Daniel Handzus - 3.7.7-11 +- Related: CVE-2026-16517 and CVE-2026-15028 + * Wed Jul 15 2026 Pavol Sloboda - 3.7.7-10 - Related: CVE-2026-14164