Compare commits

..

2 Commits
c8 ... c10

Author SHA1 Message Date
28de0a70fa import UBI brotli-1.1.0-7.el10_1 2026-01-20 17:17:45 +00:00
71119bb049 import UBI brotli-1.1.0-6.el10 2025-05-14 15:26:48 +00:00
9 changed files with 770 additions and 4418 deletions

View File

@ -1 +0,0 @@
aa08a912bb560aa6def7b29d91ac6198a6b077f3 SOURCES/v1.0.6.tar.gz

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/v1.0.6.tar.gz
brotli-1.1.0.tar.gz

View File

@ -0,0 +1,447 @@
From 28ce91caf605ac5481e9ca69131a28e1087574b7 Mon Sep 17 00:00:00 2001
From: Robert Obryk <robryk@google.com>
Date: Tue, 17 Sep 2024 16:50:39 +0200
Subject: [PATCH 1/2] add size limit to buffer
---
python/_brotli.c | 32 +++++++++++++++++++++++---------
1 file changed, 23 insertions(+), 9 deletions(-)
diff --git a/python/_brotli.c b/python/_brotli.c
index c6a0da03d..75c54c489 100644
--- a/python/_brotli.c
+++ b/python/_brotli.c
@@ -23,6 +23,7 @@ typedef struct {
PyObject *list;
/* Number of whole allocated size. */
Py_ssize_t allocated;
+ Py_ssize_t size_limit;
} BlocksOutputBuffer;
static const char unable_allocate_msg[] = "Unable to allocate output buffer.";
@@ -69,11 +70,17 @@ static const Py_ssize_t BUFFER_BLOCK_SIZE[] =
Return -1 on failure
*/
static inline int
-BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer *buffer,
+BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer *buffer, Py_ssize_t size_limit,
size_t *avail_out, uint8_t **next_out)
{
PyObject *b;
- const Py_ssize_t block_size = BUFFER_BLOCK_SIZE[0];
+ Py_ssize_t block_size = BUFFER_BLOCK_SIZE[0];
+
+ assert(size_limit > 0);
+
+ if (size_limit < block_size) {
+ block_size = size_limit;
+ }
// Ensure .list was set to NULL, for BlocksOutputBuffer_OnError().
assert(buffer->list == NULL);
@@ -94,6 +101,7 @@ BlocksOutputBuffer_InitAndGrow(BlocksOutputBuffer *buffer,
// Set variables
buffer->allocated = block_size;
+ buffer->size_limit = size_limit;
*avail_out = (size_t) block_size;
*next_out = (uint8_t*) PyBytes_AS_STRING(b);
@@ -122,10 +130,16 @@ BlocksOutputBuffer_Grow(BlocksOutputBuffer *buffer,
block_size = BUFFER_BLOCK_SIZE[Py_ARRAY_LENGTH(BUFFER_BLOCK_SIZE) - 1];
}
- // Check buffer->allocated overflow
- if (block_size > PY_SSIZE_T_MAX - buffer->allocated) {
- PyErr_SetString(PyExc_MemoryError, unable_allocate_msg);
- return -1;
+ if (block_size > buffer->size_limit - buffer->allocated) {
+ block_size = buffer->size_limit - buffer->allocated;
+ }
+
+ if (block_size == 0) {
+ // We are at the size_limit (either the provided one, in which case we
+ // shouldn't have been called, or the implicit PY_SSIZE_T_MAX one, in
+ // which case we wouldn't be able to concatenate the blocks at the end).
+ PyErr_SetString(PyExc_MemoryError, "too long");
+ return -1;
}
// Create the block
@@ -291,7 +305,7 @@ static PyObject* compress_stream(BrotliEncoderState* enc, BrotliEncoderOperation
BlocksOutputBuffer buffer = {.list=NULL};
PyObject *ret;
- if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
+ if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) {
goto error;
}
@@ -604,7 +618,7 @@ static PyObject* decompress_stream(BrotliDecoderState* dec,
BlocksOutputBuffer buffer = {.list=NULL};
PyObject *ret;
- if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
+ if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) {
goto error;
}
@@ -877,7 +891,7 @@ static PyObject* brotli_decompress(PyObject *self, PyObject *args, PyObject *key
next_in = (uint8_t*) input.buf;
available_in = input.len;
- if (BlocksOutputBuffer_InitAndGrow(&buffer, &available_out, &next_out) < 0) {
+ if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) {
goto error;
}
From eb3a31e2d356d5a633de995afe7fe60e590a26d8 Mon Sep 17 00:00:00 2001
From: Robert Obryk <robryk@google.com>
Date: Wed, 18 Sep 2024 15:25:06 +0200
Subject: [PATCH 2/2] add max_length to Python streaming decompression
---
python/_brotli.c | 192 ++++++++++++++++--------
python/tests/decompressor_test.py | 42 ++++++
tests/testdata/zerosukkanooa | Bin 0 -> 262263 bytes
tests/testdata/zerosukkanooa.compressed | Bin 0 -> 107 bytes
4 files changed, 175 insertions(+), 59 deletions(-)
create mode 100644 tests/testdata/zerosukkanooa
create mode 100644 tests/testdata/zerosukkanooa.compressed
diff --git a/python/_brotli.c b/python/_brotli.c
index 75c54c489..f86b04f93 100644
--- a/python/_brotli.c
+++ b/python/_brotli.c
@@ -606,57 +606,6 @@ static PyTypeObject brotli_CompressorType = {
brotli_Compressor_new, /* tp_new */
};
-static PyObject* decompress_stream(BrotliDecoderState* dec,
- uint8_t* input, size_t input_length) {
- BrotliDecoderResult result;
-
- size_t available_in = input_length;
- const uint8_t* next_in = input;
-
- size_t available_out;
- uint8_t* next_out;
- BlocksOutputBuffer buffer = {.list=NULL};
- PyObject *ret;
-
- if (BlocksOutputBuffer_InitAndGrow(&buffer, PY_SSIZE_T_MAX, &available_out, &next_out) < 0) {
- goto error;
- }
-
- while (1) {
- Py_BEGIN_ALLOW_THREADS
- result = BrotliDecoderDecompressStream(dec,
- &available_in, &next_in,
- &available_out, &next_out, NULL);
- Py_END_ALLOW_THREADS
-
- if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
- if (available_out == 0) {
- if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) {
- goto error;
- }
- }
- continue;
- }
-
- break;
- }
-
- if (result == BROTLI_DECODER_RESULT_ERROR || available_in != 0) {
- goto error;
- }
-
- ret = BlocksOutputBuffer_Finish(&buffer, available_out);
- if (ret != NULL) {
- goto finally;
- }
-
-error:
- BlocksOutputBuffer_OnError(&buffer);
- ret = NULL;
-finally:
- return ret;
-}
-
PyDoc_STRVAR(brotli_Decompressor_doc,
"An object to decompress a byte string.\n"
"\n"
@@ -669,10 +618,14 @@ PyDoc_STRVAR(brotli_Decompressor_doc,
typedef struct {
PyObject_HEAD
BrotliDecoderState* dec;
+ uint8_t* unconsumed_data;
+ size_t unconsumed_data_length;
} brotli_Decompressor;
static void brotli_Decompressor_dealloc(brotli_Decompressor* self) {
BrotliDecoderDestroyInstance(self->dec);
+ if (self->unconsumed_data)
+ free(self->unconsumed_data);
#if PY_MAJOR_VERSION >= 3
Py_TYPE(self)->tp_free((PyObject*)self);
#else
@@ -688,6 +641,9 @@ static PyObject* brotli_Decompressor_new(PyTypeObject *type, PyObject *args, PyO
self->dec = BrotliDecoderCreateInstance(0, 0, 0);
}
+ self->unconsumed_data = NULL;
+ self->unconsumed_data_length = 0;
+
return (PyObject *)self;
}
@@ -706,6 +662,79 @@ static int brotli_Decompressor_init(brotli_Decompressor *self, PyObject *args, P
return 0;
}
+static PyObject* decompress_stream(brotli_Decompressor* self,
+ uint8_t* input, size_t input_length, Py_ssize_t max_output_length) {
+ BrotliDecoderResult result;
+
+ size_t available_in = input_length;
+ const uint8_t* next_in = input;
+
+ size_t available_out;
+ uint8_t* next_out;
+ uint8_t* new_tail;
+ BlocksOutputBuffer buffer = {.list=NULL};
+ PyObject *ret;
+
+ if (BlocksOutputBuffer_InitAndGrow(&buffer, max_output_length, &available_out, &next_out) < 0) {
+ goto error;
+ }
+
+ while (1) {
+ Py_BEGIN_ALLOW_THREADS
+ result = BrotliDecoderDecompressStream(self->dec,
+ &available_in, &next_in,
+ &available_out, &next_out, NULL);
+ Py_END_ALLOW_THREADS
+
+ if (result == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
+ if (available_out == 0) {
+ if (buffer.allocated == PY_SSIZE_T_MAX) {
+ PyErr_SetString(PyExc_MemoryError, unable_allocate_msg);
+ goto error;
+ }
+ if (buffer.allocated == max_output_length) {
+ // We've reached the output length limit.
+ break;
+ }
+ if (BlocksOutputBuffer_Grow(&buffer, &available_out, &next_out) < 0) {
+ goto error;
+ }
+ }
+ continue;
+ }
+
+ if (result == BROTLI_DECODER_RESULT_ERROR || available_in != 0) {
+ available_in = 0;
+ goto error;
+ }
+
+ break;
+ }
+
+ ret = BlocksOutputBuffer_Finish(&buffer, available_out);
+ if (ret != NULL) {
+ goto finally;
+ }
+
+error:
+ BlocksOutputBuffer_OnError(&buffer);
+ ret = NULL;
+
+finally:
+ new_tail = available_in > 0 ? malloc(available_in) : NULL;
+ if (available_in > 0) {
+ memcpy(new_tail, next_in, available_in);
+ }
+ if (self->unconsumed_data) {
+ free(self->unconsumed_data);
+ }
+ self->unconsumed_data = new_tail;
+ self->unconsumed_data_length = available_in;
+
+ return ret;
+}
+
+
PyDoc_STRVAR(brotli_Decompressor_process_doc,
"Process \"string\" for decompression, returning a string that contains \n"
"decompressed output data. This data should be concatenated to the output \n"
@@ -713,28 +742,38 @@ PyDoc_STRVAR(brotli_Decompressor_process_doc,
"Some or all of the input may be kept in internal buffers for later \n"
"processing, and the decompressed output data may be empty until enough input \n"
"has been accumulated.\n"
+"If max_output_length is set, no more than max_output_length bytes will be\n"
+"returned. If the limit is reached, further calls to process (potentially with\n"
+"empty input) will continue to yield more data. If, after returning a string of\n"
+"the length equal to limit, can_accept_more_data() returns False, process()\n"
+"must only be called with empty input until can_accept_more_data() once again\n"
+"returns True.\n"
"\n"
"Signature:\n"
-" decompress(string)\n"
+" decompress(string, max_output_length=int)\n"
"\n"
"Args:\n"
" string (bytes): The input data\n"
-"\n"
-"Returns:\n"
+"\n""Returns:\n"
" The decompressed output data (bytes)\n"
"\n"
"Raises:\n"
" brotli.error: If decompression fails\n");
-static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args) {
+static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject *args, PyObject* keywds) {
PyObject* ret;
Py_buffer input;
int ok;
+ Py_ssize_t max_output_length = PY_SSIZE_T_MAX;
+ uint8_t* data;
+ size_t data_length;
+
+ static char* kwlist[] = { "", "max_output_length", NULL };
#if PY_MAJOR_VERSION >= 3
- ok = PyArg_ParseTuple(args, "y*:process", &input);
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "y*|n:process", kwlist, &input, &max_output_length);
#else
- ok = PyArg_ParseTuple(args, "s*:process", &input);
+ ok = PyArg_ParseTupleAndKeywords(args, keywds, "s*|n:process", kwlist, &input, &max_output_length);
#endif
if (!ok) {
@@ -745,7 +784,20 @@ static PyObject* brotli_Decompressor_process(brotli_Decompressor *self, PyObject
goto error;
}
- ret = decompress_stream(self->dec, (uint8_t*) input.buf, input.len);
+ if (self->unconsumed_data_length > 0) {
+ if (input.len > 0) {
+ PyErr_SetString(BrotliError, "process called with data when accept_more_data is False");
+ ret = NULL;
+ goto finally;
+ }
+ data = self->unconsumed_data;
+ data_length = self->unconsumed_data_length;
+ } else {
+ data = (uint8_t*)input.buf;
+ data_length = input.len;
+ }
+
+ ret = decompress_stream(self, data, data_length, max_output_length);
if (ret != NULL) {
goto finally;
}
@@ -787,13 +839,35 @@ static PyObject* brotli_Decompressor_is_finished(brotli_Decompressor *self) {
}
}
+PyDoc_STRVAR(brotli_Decompressor_can_accept_more_data_doc,
+"Checks if the decoder instance can accept more compressed data. If the decompress()\n"
+"method on this instance of decompressor was never called with max_length,\n"
+"this method will always return True.\n"
+"\n"
+"Signature:"
+" can_accept_more_data()\n"
+"\n"
+"Returns:\n"
+" True if the decoder is ready to accept more compressed data via decompress()\n"
+" False if the decoder needs to output some data via decompress(b'') before\n"
+" being provided any more compressed data\n");
+
+static PyObject* brotli_Decompressor_can_accept_more_data(brotli_Decompressor* self) {
+ if (self->unconsumed_data_length > 0) {
+ Py_RETURN_FALSE;
+ } else {
+ Py_RETURN_TRUE;
+ }
+}
+
static PyMemberDef brotli_Decompressor_members[] = {
{NULL} /* Sentinel */
};
static PyMethodDef brotli_Decompressor_methods[] = {
- {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS, brotli_Decompressor_process_doc},
+ {"process", (PyCFunction)brotli_Decompressor_process, METH_VARARGS | METH_KEYWORDS, brotli_Decompressor_process_doc},
{"is_finished", (PyCFunction)brotli_Decompressor_is_finished, METH_NOARGS, brotli_Decompressor_is_finished_doc},
+ {"can_accept_more_data", (PyCFunction)brotli_Decompressor_can_accept_more_data, METH_NOARGS, brotli_Decompressor_can_accept_more_data_doc},
{NULL} /* Sentinel */
};
diff --git a/python/tests/decompressor_test.py b/python/tests/decompressor_test.py
index 05918ada8..09a76f3ee 100644
--- a/python/tests/decompressor_test.py
+++ b/python/tests/decompressor_test.py
@@ -4,6 +4,7 @@
# See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
import functools
+import os
import unittest
from . import _test_utils
@@ -39,10 +40,51 @@ def _decompress(self, test_data):
out_file.write(self.decompressor.process(data))
self.assertTrue(self.decompressor.is_finished())
+ def _decompress_with_limit(self, test_data, max_output_length):
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ chunk_iter = iter(functools.partial(in_file.read, 10 * 1024), b'')
+ while not self.decompressor.is_finished():
+ data = b''
+ if self.decompressor.can_accept_more_data():
+ data = next(chunk_iter, b'')
+ decompressed_data = self.decompressor.process(data, max_output_length=max_output_length)
+ self.assertTrue(len(decompressed_data) <= max_output_length)
+ out_file.write(decompressed_data)
+ self.assertTrue(next(chunk_iter, None) == None)
+
def _test_decompress(self, test_data):
self._decompress(test_data)
self._check_decompression(test_data)
+ def _test_decompress_with_limit(self, test_data):
+ self._decompress_with_limit(test_data, max_output_length=20)
+ self._check_decompression(test_data)
+
+ def test_too_much_input(self):
+ with open(os.path.join(_test_utils.TESTDATA_DIR, "zerosukkanooa.compressed"), 'rb') as in_file:
+ compressed = in_file.read()
+ self.decompressor.process(compressed[:-1], max_output_length=1)
+ # the following assertion checks whether the test setup is correct
+ self.assertTrue(not self.decompressor.can_accept_more_data())
+ with self.assertRaises(brotli.error):
+ self.decompressor.process(compressed[-1:])
+
+ def test_changing_limit(self):
+ test_data = os.path.join(_test_utils.TESTDATA_DIR, "zerosukkanooa.compressed")
+ temp_uncompressed = _test_utils.get_temp_uncompressed_name(test_data)
+ with open(temp_uncompressed, 'wb') as out_file:
+ with open(test_data, 'rb') as in_file:
+ compressed = in_file.read()
+ uncompressed = self.decompressor.process(compressed[:-1], max_output_length=1)
+ self.assertTrue(len(uncompressed) <= 1)
+ out_file.write(uncompressed)
+ while not self.decompressor.can_accept_more_data():
+ out_file.write(self.decompressor.process(b''))
+ out_file.write(self.decompressor.process(compressed[-1:]))
+ self._check_decompression(test_data)
+
def test_garbage_appended(self):
with self.assertRaises(brotli.error):
self.decompressor.process(brotli.compress(b'a') + b'a')

View File

@ -0,0 +1,14 @@
--- brotli-1.1.0/c/dec/bit_reader.h.RHEL-32153-kBrotliBitMask-bounds 2023-08-29 13:00:29.000000000 +0200
+++ brotli-1.1.0/c/dec/bit_reader.h 2024-09-11 13:38:21.608972528 +0200
@@ -32,8 +32,10 @@ static BROTLI_INLINE brotli_reg_t BitMas
/* Masking with this expression turns to a single
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
return ~(~((brotli_reg_t)0) << n);
- } else {
+ } else if (n < 33) {
return kBrotliBitMask[n];
+ } else {
+ return 0;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,207 +0,0 @@
%if 0%{?rhel} > 7
# Disable python2 build by default
%bcond_with python2
%else
%bcond_without python2
%endif
Name: brotli
Version: 1.0.6
Release: 4%{?dist}
Summary: Lossless compression algorithm
License: MIT
URL: https://github.com/google/brotli
Source0: https://github.com/google/brotli/archive/v%{version}.tar.gz
Patch1: rhbz1881156.patch
Patch2: CVE-2025-6176.patch
%if %{with python2}
BuildRequires: python2-devel
%endif
BuildRequires: python3-devel
BuildRequires: gcc-c++ gcc cmake
%description
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
%if %{with python2}
%package -n python2-%{name}
Summary: Lossless compression algorithm (python 2)
Requires: python2
%{?python_provide:%python_provide python2-%{name}}
%description -n python2-%{name}
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
This package installs a Python 2 module.
%endif
%package -n python3-%{name}
Requires: %{__python3}
Summary: Lossless compression algorithm (python 3)
%{?python_provide:%python_provide python3-%{name}}
%description -n python3-%{name}
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
This package installs a Python 3 module.
%package -n %{name}-devel
Summary: Lossless compression algorithm (development files)
Requires: %{name}%{?_isa} = %{version}-%{release}
%description -n %{name}-devel
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
This package installs the development files
%prep
%autosetup -p1 -S git
# fix permissions for -debuginfo
# rpmlint will complain if I create an extra %%files section for
# -debuginfo for this so we'll put it here instead
%{__chmod} 644 c/enc/*.[ch]
%{__chmod} 644 c/include/brotli/*.h
%{__chmod} 644 c/tools/brotli.c
%build
mkdir -p build
cd build
%cmake .. -DCMAKE_INSTALL_PREFIX="%{_prefix}" \
-DCMAKE_INSTALL_LIBDIR="%{_libdir}"
%make_build
cd ..
%if %{with python2}
%py2_build
%endif
%py3_build
%install
cd build
%make_install
# I couldn't find the option to not build the static libraries
%__rm "%{buildroot}%{_libdir}/"*.a
cd ..
# Must do the python2 install first because the scripts in /usr/bin are
# overwritten with every setup.py install, and in general we want the
# python3 version to be the default. If, however, we're installing separate
# executables for python2 and python3, the order needs to be reversed so
# the unversioned executable is the python2 one.
%if %{with python2}
%py2_install
%endif
%py3_install
%{__install} -dm755 "%{buildroot}%{_mandir}/man3"
cd docs
for i in *.3;do
%{__install} -m644 "$i" "%{buildroot}%{_mandir}/man3/${i}brotli"
done
%ldconfig_scriptlets
%check
cd build
ctest -V
cd ..
%if %{with python2}
%{__python2} setup.py test
%endif
%{__python3} setup.py test
%files
%{_bindir}/brotli
%{_libdir}/*.so.*
%license LICENSE
# Note that there is no %%files section for the unversioned python module
# if we are building for several python runtimes
%if %{with python2}
%files -n python2-%{name}
%{python2_sitearch}/*
%license LICENSE
%endif
%files -n python3-%{name}
%{python3_sitearch}/*
%license LICENSE
%files -n %{name}-devel
%{_includedir}/*
%{_libdir}/*.so
%{_libdir}/pkgconfig/*
%{_mandir}/man3/*
%changelog
* Wed Jan 28 2026 Parag Nemade <pnemade AT redhat DOT com> - 1.0.6-4
- Resolves: RHEL-133986
CVE-2025-6176 Brotli decompression bomb DoS in scrapy
* Thu Oct 01 2020 Eike Rathke <erack@redhat.com> - 1.0.6-3
- Resolves: CVE-2020-8927
* Wed Jun 17 2020 Eike Rathke <erack@redhat.com> - 1.0.6-2
- Resolves: rhbz#1737412 bump NRV for build to compose
* Wed Oct 10 2018 Tomas Popela <tpopela@redhat.com> - 1.0.6-1
- Update to 1.0.6
- Resolves: rhbz#1637408
* Wed Sep 19 2018 Tomas Orsava <torsava@redhat.com> - 1.0.5-2
- Require the Python interpreter directly instead of using the package name
- Related: rhbz#1619153
* Mon Jul 16 2018 Tomas Popela <tpopela@redhat.com> - 1.0.5-1
- Update to 1.0.5
* Tue Jun 19 2018 Lumír Balhar <lbalhar@redhat.com> - 1.0.1-4
- Python 2 subpackage disabled
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Sat Feb 03 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1.0.1-2
- Switch to %%ldconfig_scriptlets
* Fri Sep 22 2017 Travis Kendrick <pouar@pouar.net> - 1.0.1-1
- update to 1.0.1
* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Tue May 23 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-4
- add man pages
* Sun May 14 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-3
- wrong directory for ctest
- LICENSE not needed in -devel
- fix "spurious-executable-perm"
- rpmbuild does the cleaning for us, so 'rm -rf %%{buildroot}' isn't needed
* Sat May 13 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-2
- include libraries and development files
* Sat May 06 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-1
- Initial build

307
brotli.spec Normal file
View File

@ -0,0 +1,307 @@
Name: brotli
Version: 1.1.0
Release: 7%{?dist}
Summary: Lossless compression algorithm
License: MIT
URL: https://github.com/google/brotli
Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
Patch1: RHEL-32153-kBrotliBitMask-bounds.patch
# Modified patch from upstream https://github.com/google/brotli/pull/1234/
# dropped binary part of updating test files from this patch
Patch2: CVE-2025-6176-brotli-1234.patch
%if 0%{?rhel} == 7
BuildRequires: devtoolset-7-toolchain, devtoolset-7-libatomic-devel
BuildRequires: cmake3
%else
BuildRequires: cmake
%endif
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: python%{python3_pkgversion}-devel
BuildRequires: python%{python3_pkgversion}-setuptools
Requires: lib%{name}%{?_isa} = %{version}-%{release}
%description
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
%package -n libbrotli
Summary: Library for brotli lossless compression algorithm
%description -n libbrotli
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
%package -n python%{python3_pkgversion}-%{name}
Summary: Lossless compression algorithm (python 3)
%{?python_provide:%python_provide python%{python3_pkgversion}-%{name}}
%description -n python%{python3_pkgversion}-%{name}
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
This package installs a Python 3 module.
%package devel
Summary: Lossless compression algorithm (development files)
Requires: %{name}%{?_isa} = %{version}-%{release}
Requires: lib%{name}%{?_isa} = %{version}-%{release}
%description devel
Brotli is a generic-purpose lossless compression algorithm that compresses
data using a combination of a modern variant of the LZ77 algorithm, Huffman
coding and 2nd order context modeling, with a compression ratio comparable
to the best currently available general-purpose compression methods.
It is similar in speed with deflate but offers more dense compression.
This package installs the development files
%prep
%autosetup -p1
# fix permissions for -debuginfo
# rpmlint will complain if I create an extra %%files section for
# -debuginfo for this so we'll put it here instead
chmod 644 c/enc/*.[ch]
chmod 644 c/include/brotli/*.h
chmod 644 c/tools/brotli.c
%build
%if 0%{?rhel} == 7
. /opt/rh/devtoolset-7/enable
%cmake3 \
-DCMAKE_INSTALL_PREFIX="%{_prefix}" \
-DCMAKE_INSTALL_LIBDIR="%{_libdir}"
%cmake3_build
%else
%cmake \
-DCMAKE_INSTALL_PREFIX="%{_prefix}" \
-DCMAKE_INSTALL_LIBDIR="%{_libdir}"
%cmake_build
%endif
%py3_build
%install
%if 0%{?rhel} == 7
. /opt/rh/devtoolset-7/enable
%cmake3_install
%else
%cmake_install
%endif
# I couldn't find the option to not build the static libraries
#rm "%{buildroot}%{_libdir}/"*.a
%py3_install
install -dm755 "%{buildroot}%{_mandir}/man3"
cd docs
for i in *.3;do
install -m644 "$i" "%{buildroot}%{_mandir}/man3/${i}brotli"
done
%ldconfig_scriptlets
%check
%if 0%{?rhel} == 7
. /opt/rh/devtoolset-7/enable
%ctest3
%else
%ctest
%endif
%files
%{_bindir}/brotli
%files -n libbrotli
%license LICENSE
%{_libdir}/libbrotlicommon.so.1*
%{_libdir}/libbrotlidec.so.1*
%{_libdir}/libbrotlienc.so.1*
# Note that there is no %%files section for the unversioned python module
# if we are building for several python runtimes
%files -n python%{python3_pkgversion}-%{name}
%license LICENSE
%{python3_sitearch}/brotli.py
%{python3_sitearch}/_brotli.cpython-%{python3_version_nodots}*.so
%{python3_sitearch}/__pycache__/brotli.cpython-%{python3_version_nodots}*.py*
%{python3_sitearch}/Brotli-1.1.0-py%{python3_version}.egg-info/
%files devel
%{_includedir}/brotli
%{_libdir}/libbrotlicommon.so
%{_libdir}/libbrotlidec.so
%{_libdir}/libbrotlienc.so
%{_libdir}/pkgconfig/libbrotlicommon.pc
%{_libdir}/pkgconfig/libbrotlidec.pc
%{_libdir}/pkgconfig/libbrotlienc.pc
%{_mandir}/man3/constants.h.3brotli*
%{_mandir}/man3/decode.h.3brotli*
%{_mandir}/man3/encode.h.3brotli*
%{_mandir}/man3/types.h.3brotli*
%changelog
* Thu Dec 18 2025 Parag Nemade <pnemade AT redhat DOT com> - 1.1.0-7
- Resolves: RHEL-133984
CVE-2025-6176 Brotli decompression bomb DoS in scrapy
* Tue Oct 29 2024 Troy Dawson <tdawson@redhat.com> - 1.1.0-6
- Bump release for October 2024 mass rebuild:
Resolves: RHEL-64018
* Wed Sep 11 2024 Eike Rathke <erack@redhat.com> - 1.1.0-5
- Check BitMask(n) n value for kBrotliBitMask[n] bounds
* Mon Jun 24 2024 Troy Dawson <tdawson@redhat.com> - 1.1.0-4
- Bump release for June 2024 mass rebuild
* Tue Jan 23 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.1.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Jan 19 2024 Fedora Release Engineering <releng@fedoraproject.org> - 1.1.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
* Fri Sep 15 2023 Jonathan Wright <jonathan@almalinux.org> - 1.1.0-1
- Update to 1.1.1 rhbz#2233368
* Wed Jul 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-13
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
* Tue Jun 13 2023 Python Maint <python-maint@redhat.com> - 1.0.9-12
- Rebuilt for Python 3.12
* Wed Jan 18 2023 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-11
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
* Sat Dec 03 2022 Jonathan Wright <jonathan@almalinux.org> - 1.0.9-10
- Fix EL7 builds
* Wed Jul 20 2022 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-9
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Mon Jun 13 2022 Python Maint <python-maint@redhat.com> - 1.0.9-8
- Rebuilt for Python 3.11
* Wed Jan 19 2022 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-7
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Wed Jul 21 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Thu Jun 03 2021 Python Maint <python-maint@redhat.com> - 1.0.9-5
- Rebuilt for Python 3.10
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.9-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Thu Oct 01 2020 Travis Kendrick <pouar@pouar.net> - 1.0.9-3
- Apparently %%autosetup calls %%patch on its own
* Thu Oct 01 2020 Travis Kendrick <pouar@pouar.net> - 1.0.9-2
- Fix pc file (#1884364)
* Wed Sep 30 2020 Travis Kendrick <pouar@pouar.net> - 1.0.9-1
- Update to 1.0.9 (#1872932)
* Wed Aug 12 2020 Carl George <carl@george.computer> - 1.0.7-14
- Update cmake invocation rhbz#1863298
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.7-13
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.7-12
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Sat May 23 2020 Miro Hrončok <mhroncok@redhat.com> - 1.0.7-11
- Rebuilt for Python 3.9
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.7-10
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Sat Dec 7 2019 Peter Robinson <pbrobinson@fedoraproject.org> 1.0.7-9
- Splil out the libs to a separate package
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 1.0.7-8
- Rebuilt for Python 3.8.0rc1 (#1748018)
* Sat Aug 17 2019 Miro Hrončok <mhroncok@redhat.com> - 1.0.7-7
- Rebuilt for Python 3.8
* Wed Jul 24 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.7-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Sat Apr 20 2019 Orion Poplawski <orion@nwra.com> - 1.0.7-5
- Build with devtoolset-7 on EPEL7 to fix aarch64 builds
* Thu Mar 28 2019 Carl George <carl@george.computer> - 1.0.7-4
- EPEL compatibility
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.7-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Sun Dec 09 2018 Miro Hrončok <mhroncok@redhat.com> - 1.0.7-2
- Remove last python2 bits
* Wed Nov 28 2018 Travis Kendrick pouar@pouar.net> - 1.0.7-1
- Update to 1.0.7
* Wed Nov 28 2018 Travis Kendrick pouar@pouar.net> - 1.0.5-2
- remove Python 2 support https://fedoraproject.org/wiki/Changes/Mass_Python_2_Package_Removal
* Fri Jul 13 2018 Travis Kendrick pouar@pouar.net> - 1.0.5-1
- update to 1.0.5
* Thu Jul 12 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.4-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Mon Jun 18 2018 Miro Hrončok <mhroncok@redhat.com> - 1.0.4-3
- Rebuilt for Python 3.7
* Wed Apr 18 2018 Travis Kendrick pouar@pouar.net> - 1.0.4-2
- update to 1.0.4
* Sat Mar 03 2018 Travis Kendrick <pouar@pouar.net> - 1.0.3-1
- update to 1.0.3
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 1.0.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Sat Feb 03 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 1.0.1-2
- Switch to %%ldconfig_scriptlets
* Fri Sep 22 2017 Travis Kendrick <pouar@pouar.net> - 1.0.1-1
- update to 1.0.1
* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild
* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.6.0-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Tue May 23 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-4
- add man pages
* Sun May 14 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-3
- wrong directory for ctest
- LICENSE not needed in -devel
- fix "spurious-executable-perm"
- rpmbuild does the cleaning for us, so 'rm -rf %%{buildroot}' isn't needed
* Sat May 13 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-2
- include libraries and development files
* Sat May 06 2017 Travis Kendrick <pouar@pouar.net> - 0.6.0-1
- Initial build

1
sources Normal file
View File

@ -0,0 +1 @@
SHA512 (brotli-1.1.0.tar.gz) = 6eb280d10d8e1b43d22d00fa535435923c22ce8448709419d676ff47d4a644102ea04f488fc65a179c6c09fee12380992e9335bad8dfebd5d1f20908d10849d9