From 32a0119716d009eac689cb05ee46ea26378badfe Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Mon, 17 Jun 2024 13:25:14 +0200 Subject: [PATCH] Applied patch for CVE-2022-1941 (#RHEL-40872) Applied patch to make emacs dependency optional (#RHEL-40572) Resolves: #RHEL-40872 Resolves: #RHEL-40572 Signed-off-by: Adrian Reber --- CVE-2022-1941.patch | 189 ++++++++++++++++++++++++++++++++++++++++++++ protobuf.spec | 29 ++++++- 2 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 CVE-2022-1941.patch diff --git a/CVE-2022-1941.patch b/CVE-2022-1941.patch new file mode 100644 index 0000000..1741c29 --- /dev/null +++ b/CVE-2022-1941.patch @@ -0,0 +1,189 @@ +--- protobuf-3.14.0/src/google/protobuf/extension_set_inl.h 2024-06-17 08:34:37.710063457 +0200 ++++ protobuf-3.14.0/src/google/protobuf/extension_set_inl.h.org 2024-06-17 08:30:35.432690742 +0200 +@@ -206,16 +206,21 @@ + const char* ptr, const Msg* containing_type, + internal::InternalMetadata* metadata, internal::ParseContext* ctx) { + std::string payload; ++ uint32_t type_id; ++ enum class State { kNoTag, kHasType, kHasPayload, kDone }; ++ State state = State::kNoTag; ++ +- uint32 type_id = 0; +- bool payload_read = false; + while (!ctx->Done(&ptr)) { + uint32 tag = static_cast(*ptr++); + if (tag == WireFormatLite::kMessageSetTypeIdTag) { + uint64 tmp; + ptr = ParseBigVarint(ptr, &tmp); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ if (state == State::kNoTag) { ++ type_id = tmp; ++ state = State::kHasType; ++ } else if (state == State::kHasPayload) { ++ type_id = tmp; +- type_id = tmp; +- if (payload_read) { + ExtensionInfo extension; + bool was_packed_on_wire; + if (!FindExtension(2, type_id, containing_type, ctx, &extension, +@@ -241,20 +236,24 @@ + GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && + tmp_ctx.EndedAtLimit()); + } ++ state = State::kDone; +- type_id = 0; + } + } else if (tag == WireFormatLite::kMessageSetMessageTag) { ++ if (state == State::kHasType) { +- if (type_id != 0) { + ptr = ParseFieldMaybeLazily(static_cast(type_id) * 8 + 2, ptr, + containing_type, metadata, ctx); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr); ++ state = State::kDone; +- type_id = 0; + } else { ++ std::string tmp; + int32 size = ReadSize(&ptr); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ ptr = ctx->ReadString(ptr, size, &tmp); +- ptr = ctx->ReadString(ptr, size, &payload); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ if (state == State::kNoTag) { ++ payload = std::move(tmp); ++ state = State::kHasPayload; ++ } +- payload_read = true; + } + } else { + ptr = ReadTag(ptr - 1, &tag); +--- protobuf-3.14.0/src/google/protobuf/wire_format.cc 2024-06-17 08:38:49.003336799 +0200 ++++ protobuf-3.14.0/src/google/protobuf/wire_format.cc.org 2024-06-17 08:35:18.445621561 +0200 +@@ -659,9 +659,11 @@ + const char* _InternalParse(const char* ptr, internal::ParseContext* ctx) { + // Parse a MessageSetItem + auto metadata = reflection->MutableInternalMetadata(msg); ++ enum class State { kNoTag, kHasType, kHasPayload, kDone }; ++ State state = State::kNoTag; ++ + std::string payload; + uint32 type_id = 0; +- bool payload_read = false; + while (!ctx->Done(&ptr)) { + // We use 64 bit tags in order to allow typeid's that span the whole + // range of 32 bit numbers. +@@ -670,8 +668,11 @@ + uint64 tmp; + ptr = ParseBigVarint(ptr, &tmp); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ if (state == State::kNoTag) { ++ type_id = tmp; ++ state = State::kHasType; ++ } else if (state == State::kHasPayload) { ++ type_id = tmp; +- type_id = tmp; +- if (payload_read) { + const FieldDescriptor* field; + if (ctx->data().pool == nullptr) { + field = reflection->FindKnownExtensionByNumber(type_id); +@@ -698,17 +693,17 @@ + GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && + tmp_ctx.EndedAtLimit()); + } ++ state = State::kDone; +- type_id = 0; + } + continue; + } else if (tag == WireFormatLite::kMessageSetMessageTag) { ++ if (state == State::kNoTag) { +- if (type_id == 0) { + int32 size = ReadSize(&ptr); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); + ptr = ctx->ReadString(ptr, size, &payload); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ state = State::kHasPayload; ++ } else if (state == State::kHasType) { +- payload_read = true; +- } else { + // We're now parsing the payload + const FieldDescriptor* field = nullptr; + if (descriptor->IsExtensionNumber(type_id)) { +@@ -722,7 +717,12 @@ + ptr = WireFormat::_InternalParseAndMergeField( + msg, ptr, ctx, static_cast(type_id) * 8 + 2, reflection, + field); ++ state = State::kDone; ++ } else { ++ int32_t size = ReadSize(&ptr); ++ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ ptr = ctx->Skip(ptr, size); ++ GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); +- type_id = 0; + } + } else { + // An unknown field in MessageSetItem. +--- protobuf-3.14.0/src/google/protobuf/wire_format_lite.h 2024-06-17 08:43:18.156450819 +0200 ++++ protobuf-3.14.0/src/google/protobuf/wire_format_lite.h.org 2024-06-17 08:39:03.671177609 +0200 +@@ -1798,6 +1798,9 @@ + // we can parse it later. + std::string message_data; + ++ enum class State { kNoTag, kHasType, kHasPayload, kDone }; ++ State state = State::kNoTag; ++ + while (true) { + const uint32 tag = input->ReadTagNoLastTag(); + if (tag == 0) return false; +@@ -1806,26 +1809,35 @@ + case WireFormatLite::kMessageSetTypeIdTag: { + uint32 type_id; + if (!input->ReadVarint32(&type_id)) return false; +- last_type_id = type_id; + ++ if (state == State::kNoTag) { ++ last_type_id = type_id; ++ state = State::kHasType; ++ } else if (state == State::kHasPayload) { +- if (!message_data.empty()) { + // We saw some message data before the type_id. Have to parse it + // now. + io::CodedInputStream sub_input( + reinterpret_cast(message_data.data()), + static_cast(message_data.size())); + sub_input.SetRecursionLimit(input->RecursionBudget()); ++ if (!ms.ParseField(type_id, &sub_input)) { +- if (!ms.ParseField(last_type_id, &sub_input)) { + return false; + } + message_data.clear(); ++ state = State::kDone; + } + + break; + } + + case WireFormatLite::kMessageSetMessageTag: { ++ if (state == State::kHasType) { ++ // Already saw type_id, so we can parse this directly. ++ if (!ms.ParseField(last_type_id, input)) { ++ return false; ++ } ++ state = State::kDone; ++ } else if (state == State::kNoTag) { +- if (last_type_id == 0) { + // We haven't seen a type_id yet. Append this data to message_data. + uint32 length; + if (!input->ReadVarint32(&length)) return false; +@@ -1836,11 +1824,9 @@ + auto ptr = reinterpret_cast(&message_data[0]); + ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr); + if (!input->ReadRaw(ptr, length)) return false; ++ state = State::kHasPayload; + } else { ++ if (!ms.SkipField(tag, input)) return false; +- // Already saw type_id, so we can parse this directly. +- if (!ms.ParseField(last_type_id, input)) { +- return false; +- } + } + + break; diff --git a/protobuf.spec b/protobuf.spec index 197203b..42e3a71 100644 --- a/protobuf.spec +++ b/protobuf.spec @@ -2,6 +2,8 @@ %bcond_without python # Build -java subpackage %bcond_with java +# Build -emacs subpackage +%bcond_without emacs #global rcver rc2 # Disable LTO to work around annobin error messages @@ -10,7 +12,7 @@ Summary: Protocol Buffers - Google's data interchange format Name: protobuf Version: 3.14.0 -Release: 13%{?dist} +Release: 14%{?dist} License: BSD URL: https://github.com/protocolbuffers/protobuf Source: https://github.com/protocolbuffers/protobuf/archive/v%{version}%{?rcver}/%{name}-%{version}%{?rcver}-all.tar.gz @@ -27,11 +29,17 @@ Patch1: protobuf-3.14-disable-IoTest.LargeOutput.patch # Based on https://github.com/protocolbuffers/protobuf/commit/af95001202a035d78ff997e737bd67fca22ab32a # As described in https://bugzilla.suse.com/show_bug.cgi?id=1195258 Patch2: CVE-2021-22570.patch +# Fix for CVE-2022-1941 "protobuf: message parsing vulnerability in ProtocolBuffers" +# https://issues.redhat.com/browse/RHEL-40872 +# Based on https://github.com/protocolbuffers/protobuf/pull/10542.patch +Patch3: CVE-2022-1941.patch BuildRequires: make BuildRequires: autoconf BuildRequires: automake +%if %{with emacs} BuildRequires: emacs +%endif BuildRequires: gcc-c++ BuildRequires: libtool BuildRequires: pkgconfig @@ -196,6 +204,7 @@ Protocol Buffer BOM POM. %endif +%if %{with emacs} %package emacs Summary: Emacs mode for Google Protocol Buffers descriptions BuildArch: noarch @@ -205,13 +214,15 @@ Obsoletes: protobuf-emacs-el < 3.6.1-4 %description emacs This package contains syntax highlighting for Google Protocol Buffers descriptions in the Emacs editor. +%endif %prep %setup -q -n %{name}-%{version}%{?rcver} -a 3 # IoTest.LargeOutput fails sometimes if not enough memory is available # https://github.com/protocolbuffers/protobuf/issues/8082 -%patch1 -p1 -%patch2 -p1 +%patch -P 1 -p1 +%patch -P 2 -p1 +%patch -P 3 -p1 mv googletest-5ec7f0c4a113e2f18ac2c6cc7df51ad6afc24081/* third_party/googletest/ find -name \*.cc -o -name \*.h | xargs chmod -x chmod 644 examples/* @@ -276,7 +287,9 @@ export MAVEN_OPTS=-Xmx1024m %mvn_build -s -- -f java/pom.xml %endif +%if %{with emacs} %{_emacs_bytecompile} editors/protobuf-mode.el +%endif %check @@ -286,7 +299,7 @@ fail=0 %else fail=1 %endif -%make_build check CXXFLAGS="%{build_cxxflags} -Wno-error=type-limits" || exit $fail +%make_build check CXXFLAGS="%{build_cxxflags} -Wno-error=type-limits -Wno-error=deprecated-declarations" || exit $fail %install @@ -307,11 +320,13 @@ install -p -m 644 -D editors/proto.vim %{buildroot}%{_datadir}/vim/vimfiles/synt %mvn_install %endif +%if %{with emacs} mkdir -p %{buildroot}%{_emacs_sitelispdir}/%{name} install -p -m 0644 editors/protobuf-mode.el %{buildroot}%{_emacs_sitelispdir}/%{name} install -p -m 0644 editors/protobuf-mode.elc %{buildroot}%{_emacs_sitelispdir}/%{name} mkdir -p %{buildroot}%{_emacs_sitestartdir} install -p -m 0644 %{SOURCE2} %{buildroot}%{_emacs_sitestartdir} +%endif %ldconfig_scriptlets %ldconfig_scriptlets lite @@ -336,9 +351,11 @@ install -p -m 0644 %{SOURCE2} %{buildroot}%{_emacs_sitestartdir} %{_libdir}/pkgconfig/protobuf.pc %doc examples/add_person.cc examples/addressbook.proto examples/list_people.cc examples/Makefile examples/README.md +%if %{with emacs} %files emacs %{_emacs_sitelispdir}/%{name}/ %{_emacs_sitestartdir}/protobuf-init.el +%endif %files static %{_libdir}/libprotobuf.a @@ -391,6 +408,10 @@ install -p -m 0644 %{SOURCE2} %{buildroot}%{_emacs_sitestartdir} %changelog +* Mon Jun 17 2024 Adrian Reber - 3.14.0-14 +- Applied patch for CVE-2022-1941 (#RHEL-40872) +- Applied patch to make emacs dependency optional (#RHEL-40572) + * Wed Mar 23 2022 Adrian Reber - 3.14.0-13 - Rebuilt for test fixes