From: NitzanMordhai Date: Wed, 21 Jan 2026 13:07:56 +0000 (+0000) Subject: mgr/PyFormatter: prevent segfault on non-printable characters X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=a7ad271d5f433e98fa38c260fee25aac1d555901;p=ceph-ci.git mgr/PyFormatter: prevent segfault on non-printable characters If PyFormatter::dump_string attempting to format non-printable characters can result in a nullptr being passed to dump_pyobject, causing a segfault. It occured in the following case - crash module tried to load the crash entries containing matedata with non-printable characters. when these were passed to PyFormatter, the resulting crash prevented ceph-mgr from starting. Fix this by attempting to create a python object using PyUnicode_FromString. If it returns nullptr (indicating a decoding failure), the code now falls back to decoding using Latin1. Additionally, add a guard in dump_pyobject to prevent processing nullptr objects, providing a secondary layer of protection against segfaults. Fixes: https://tracker.ceph.com/issues/74379 Signed-off-by: Nitzan Mordechai --- diff --git a/src/mgr/PyFormatter.cc b/src/mgr/PyFormatter.cc index 7c333308ab5..3bed72a088a 100644 --- a/src/mgr/PyFormatter.cc +++ b/src/mgr/PyFormatter.cc @@ -64,7 +64,14 @@ void PyFormatter::dump_float(std::string_view name, double d) void PyFormatter::dump_string(std::string_view name, std::string_view s) { - dump_pyobject(name, PyUnicode_FromString(s.data())); + PyObject *p = PyUnicode_FromStringAndSize(s.data(), s.size()); + if (!p) { + PyErr_Clear(); + p = PyUnicode_DecodeLatin1(s.data(), s.size(), nullptr); + ceph_assert(p); + } + + dump_pyobject(name, p); } void PyFormatter::dump_bool(std::string_view name, bool b) @@ -105,6 +112,9 @@ void PyFormatter::dump_format_va(std::string_view name, const char *ns, bool quo */ void PyFormatter::dump_pyobject(std::string_view name, PyObject *p) { + if (!p) { + ceph_abort_msg("PyFormatter::dump_pyobject received null PyObject"); + } if (PyList_Check(cursor)) { PyList_Append(cursor, p); Py_DECREF(p);