]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/PyFormatter: prevent segfault on non-printable characters
authorNitzanMordhai <nmordech@ibm.com>
Wed, 21 Jan 2026 13:07:56 +0000 (13:07 +0000)
committerNitzanMordhai <nmordech@ibm.com>
Mon, 26 Jan 2026 12:57:20 +0000 (12:57 +0000)
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 <nmordec@ibm.com>
src/mgr/PyFormatter.cc

index 7c333308ab50e329806405f37a0f5d51b9f0fcc4..3bed72a088ab81faf1dca8150032f4d1fb5198b6 100644 (file)
@@ -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);