From: Kefu Chai Date: Sat, 23 Aug 2025 08:13:13 +0000 (+0800) Subject: osd/scrub: fix heap-buffer-overflow when checking digest emptiness X-Git-Tag: testing/wip-vshankar-testing-20250908.050731-debug~5^2 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=100c20b7d6588295f539208a2812ba7fd3fb5222;p=ceph-ci.git osd/scrub: fix heap-buffer-overflow when checking digest emptiness Replace unsafe string construction with bufferlist::length() to avoid reading beyond buffer boundaries. In commit 92ccbff1, we introduced a bug when checking if a digest was empty by constructing a std::string from bufferlist: ``` std::string(digest.second.c_str()).empty() ``` This is unsafe because bufferlist data is not guaranteed to be null- terminated. The std::string constructor searches for a null terminator and may read beyond the bufferlist's allocated memory, causing a heap-buffer-overflow detected by AddressSanitizer: ``` ==66092==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7e0c65215004 at pc 0x7fbc6e27c597 bp 0x7ffe29fb6100 sp 0x7ffe29fb58b8 READ of size 5 at 0x7e0c65215004 thread T0 #0 0x7fbc6e27c596 in strlen /usr/src/debug/gcc/gcc/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:425 #1 0x562c75fad91a in std::char_traits::length(char const*) /usr/include/c++/15.2.1/bits/char_traits.h:393 #2 0x562c75fb4222 in std::__cxx11::basic_string, std::allocator >::basic_string >(char const*, std::allocator const&) /usr/include/c++/15.2.1/bits/b asic_string.h:713 #3 0x562c761b81ae in operator() /home/kefu/dev/ceph/src/osd/scrubber/scrub_backend.cc:1300 #4 0x562c761d7d53 in operator()::_iterator > /usr/include/c++/15.2.1/bits/predefined_ops.h:318 #5 0x562c761d789c in __find_if::_iterator, __gnu_cxx::__ops::_Iter_pred&)> > > /usr/include/c++/15.2.1/bits/stl_algobase.h:2095 #6 0x562c761d72b2 in find_if::_iterator, ScrubBackend::match_in_shards(const hobject_t&, auth_selection_t&, inconsistent_obj_wrapper&, std::stringstream&)::&)> > /usr/include/c++/15.2.1/bits/stl_algo.h:3921 #7 0x562c761d5f6f in none_of::_iterator, ScrubBackend::match_in_shards(const hobject_t&, auth_selection_t&, inconsistent_obj_wrapper&, std::stringstream&)::&)> > /usr/include/c++/15.2.1/bits/stl_algo.h:431 #8 0x562c761d4a50 in any_of::_iterator, ScrubBackend::match_in_shards(const hobject_t&, auth_selection_t&, inconsistent_obj_wrapper&, s td::stringstream&)::&)> > /usr/include/c++/15.2.1/bits/stl_algo.h:450 #9 0x562c761bb84b in ScrubBackend::match_in_shards(hobject_t const&, auth_selection_t&, inconsistent_obj_wrapper&, std::__cxx11::basic_stringstream, std::allocator >&) /home/k efu/dev/ceph/src/osd/scrubber/scrub_backend.cc:1297 #10 0x562c761b4282 in ScrubBackend::compare_obj_in_maps[abi:cxx11](hobject_t const&) /home/kefu/dev/ceph/src/osd/scrubber/scrub_backend.cc:941 #11 0x562c761d44af in operator() /home/kefu/dev/ceph/src/osd/scrubber/scrub_backend.cc:887 #12 0x562c761d4836 in for_each, ScrubBackend::compare_smaps():: > /usr/include/c++/15.2.1/bits/stl_algo.h:3798 #13 0x562c761b3259 in ScrubBackend::compare_smaps() /home/kefu/dev/ceph/src/osd/scrubber/scrub_backend.cc:884 #14 0x562c761a478d in ScrubBackend::update_authoritative() /home/kefu/dev/ceph/src/osd/scrubber/scrub_backend.cc:315` ``` Fix by using bufferlist::length() which tells if the given buffer is empty instead of converting the buffer content to a string. Signed-off-by: Kefu Chai --- diff --git a/src/osd/scrubber/scrub_backend.cc b/src/osd/scrubber/scrub_backend.cc index 4fbb9398f98..421f7bff46d 100644 --- a/src/osd/scrubber/scrub_backend.cc +++ b/src/osd/scrubber/scrub_backend.cc @@ -1297,7 +1297,7 @@ ScrubBackend::auth_and_obj_errs_t ScrubBackend::match_in_shards( if (std::any_of( digests.begin(), digests.end(), [](const std::pair& digest) { - return !std::string(digest.second.c_str()).empty(); + return digest.second.length() > 0; })) { // Unseed all buffers in chunks for (auto& [srd, bl] : digests) {