From 19ddc52756abe89ae0babc21ae3d1ca1b9b750bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Wed, 11 Jun 2025 20:35:46 +0200 Subject: [PATCH] Resolves: RHEL-45756 - Varnish consumes significantly more memory under RHEL8/9 --- .gitignore | 1 + jemalloc-5.3.0-aarch64-ts-segfault.patch | 140 +++++++++++++++++++++++ jemalloc-5.3.0_fno-builtin.patch | 29 +++++ sources | 1 + varnish.spec | 128 ++++++++++++++++++++- 5 files changed, 294 insertions(+), 5 deletions(-) create mode 100644 jemalloc-5.3.0-aarch64-ts-segfault.patch create mode 100644 jemalloc-5.3.0_fno-builtin.patch diff --git a/.gitignore b/.gitignore index db5dd04..74593e5 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,4 @@ varnish-2.1.3.tar.gz /varnish-7.6.0.tgz /pkg-varnish-cache-7d90347.tar.gz /varnish-7.6.1.tgz +/jemalloc-5.3.0.tar.bz2 diff --git a/jemalloc-5.3.0-aarch64-ts-segfault.patch b/jemalloc-5.3.0-aarch64-ts-segfault.patch new file mode 100644 index 0000000..624f4ff --- /dev/null +++ b/jemalloc-5.3.0-aarch64-ts-segfault.patch @@ -0,0 +1,140 @@ +diff --git a/test/unit/psset.c b/test/unit/psset.c +index 6ff7201..58b4a88 100644 +--- a/test/unit/psset.c ++++ b/test/unit/psset.c +@@ -124,7 +124,7 @@ TEST_BEGIN(test_fill) { + hpdata_t pageslab; + hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); + +- edata_t alloc[HUGEPAGE_PAGES]; ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + psset_t psset; + psset_init(&psset); +@@ -147,6 +147,8 @@ TEST_BEGIN(test_fill) { + edata_init_test(&extra_alloc); + err = test_psset_alloc_reuse(&psset, &extra_alloc, PAGE); + expect_true(err, "Alloc succeeded even though psset should be empty"); ++ ++ free(alloc); + } + TEST_END + +@@ -157,7 +159,7 @@ TEST_BEGIN(test_reuse) { + hpdata_t pageslab; + hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); + +- edata_t alloc[HUGEPAGE_PAGES]; ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + psset_t psset; + psset_init(&psset); +@@ -239,6 +241,8 @@ TEST_BEGIN(test_reuse) { + err = test_psset_alloc_reuse(&psset, &alloc[index_of_4], 4 * PAGE); + expect_false(err, "Should have been able to find alloc."); + edata_expect(&alloc[index_of_4], index_of_4, 4); ++ ++ free(alloc); + } + TEST_END + +@@ -249,7 +253,7 @@ TEST_BEGIN(test_evict) { + hpdata_t pageslab; + hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); + +- edata_t alloc[HUGEPAGE_PAGES]; ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + psset_t psset; + psset_init(&psset); +@@ -273,6 +277,8 @@ TEST_BEGIN(test_evict) { + + err = test_psset_alloc_reuse(&psset, &alloc[0], PAGE); + expect_true(err, "psset should be empty."); ++ ++ free(alloc); + } + TEST_END + +@@ -286,7 +292,9 @@ TEST_BEGIN(test_multi_pageslab) { + (void *)((uintptr_t)PAGESLAB_ADDR + HUGEPAGE), + PAGESLAB_AGE + 1); + +- edata_t alloc[2][HUGEPAGE_PAGES]; ++ edata_t* alloc[2]; ++ alloc[0] = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); ++ alloc[1] = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + psset_t psset; + psset_init(&psset); +@@ -336,6 +344,9 @@ TEST_BEGIN(test_multi_pageslab) { + */ + err = test_psset_alloc_reuse(&psset, &alloc[1][0], 2 * PAGE); + expect_false(err, "Allocation should have succeeded"); ++ ++ free(alloc[0]); ++ free(alloc[1]); + } + TEST_END + +@@ -385,7 +396,7 @@ TEST_BEGIN(test_stats) { + hpdata_t pageslab; + hpdata_init(&pageslab, PAGESLAB_ADDR, PAGESLAB_AGE); + +- edata_t alloc[HUGEPAGE_PAGES]; ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + psset_t psset; + psset_init(&psset); +@@ -415,6 +426,8 @@ TEST_BEGIN(test_stats) { + stats_expect(&psset, 0); + psset_update_end(&psset, &pageslab); + stats_expect(&psset, 1); ++ ++ free(alloc); + } + TEST_END + +@@ -475,8 +488,8 @@ init_test_pageslabs(psset_t *psset, hpdata_t *pageslab, + + TEST_BEGIN(test_oldest_fit) { + bool err; +- edata_t alloc[HUGEPAGE_PAGES]; +- edata_t worse_alloc[HUGEPAGE_PAGES]; ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); ++ edata_t *worse_alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); + + hpdata_t pageslab; + hpdata_t worse_pageslab; +@@ -493,14 +506,19 @@ TEST_BEGIN(test_oldest_fit) { + expect_false(err, "Nonempty psset failed page allocation"); + expect_ptr_eq(&pageslab, edata_ps_get(&test_edata), + "Allocated from the wrong pageslab"); ++ ++ free(alloc); ++ free(worse_alloc); + } + TEST_END + + TEST_BEGIN(test_insert_remove) { + bool err; + hpdata_t *ps; +- edata_t alloc[HUGEPAGE_PAGES]; +- edata_t worse_alloc[HUGEPAGE_PAGES]; ++ ++ edata_t *alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); ++ edata_t *worse_alloc = (edata_t *)malloc(sizeof(edata_t) * HUGEPAGE_PAGES); ++ + + hpdata_t pageslab; + hpdata_t worse_pageslab; +@@ -539,6 +557,9 @@ TEST_BEGIN(test_insert_remove) { + psset_update_begin(&psset, &worse_pageslab); + err = test_psset_alloc_reuse(&psset, &alloc[HUGEPAGE_PAGES - 1], PAGE); + expect_true(err, "psset should be empty, but an alloc succeeded"); ++ ++ free(alloc); ++ free(worse_alloc); + } + TEST_END + diff --git a/jemalloc-5.3.0_fno-builtin.patch b/jemalloc-5.3.0_fno-builtin.patch new file mode 100644 index 0000000..b938dff --- /dev/null +++ b/jemalloc-5.3.0_fno-builtin.patch @@ -0,0 +1,29 @@ +commit 3de0c24859f4413bf03448249078169bb50bda0f +Author: divanorama +Date: Thu Sep 29 23:35:59 2022 +0200 + + Disable builtin malloc in tests + + With `--with-jemalloc-prefix=` and without `-fno-builtin` or `-O1` both clang and gcc may optimize out `malloc` calls + whose result is unused. Comparing result to NULL also doesn't necessarily count as being used. + + This won't be a problem in most client programs as this only concerns really unused pointers, but in + tests it's important to actually execute allocations. + `-fno-builtin` should disable this optimization for both gcc and clang, and applying it only to tests code shouldn't hopefully be an issue. + Another alternative is to force "use" of result but that'd require more changes and may miss some other optimization-related issues. + + This should resolve https://github.com/jemalloc/jemalloc/issues/2091 + +diff --git a/Makefile.in b/Makefile.in +index 6809fb29..a964f07e 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -458,6 +458,8 @@ $(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c + $(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp + $(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include + $(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include ++$(TESTS_OBJS): CFLAGS += -fno-builtin ++$(TESTS_CPP_OBJS): CPPFLAGS += -fno-builtin + ifneq ($(IMPORTLIB),$(SO)) + $(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT + endif diff --git a/sources b/sources index cf0ad93..6665ec2 100644 --- a/sources +++ b/sources @@ -1,2 +1,3 @@ SHA512 (varnish-7.6.1.tgz) = a43ecdcc5a113b947d56a7f28d756199c82e702a0e98bbad635a5df4739c50aaf778143dee3acf57d586569b780615ed73996df71488e4f776fb515f206b7fca SHA512 (pkg-varnish-cache-7d90347.tar.gz) = c5bf026bb50b416001d0e22e56c2774c143dab1f4658f03f1a4e6578369b71cfda5854b7d6b580c43c2ab8e68bfb9033b56734adfd29ac0fddc61fd6b1b4b0c0 +SHA512 (jemalloc-5.3.0.tar.bz2) = 22907bb052096e2caffb6e4e23548aecc5cc9283dce476896a2b1127eee64170e3562fa2e7db9571298814a7a2c7df6e8d1fbe152bd3f3b0c1abec22a2de34b1 diff --git a/varnish.spec b/varnish.spec index 58d92c1..5cb2d30 100644 --- a/varnish.spec +++ b/varnish.spec @@ -23,11 +23,24 @@ # Default: Use jemalloc, as adviced by upstream project # Change to 1 to use system allocator (ie. glibc) %if 0%{?rhel} -%bcond_without system_allocator + %if 0%{?rhel} > 9 + # for rhel >= 10, use bundled jemalloc + %bcond_with system_allocator + %bcond_without bundled_jemalloc + %else + # for rhel <= 9, use system allocator + %bcond_without system_allocator + %bcond_with bundled_jemalloc + %endif %else -%bcond_with system_allocator + # use jemalloc from repo + %bcond_with system_allocator + %bcond_with bundled_jemalloc %endif +%define jemalloc_version 5.3.0 +%define jemalloc_prefix varnish_ + %if %{with system_allocator} # use _lto_cflags if present %else @@ -37,13 +50,20 @@ Summary: High-performance HTTP accelerator Name: varnish Version: 7.6.1 -Release: 3%{?dist} +Release: 4%{?dist} License: BSD-2-Clause AND (BSD-2-Clause-FreeBSD AND BSD-3-Clause AND LicenseRef-Fedora-Public-Domain AND Zlib) URL: https://www.varnish-cache.org/ Source0: http://varnish-cache.org/_downloads/%{name}-%{version}.tgz Source1: https://github.com/varnishcache/pkg-varnish-cache/archive/%{commit1}.tar.gz#/pkg-varnish-cache-%{shortcommit1}.tar.gz +Source2: https://github.com/jemalloc/jemalloc/releases/download/%{jemalloc_version}/jemalloc-%{jemalloc_version}.tar.bz2 # Patches: +%if %{with bundled_jemalloc} +# bundled jemalloc patch +Patch1: jemalloc-5.3.0_fno-builtin.patch +Patch2: jemalloc-5.3.0-aarch64-ts-segfault.patch +%endif + # https://bugzilla.redhat.com/show_bug.cgi?id=2364235 Patch100: varnish-7.6.1-CVE-2025-47905.patch @@ -64,6 +84,10 @@ Provides: vmod(unix)%{_isa} = %{version}-%{release} Provides: vmod(vtc)%{_isa} = %{version}-%{release} %endif +%if %{with bundled_jemalloc} +Provides: bundled(jemalloc) +%endif + %if 0%{?rhel} == 7 BuildRequires: python34 python34-sphinx python34-docutils @@ -74,10 +98,12 @@ BuildRequires: gcc %if %{with system_allocator} # use glibc %else +%if %{without bundled_jemalloc} %ifnarch aarch64 BuildRequires: jemalloc-devel %endif %endif +%endif BuildRequires: libedit-devel BuildRequires: make @@ -86,6 +112,11 @@ BuildRequires: pcre2-devel BuildRequires: pkgconfig BuildRequires: systemd-units +%if %{with bundled_jemalloc} +BuildRequires: /usr/bin/xsltproc +BuildRequires: perl-generators +%endif + # Extra requirements for the build suite # needs haproxy2 %if 0%{?fedora} > 30 || 0%{?rhel} > 8 @@ -109,8 +140,10 @@ Requires(postun): systemd-units %if %{with system_allocator} # use glibc %else +%if %{without bundled_jemalloc} Requires: jemalloc %endif +%endif %description This is Varnish Cache, a high-performance HTTP accelerator. @@ -152,7 +185,55 @@ sed -i 's,rst2man-3.6,rst2man-3.4,g; s,rst2html-3.6,rst2html-3.4,g; s,phinx-buil %patch 100 -p1 -b .CVE-2022-45060 +# jemalloc +%if %{with bundled_jemalloc} +tar xjf %SOURCE2 +sed -i '/^LIBPREFIX/s/@libprefix@/@libprefix@%{jemalloc_prefix}/' jemalloc*/Makefile.in +pushd jemalloc* +%patch 1 -p1 -b .jemalloc +%patch 2 -p1 -b .ts-segfault +popd + +# Override PAGESIZE, bz #1545539 +%ifarch %ix86 %arm x86_64 s390x riscv64 +%define lg_page --with-lg-page=12 +%endif + +%ifarch ppc64 ppc64le aarch64 +%define lg_page --with-lg-page=16 +%endif + +# Disable thp on systems not supporting this for now +%ifarch %ix86 %arm aarch64 s390x +%define disable_thp --disable-thp +%endif +%endif + %build + +%if %{with bundled_jemalloc} +# build bundled jemalloc first +pushd jemalloc* + +echo "For debugging package builders" +echo "What is the pagesize?" +getconf PAGESIZE + +echo "What mm features are available?" +ls /sys/kernel/mm +ls /sys/kernel/mm/transparent_hugepage || true +cat /sys/kernel/mm/transparent_hugepage/enabled || true + +echo "What kernel version and config is this?" +uname -a + +%configure %{?disable_thp} %{?lg_page} --enable-prof +make %{?_smp_mflags} +popd +%endif + + +# varnish %if %{with system_allocator} export CFLAGS="%{optflags}" %else @@ -186,6 +267,14 @@ export RST2MAN=/bin/true # Explicit python, please export PYTHON=%{__python} +for f in configure configure.ac; do + sed -i 's|ljemalloc|l%{jemalloc_prefix}jemalloc|g' $f +done + +%if %{with bundled_jemalloc} +export LDFLAGS="$LDFLAGS -L%{_builddir}/%{name}-%{version}/jemalloc-%{jemalloc_version}/lib" +%endif + %configure LT_SYS_LIBRARY_PATH=%_libdir \ --disable-static \ --localstatedir=/var/lib \ @@ -196,10 +285,13 @@ export PYTHON=%{__python} --enable-pcre2-jit=no \ %endif %endif -%if %{with system_allocator} +%if %{with system_allocator} || %{without bundled_jemalloc} --with-jemalloc=no \ %endif +%if %{with bundled_jemalloc} +export LD_LIBRARY_PATH=%{_builddir}/%{name}-%{version}/jemalloc-%{jemalloc_version}/lib +%endif %make_build # One varnish user is enough @@ -209,23 +301,45 @@ sed -i 's,User=varnishlog,User=varnish,g;' redhat/varnishncsa.service rm -rf doc/html/_sources %check +# check jemalloc first +%if %{with bundled_jemalloc} +pushd jemalloc* +make %{?_smp_mflags} check +popd +%endif # Up the stack size in tests, necessary on secondary arches sed -i 's/thread_pool_stack 80k/thread_pool_stack 128k/g;' bin/varnishtest/tests/*.vtc sed -i 's/file,2M/file,8M/' bin/varnishtest/tests/r04036.vtc +%if %{with bundled_jemalloc} +export LD_LIBRARY_PATH=%{_builddir}/%{name}-%{version}/jemalloc-%{jemalloc_version}/lib +%endif + # Just a hack to avoid too high load on secondary arch builders %ifarch s390x ppc64le # This works when ran alone, but not in the whole suite. Load and/or timing issues rm bin/varnishtest/tests/t02014.vtc make -j2 check %else -#make_build check +%make_build check %endif %install rm -rf %{buildroot} +# jemalloc +%if %{with bundled_jemalloc} +pushd jemalloc* +make DESTDIR=%{buildroot} install_lib %{?_smp_mflags} + +find %{buildroot}%{_libdir}/ -name '*.a' -exec rm -vf {} ';' + +# we don't need .pc file +rm %{buildroot}%{_libdir}/pkgconfig/jemalloc.pc +popd +%endif + # mock el7 defaults to LANG=C, which makes python3 fail when parsing utf8 text %if 0%{?rhel} == 7 export LANG=en_US.UTF-8 @@ -319,6 +433,10 @@ test -f /etc/varnish/secret || (uuidgen > /etc/varnish/secret && chmod 0600 /etc %changelog +* Wed Jun 11 2025 Luboš Uhliarik - 7.6.1-4 +- Resolves: RHEL-45756 - Varnish consumes significantly more memory + under RHEL8/9 + * Tue May 20 2025 Luboš Uhliarik - 7.6.1-3 - Resolves: RHEL-89691 - varnish: request smuggling attacks (CVE-2025-47905)