Package: release.debian.org Severity: normal X-Debbugs-Cc: protoz...@packages.debian.org Control: affects -1 + src:protozero User: release.debian....@packages.debian.org Usertags: unblock
Please unblock package protozero The new upstream release has been uploaded to experimental for now, but I'd like to move it to unstable and have it migrate to testing too. [ Reason ] Fixes a buffer overrun security issue. [ Impact ] Unfixed security issue. [ Tests ] Upstream test suite. [ Risks ] Low, only three rdeps (libosmium, mapnik, qtlocation-opensource-src). [ Checklist ] [x] all changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in testing [ Other info ] Upstream reported the issue on the debian-gis list: https://lists.debian.org/debian-gis/2025/07/msg00002.html unblock protozero/1.8.1-1
diff -Nru protozero-1.8.0/CHANGELOG.md protozero-1.8.1/CHANGELOG.md --- protozero-1.8.0/CHANGELOG.md 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/CHANGELOG.md 2025-07-15 19:28:17.000000000 +0200 @@ -14,7 +14,15 @@ ### Fixed -## [1.8.0] - 2024-01-13 +## [1.8.1] - 2025-07-15 + +### Fixed + +- Fix buffer overrun in `get_bool()` +- Fix test that checks that protozero also works with `std::string_view` + + +## [1.8.0] - 2025-01-13 ### Changed diff -Nru protozero-1.8.0/CMakeLists.txt protozero-1.8.1/CMakeLists.txt --- protozero-1.8.0/CMakeLists.txt 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/CMakeLists.txt 2025-07-15 19:28:17.000000000 +0200 @@ -10,7 +10,7 @@ #----------------------------------------------------------------------------- -project(protozero VERSION 1.8.0 LANGUAGES CXX C) +project(protozero VERSION 1.8.1 LANGUAGES CXX C) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -40,9 +40,13 @@ include_directories("${CMAKE_SOURCE_DIR}/include") +# Used for testing set(PROTOZERO_DATA_VIEW "" CACHE STRING "Type used for protozero::data_view") if(NOT PROTOZERO_DATA_VIEW STREQUAL "") - add_definitions(-DPROTOZERO_DATA_VIEW=${PROTOZERO_DATA_VIEW}) + message(STATUS "Using ${PROTOZERO_DATA_VIEW} as data_view") + add_definitions(-DPROTOZERO_USE_VIEW=${PROTOZERO_DATA_VIEW}) +else() + message(STATUS "Using built-in data_view") endif() diff -Nru protozero-1.8.0/debian/changelog protozero-1.8.1/debian/changelog --- protozero-1.8.0/debian/changelog 2025-01-14 05:33:36.000000000 +0100 +++ protozero-1.8.1/debian/changelog 2025-07-16 12:48:27.000000000 +0200 @@ -1,3 +1,17 @@ +protozero (1.8.1-1) unstable; urgency=medium + + * Move from experimental to unstable. + + -- Bas Couwenberg <sebas...@debian.org> Wed, 16 Jul 2025 12:48:27 +0200 + +protozero (1.8.1-1~exp1) experimental; urgency=medium + + * New upstream release. + * Bump Standards-Version to 4.7.2, no changes. + * Fix old FSF address in copyright file. + + -- Bas Couwenberg <sebas...@debian.org> Wed, 16 Jul 2025 12:44:43 +0200 + protozero (1.8.0-1) unstable; urgency=medium * New upstream release. diff -Nru protozero-1.8.0/debian/control protozero-1.8.1/debian/control --- protozero-1.8.0/debian/control 2024-07-28 19:52:33.000000000 +0200 +++ protozero-1.8.1/debian/control 2025-07-16 12:48:08.000000000 +0200 @@ -10,7 +10,7 @@ libprotobuf-dev <!nocheck>, protobuf-compiler <!nocheck>, pkgconf -Standards-Version: 4.7.0 +Standards-Version: 4.7.2 Vcs-Browser: https://salsa.debian.org/debian-gis-team/protozero/ Vcs-Git: https://salsa.debian.org/debian-gis-team/protozero.git Homepage: https://github.com/mapbox/protozero diff -Nru protozero-1.8.0/debian/copyright protozero-1.8.1/debian/copyright --- protozero-1.8.0/debian/copyright 2025-01-14 05:32:16.000000000 +0100 +++ protozero-1.8.1/debian/copyright 2025-03-29 07:28:35.000000000 +0100 @@ -92,10 +92,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. . - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - . On Debian systems, the complete text of version 2 of the GNU General Public License can be found in `/usr/share/common-licenses/GPL-2'. diff -Nru protozero-1.8.0/doc/CMakeLists.txt protozero-1.8.1/doc/CMakeLists.txt --- protozero-1.8.0/doc/CMakeLists.txt 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/doc/CMakeLists.txt 2025-07-15 19:28:17.000000000 +0200 @@ -11,7 +11,7 @@ message(STATUS "Looking for doxygen") find_package(Doxygen) -if(DOXYGEN_FOUND) +if(DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND) message(STATUS "Looking for doxygen - found") configure_file(Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) diff -Nru protozero-1.8.0/FUZZING.md protozero-1.8.1/FUZZING.md --- protozero-1.8.0/FUZZING.md 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/FUZZING.md 2025-07-15 19:28:17.000000000 +0200 @@ -18,5 +18,16 @@ See the AFL documentation for more information. +For increased speed, you can also use the dedicated pbf-fuzzer tool, which skips reading +data from files or stdin: + + clang++ -O2 -std=c++17 -g -DNDEBUG -Iinclude -fsanitize=address,fuzzer tools/pbf-fuzzer.cpp -o tools/pbf-fuzzer + ./tools/pbf-fuzzer + +or using AFL++ + + afl-clang-fast++ -O2 -std=c++17 -g -DNDEBUG -Iinclude -fsanitize=address,fuzzer tools/pbf-fuzzer.cpp -o tools/pbf-fuzzer + afl-fuzz -i testcase_dir -o findings_dir -- tools/pbf-fuzzer + This only checkes the reading side of Protozero! diff -Nru protozero-1.8.0/.github/actions/install-ubuntu/action.yml protozero-1.8.1/.github/actions/install-ubuntu/action.yml --- protozero-1.8.0/.github/actions/install-ubuntu/action.yml 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/.github/actions/install-ubuntu/action.yml 2025-07-15 19:28:17.000000000 +0200 @@ -7,6 +7,8 @@ run: | sudo apt-get update -qq sudo apt-get install -yq \ + doxygen \ + graphviz \ libprotobuf-dev \ protobuf-compiler shell: bash diff -Nru protozero-1.8.0/.github/workflows/ci.yml protozero-1.8.1/.github/workflows/ci.yml --- protozero-1.8.0/.github/workflows/ci.yml 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/.github/workflows/ci.yml 2025-07-15 19:28:17.000000000 +0200 @@ -51,6 +51,7 @@ - image: "debian:bookworm" c_compiler: clang cpp_compiler: clang++ + cpp_version: 17 data_view: std::string_view - image: "debian:testing" c_compiler: clang @@ -136,7 +137,7 @@ CXX: clang++ BUILD_TYPE: ${{ matrix.build_type }} steps: - - run: brew install protobuf + - run: brew install doxygen graphviz protobuf - uses: actions/checkout@v4 - uses: ./.github/actions/cmake - uses: ./.github/actions/build @@ -149,8 +150,8 @@ fail-fast: false matrix: os: - - windows-2019 - windows-2022 + - windows-2025 steps: - run: | vcpkg install \ diff -Nru protozero-1.8.0/include/protozero/pbf_reader.hpp protozero-1.8.1/include/protozero/pbf_reader.hpp --- protozero-1.8.0/include/protozero/pbf_reader.hpp 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/include/protozero/pbf_reader.hpp 2025-07-15 19:28:17.000000000 +0200 @@ -494,9 +494,9 @@ bool get_bool() { protozero_assert(tag() != 0 && "call next() before accessing field value"); protozero_assert(has_wire_type(pbf_wire_type::varint) && "not a varint"); - const bool result = m_data[0] != 0; + const char* value = m_data; skip_varint(&m_data, m_end); - return result; + return *value != 0; } /** diff -Nru protozero-1.8.0/include/protozero/version.hpp protozero-1.8.1/include/protozero/version.hpp --- protozero-1.8.0/include/protozero/version.hpp 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/include/protozero/version.hpp 2025-07-15 19:28:17.000000000 +0200 @@ -23,12 +23,12 @@ #define PROTOZERO_VERSION_MINOR 8 /// The patch number -#define PROTOZERO_VERSION_PATCH 0 +#define PROTOZERO_VERSION_PATCH 1 /// The complete version number #define PROTOZERO_VERSION_CODE (PROTOZERO_VERSION_MAJOR * 10000 + PROTOZERO_VERSION_MINOR * 100 + PROTOZERO_VERSION_PATCH) /// Version number as string -#define PROTOZERO_VERSION_STRING "1.8.0" +#define PROTOZERO_VERSION_STRING "1.8.1" #endif // PROTOZERO_VERSION_HPP diff -Nru protozero-1.8.0/test/t/bool/reader_test_cases.cpp protozero-1.8.1/test/t/bool/reader_test_cases.cpp --- protozero-1.8.0/test/t/bool/reader_test_cases.cpp 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/test/t/bool/reader_test_cases.cpp 2025-07-15 19:28:17.000000000 +0200 @@ -139,3 +139,11 @@ } } +TEST_CASE("read bool from using pbf_reader: truncated message") { + std::vector<char> buffer = { 0x08 }; + + protozero::pbf_reader item{buffer.data(), buffer.size()}; + + REQUIRE(item.next()); + REQUIRE_THROWS_AS(item.get_bool(), protozero::end_of_buffer_exception); +} diff -Nru protozero-1.8.0/test/unit/test_data_view.cpp protozero-1.8.1/test/unit/test_data_view.cpp --- protozero-1.8.0/test/unit/test_data_view.cpp 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/test/unit/test_data_view.cpp 2025-07-15 19:28:17.000000000 +0200 @@ -53,7 +53,9 @@ const std::string s = std::string(view); REQUIRE(s == "foobar"); REQUIRE(std::string(view) == "foobar"); +#ifndef PROTOZERO_USE_VIEW REQUIRE(view.to_string() == "foobar"); +#endif } #ifndef PROTOZERO_USE_VIEW @@ -69,14 +71,14 @@ protozero::data_view view1{"foo"}; protozero::data_view view2{"bar"}; - REQUIRE(view1.to_string() == "foo"); - REQUIRE(view2.to_string() == "bar"); + REQUIRE(std::string(view1) == "foo"); + REQUIRE(std::string(view2) == "bar"); using std::swap; swap(view1, view2); - REQUIRE(view2.to_string() == "foo"); - REQUIRE(view1.to_string() == "bar"); + REQUIRE(std::string(view2) == "foo"); + REQUIRE(std::string(view1) == "bar"); } TEST_CASE("comparing data_views") { diff -Nru protozero-1.8.0/tools/pbf-decoder.cpp protozero-1.8.1/tools/pbf-decoder.cpp --- protozero-1.8.0/tools/pbf-decoder.cpp 2025-01-13 10:42:19.000000000 +0100 +++ protozero-1.8.1/tools/pbf-decoder.cpp 2025-07-15 19:28:17.000000000 +0200 @@ -32,6 +32,7 @@ #include <sstream> #include <stdexcept> #include <string> +#include <vector> namespace { @@ -194,15 +195,15 @@ << " -o, --offset=OFFSET Start reading from OFFSET bytes\n"; } -std::string read_from_file(const char* filename) { +std::vector<char> read_from_file(const char* filename) { const std::ifstream file{filename, std::ios::binary}; - return std::string{std::istreambuf_iterator<char>(file.rdbuf()), - std::istreambuf_iterator<char>()}; + return std::vector<char>{std::istreambuf_iterator<char>(file.rdbuf()), + std::istreambuf_iterator<char>()}; } -std::string read_from_stdin() { - return std::string{std::istreambuf_iterator<char>(std::cin.rdbuf()), - std::istreambuf_iterator<char>()}; +std::vector<char> read_from_stdin() { + return std::vector<char>{std::istreambuf_iterator<char>(std::cin.rdbuf()), + std::istreambuf_iterator<char>()}; } } // anonymous namespace @@ -251,15 +252,15 @@ const std::string filename{argv[optind]}; try { - std::string buffer{filename == "-" ? read_from_stdin() : - read_from_file(argv[optind])}; + std::vector<char> buffer{filename == "-" ? read_from_stdin() : + read_from_file(argv[optind])}; if (offset > buffer.size()) { throw std::runtime_error{"offset is larger than file size"}; } if (offset > 0) { - buffer.erase(0, offset); + buffer.erase(buffer.begin(), buffer.begin() + offset); } if (length < buffer.size()) { diff -Nru protozero-1.8.0/tools/pbf-fuzzer.cpp protozero-1.8.1/tools/pbf-fuzzer.cpp --- protozero-1.8.0/tools/pbf-fuzzer.cpp 1970-01-01 01:00:00.000000000 +0100 +++ protozero-1.8.1/tools/pbf-fuzzer.cpp 2025-07-15 19:28:17.000000000 +0200 @@ -0,0 +1,85 @@ +#include <protozero/pbf_reader.hpp> + +// From Google Benchmark library. +// See https://github.com/google/benchmark/blob/main/LICENSE +template <class Tp> +inline __attribute__((always_inline)) void DoNotOptimize(Tp const& value) { + asm volatile("" : : "r,m"(value) : "memory"); +} + +template <typename T> +int read_packed(protozero::iterator_range<T> range) { + try { + for (const auto& item : range) { + DoNotOptimize(item); + } + } catch (const protozero::exception&) { + // no-op. This is probably not a packed field of that type. + } + return 0; +} + +template <typename Fn> +void try_field(const protozero::pbf_reader& reader, Fn&& fn) { + try { + DoNotOptimize(fn(reader)); + } catch (const protozero::exception&) { + // no-op. This is probably not a field of that type. + } +} + +int try_message(protozero::pbf_reader reader) { + try { + while (reader.next()) { + if (reader.has_wire_type(protozero::pbf_wire_type::varint)) { + // Try to decode this field as any of the types that can be encoded as varint. + try_field(reader, [](protozero::pbf_reader r) { return r.get_bool(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_enum(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_int32(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_sint32(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_uint32(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_int64(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_sint64(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_uint64(); }); + } else if (reader.has_wire_type(protozero::pbf_wire_type::length_delimited)) { + // Try to decode this field as any of the types that can be encoded as length-delimited. + try_field(reader, [](protozero::pbf_reader r) { return try_message(r.get_message()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_bool()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_double()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_enum()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_fixed32()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_fixed64()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_float()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_int32()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_int64()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_sfixed32()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_sfixed64()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_sint32()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_sint64()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_uint32()); }); + try_field(reader, [](protozero::pbf_reader r) { return read_packed(r.get_packed_uint64()); }); + } else if (reader.has_wire_type(protozero::pbf_wire_type::fixed64)) { + // Try to decode this field as any of the types that can be encoded as fixed64. + try_field(reader, [](protozero::pbf_reader r) { return r.get_double(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_fixed64(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_sfixed64(); }); + } else if (reader.has_wire_type(protozero::pbf_wire_type::fixed32)) { + // Try to decode this field as any of the types that can be encoded as fixed32. + try_field(reader, [](protozero::pbf_reader r) { return r.get_float(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_fixed32(); }); + try_field(reader, [](protozero::pbf_reader r) { return r.get_sfixed32(); }); + } + + reader.skip(); + } + } catch (const protozero::exception&) { + // no-op. This is probably not a valid message. + } + + return 0; +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + try_message(protozero::pbf_reader{reinterpret_cast<const char*>(data), size}); + return 0; +}