Merge sudo_module_register_loghandler and sudo_module_set_default_loghandler.

We now create the LogHandler class for each interpreter in
python_plugin_init() instead of just once in sudo_module_init().
This fixes the crash seen in Py_EndInterpreter() with Python 3.12
and significantly reduces the number of leaked objects tracked by
MemorySanitizer.
This commit is contained in:
Todd C. Miller
2023-07-24 11:07:45 -06:00
parent 56b829f66b
commit 09b9632699
4 changed files with 28 additions and 51 deletions

View File

@@ -27,8 +27,6 @@
# define PyObject_CallNoArgs(_o) PyObject_CallObject((_o), NULL)
#endif
static PyObject *sudo_type_LogHandler;
static void
_debug_plugin(unsigned int log_level, const char *log_message)
{
@@ -127,74 +125,58 @@ static PyMethodDef _sudo_LogHandler_class_methods[] =
{NULL, NULL, 0, NULL}
};
// This function registers sudo.LogHandler class
// This function creates the sudo.LogHandler class and adds it
// to the root logger.
int
sudo_module_register_loghandler(PyObject *py_module)
sudo_module_set_default_loghandler()
{
debug_decl(sudo_module_register_loghandler, PYTHON_DEBUG_INTERNAL);
PyObject *py_logging_module = NULL, *py_streamhandler = NULL;
PyObject *py_sudo, *py_logging_module = NULL, *py_logger = NULL,
*py_streamhandler = NULL, *py_class = NULL,
*py_loghandler = NULL, *py_result = NULL;
py_sudo = PyImport_ImportModule("sudo");
if (py_sudo == NULL)
goto cleanup;
py_logging_module = PyImport_ImportModule("logging");
if (py_logging_module == NULL)
goto cleanup;
// Get the root logger which all loggers descend from.
py_logger = PyObject_CallMethod(py_logging_module, "getLogger", NULL);
if (py_logger == NULL)
goto cleanup;
py_streamhandler = PyObject_GetAttrString(py_logging_module, "StreamHandler");
if (py_streamhandler == NULL)
goto cleanup;
sudo_type_LogHandler = sudo_module_create_class("sudo.LogHandler",
// Create our own handler that is a sub-class of StreamHandler
py_class = sudo_module_create_class("sudo.LogHandler",
_sudo_LogHandler_class_methods, py_streamhandler);
if (sudo_type_LogHandler == NULL)
if (py_class == NULL)
goto cleanup;
if (PyModule_AddObject(py_module, "LogHandler", sudo_type_LogHandler) < 0) {
Py_CLEAR(sudo_type_LogHandler);
// PyModule_AddObject steals a reference to py_class on success
if (PyModule_AddObject(py_sudo, "LogHandler", py_class) < 0)
goto cleanup;
}
Py_INCREF(py_class);
// PyModule_AddObject steals a reference to sudo_type_LogHandler on success
Py_INCREF(sudo_type_LogHandler);
cleanup:
Py_CLEAR(py_streamhandler);
Py_CLEAR(py_logging_module);
debug_return_int(PyErr_Occurred() ? SUDO_RC_ERROR : SUDO_RC_OK);
}
// This sets sudo.LogHandler as the default log handler:
// logging.getLogger().addHandler(sudo.LogHandler())
int
sudo_module_set_default_loghandler(void)
{
debug_decl(sudo_module_set_default_loghandler, PYTHON_DEBUG_INTERNAL);
PyObject *py_loghandler = NULL, *py_logging_module = NULL,
*py_logger = NULL, *py_result = NULL;
py_loghandler = PyObject_CallNoArgs(sudo_type_LogHandler);
py_loghandler = PyObject_CallNoArgs(py_class);
if (py_loghandler == NULL)
goto cleanup;
py_logging_module = PyImport_ImportModule("logging");
if (py_logging_module == NULL)
goto cleanup;
py_logger = PyObject_CallMethod(py_logging_module, "getLogger", NULL);
if (py_logger == NULL)
goto cleanup;
py_result = PyObject_CallMethod(py_logger, "addHandler", "O", py_loghandler);
cleanup:
Py_CLEAR(py_result);
Py_CLEAR(py_loghandler);
Py_CLEAR(py_class);
Py_CLEAR(py_streamhandler);
Py_CLEAR(py_logger);
Py_CLEAR(py_logging_module);
#if 0
// XXX - If we don't leak py_loghandler here we may get a crash in
// Py_EndInterpreter() on Python 3.12.
Py_CLEAR(py_loghandler);
#endif
Py_CLEAR(py_sudo);
debug_return_int(PyErr_Occurred() ? SUDO_RC_ERROR : SUDO_RC_OK);
}

View File

@@ -542,8 +542,9 @@ python_plugin_init(struct PluginContext *plugin_ctx, char * const plugin_options
goto cleanup;
}
if (sudo_module_set_default_loghandler() < 0)
if (sudo_module_set_default_loghandler() != SUDO_RC_OK) {
goto cleanup;
}
if (_python_plugin_set_path(plugin_ctx, _lookup_value(plugin_options, "ModulePath")) != SUDO_RC_OK) {
goto cleanup;

View File

@@ -595,9 +595,6 @@ sudo_module_init(void)
if (sudo_module_register_baseplugin(py_module) != SUDO_RC_OK)
goto cleanup;
if (sudo_module_register_loghandler(py_module) != SUDO_RC_OK)
goto cleanup;
cleanup:
if (PyErr_Occurred()) {
Py_CLEAR(py_module);

View File

@@ -45,9 +45,6 @@ int sudo_module_ConvMessages_to_c(PyObject *py_tuple, Py_ssize_t *num_msgs, stru
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
int sudo_module_register_baseplugin(PyObject *py_module);
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
int sudo_module_register_loghandler(PyObject *py_module);
CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION
int sudo_module_set_default_loghandler(void);