Issue #29034: Fix memory leak and use-after-free in path_converter.
This commit is contained in:
parent
ec53b07ef1
commit
04316c4cc8
|
@ -10,6 +10,8 @@ What's New in Python 3.6.1 release candidate 1?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #29034: Fix memory leak and use-after-free in os module (path_converter).
|
||||||
|
|
||||||
- Issue #29159: Fix regression in bytes(x) when x.__index__() raises Exception.
|
- Issue #29159: Fix regression in bytes(x) when x.__index__() raises Exception.
|
||||||
|
|
||||||
- Issue #28932: Do not include <sys/random.h> if it does not exist.
|
- Issue #28932: Do not include <sys/random.h> if it does not exist.
|
||||||
|
|
|
@ -785,7 +785,9 @@ dir_fd_converter(PyObject *o, void *p)
|
||||||
* The length of the path in characters, if specified as
|
* The length of the path in characters, if specified as
|
||||||
* a string.
|
* a string.
|
||||||
* path.object
|
* path.object
|
||||||
* The original object passed in.
|
* The original object passed in (if get a PathLike object,
|
||||||
|
* the result of PyOS_FSPath() is treated as the original object).
|
||||||
|
* Own a reference to the object.
|
||||||
* path.cleanup
|
* path.cleanup
|
||||||
* For internal use only. May point to a temporary object.
|
* For internal use only. May point to a temporary object.
|
||||||
* (Pay no attention to the man behind the curtain.)
|
* (Pay no attention to the man behind the curtain.)
|
||||||
|
@ -836,24 +838,22 @@ typedef struct {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
path_cleanup(path_t *path) {
|
path_cleanup(path_t *path)
|
||||||
if (path->cleanup) {
|
{
|
||||||
Py_CLEAR(path->cleanup);
|
Py_CLEAR(path->object);
|
||||||
}
|
Py_CLEAR(path->cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
path_converter(PyObject *o, void *p)
|
path_converter(PyObject *o, void *p)
|
||||||
{
|
{
|
||||||
path_t *path = (path_t *)p;
|
path_t *path = (path_t *)p;
|
||||||
PyObject *bytes, *to_cleanup = NULL;
|
PyObject *bytes = NULL;
|
||||||
Py_ssize_t length;
|
Py_ssize_t length = 0;
|
||||||
int is_index, is_buffer, is_bytes, is_unicode;
|
int is_index, is_buffer, is_bytes, is_unicode;
|
||||||
/* Default to failure, forcing explicit signaling of succcess. */
|
|
||||||
int ret = 0;
|
|
||||||
const char *narrow;
|
const char *narrow;
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
PyObject *wo;
|
PyObject *wo = NULL;
|
||||||
const wchar_t *wide;
|
const wchar_t *wide;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -870,7 +870,9 @@ path_converter(PyObject *o, void *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ensure it's always safe to call path_cleanup(). */
|
/* Ensure it's always safe to call path_cleanup(). */
|
||||||
path->cleanup = NULL;
|
path->object = path->cleanup = NULL;
|
||||||
|
/* path->object owns a reference to the original object */
|
||||||
|
Py_INCREF(o);
|
||||||
|
|
||||||
if ((o == Py_None) && path->nullable) {
|
if ((o == Py_None) && path->nullable) {
|
||||||
path->wide = NULL;
|
path->wide = NULL;
|
||||||
|
@ -879,10 +881,8 @@ path_converter(PyObject *o, void *p)
|
||||||
#else
|
#else
|
||||||
path->narrow = NULL;
|
path->narrow = NULL;
|
||||||
#endif
|
#endif
|
||||||
path->length = 0;
|
|
||||||
path->object = o;
|
|
||||||
path->fd = -1;
|
path->fd = -1;
|
||||||
return 1;
|
goto success_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only call this here so that we don't treat the return value of
|
/* Only call this here so that we don't treat the return value of
|
||||||
|
@ -899,10 +899,11 @@ path_converter(PyObject *o, void *p)
|
||||||
|
|
||||||
func = _PyObject_LookupSpecial(o, &PyId___fspath__);
|
func = _PyObject_LookupSpecial(o, &PyId___fspath__);
|
||||||
if (NULL == func) {
|
if (NULL == func) {
|
||||||
goto error_exit;
|
goto error_format;
|
||||||
}
|
}
|
||||||
|
/* still owns a reference to the original object */
|
||||||
o = to_cleanup = PyObject_CallFunctionObjArgs(func, NULL);
|
Py_DECREF(o);
|
||||||
|
o = _PyObject_CallNoArg(func);
|
||||||
Py_DECREF(func);
|
Py_DECREF(func);
|
||||||
if (NULL == o) {
|
if (NULL == o) {
|
||||||
goto error_exit;
|
goto error_exit;
|
||||||
|
@ -914,7 +915,7 @@ path_converter(PyObject *o, void *p)
|
||||||
is_bytes = 1;
|
is_bytes = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goto error_exit;
|
goto error_format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,26 +923,24 @@ path_converter(PyObject *o, void *p)
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
wide = PyUnicode_AsUnicodeAndSize(o, &length);
|
wide = PyUnicode_AsUnicodeAndSize(o, &length);
|
||||||
if (!wide) {
|
if (!wide) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
if (length > 32767) {
|
if (length > 32767) {
|
||||||
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
|
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
if (wcslen(wide) != length) {
|
if (wcslen(wide) != length) {
|
||||||
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
path->wide = wide;
|
path->wide = wide;
|
||||||
path->length = length;
|
path->narrow = FALSE;
|
||||||
path->object = o;
|
|
||||||
path->fd = -1;
|
path->fd = -1;
|
||||||
ret = 1;
|
goto success_exit;
|
||||||
goto exit;
|
|
||||||
#else
|
#else
|
||||||
if (!PyUnicode_FSConverter(o, &bytes)) {
|
if (!PyUnicode_FSConverter(o, &bytes)) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -961,16 +960,16 @@ path_converter(PyObject *o, void *p)
|
||||||
path->nullable ? "string, bytes, os.PathLike or None" :
|
path->nullable ? "string, bytes, os.PathLike or None" :
|
||||||
"string, bytes or os.PathLike",
|
"string, bytes or os.PathLike",
|
||||||
Py_TYPE(o)->tp_name)) {
|
Py_TYPE(o)->tp_name)) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
bytes = PyBytes_FromObject(o);
|
bytes = PyBytes_FromObject(o);
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_index) {
|
else if (is_index) {
|
||||||
if (!_fd_converter(o, &path->fd)) {
|
if (!_fd_converter(o, &path->fd)) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
path->wide = NULL;
|
path->wide = NULL;
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
|
@ -978,13 +977,10 @@ path_converter(PyObject *o, void *p)
|
||||||
#else
|
#else
|
||||||
path->narrow = NULL;
|
path->narrow = NULL;
|
||||||
#endif
|
#endif
|
||||||
path->length = 0;
|
goto success_exit;
|
||||||
path->object = o;
|
|
||||||
ret = 1;
|
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
error_exit:
|
error_format:
|
||||||
PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s",
|
PyErr_Format(PyExc_TypeError, "%s%s%s should be %s, not %.200s",
|
||||||
path->function_name ? path->function_name : "",
|
path->function_name ? path->function_name : "",
|
||||||
path->function_name ? ": " : "",
|
path->function_name ? ": " : "",
|
||||||
|
@ -995,15 +991,14 @@ path_converter(PyObject *o, void *p)
|
||||||
path->nullable ? "string, bytes, os.PathLike or None" :
|
path->nullable ? "string, bytes, os.PathLike or None" :
|
||||||
"string, bytes or os.PathLike",
|
"string, bytes or os.PathLike",
|
||||||
Py_TYPE(o)->tp_name);
|
Py_TYPE(o)->tp_name);
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = PyBytes_GET_SIZE(bytes);
|
length = PyBytes_GET_SIZE(bytes);
|
||||||
narrow = PyBytes_AS_STRING(bytes);
|
narrow = PyBytes_AS_STRING(bytes);
|
||||||
if ((size_t)length != strlen(narrow)) {
|
if ((size_t)length != strlen(narrow)) {
|
||||||
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
||||||
Py_DECREF(bytes);
|
goto error_exit;
|
||||||
goto exit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MS_WINDOWS
|
#ifdef MS_WINDOWS
|
||||||
|
@ -1012,43 +1007,51 @@ path_converter(PyObject *o, void *p)
|
||||||
length
|
length
|
||||||
);
|
);
|
||||||
if (!wo) {
|
if (!wo) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
wide = PyUnicode_AsWideCharString(wo, &length);
|
wide = PyUnicode_AsUnicodeAndSize(wo, &length);
|
||||||
Py_DECREF(wo);
|
|
||||||
|
|
||||||
if (!wide) {
|
if (!wide) {
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
if (length > 32767) {
|
if (length > 32767) {
|
||||||
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
|
FORMAT_EXCEPTION(PyExc_ValueError, "%s too long for Windows");
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
if (wcslen(wide) != length) {
|
if (wcslen(wide) != length) {
|
||||||
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s");
|
||||||
goto exit;
|
goto error_exit;
|
||||||
}
|
}
|
||||||
path->wide = wide;
|
path->wide = wide;
|
||||||
path->narrow = TRUE;
|
path->narrow = TRUE;
|
||||||
|
path->cleanup = wo;
|
||||||
|
Py_DECREF(bytes);
|
||||||
#else
|
#else
|
||||||
path->wide = NULL;
|
path->wide = NULL;
|
||||||
path->narrow = narrow;
|
path->narrow = narrow;
|
||||||
#endif
|
|
||||||
path->length = length;
|
|
||||||
path->object = o;
|
|
||||||
path->fd = -1;
|
|
||||||
if (bytes == o) {
|
if (bytes == o) {
|
||||||
|
/* Still a reference owned by path->object, don't have to
|
||||||
|
worry about path->narrow is used after free. */
|
||||||
Py_DECREF(bytes);
|
Py_DECREF(bytes);
|
||||||
ret = 1;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
path->cleanup = bytes;
|
path->cleanup = bytes;
|
||||||
ret = Py_CLEANUP_SUPPORTED;
|
|
||||||
}
|
}
|
||||||
exit:
|
#endif
|
||||||
Py_XDECREF(to_cleanup);
|
path->fd = -1;
|
||||||
return ret;
|
|
||||||
|
success_exit:
|
||||||
|
path->length = length;
|
||||||
|
path->object = o;
|
||||||
|
return Py_CLEANUP_SUPPORTED;
|
||||||
|
|
||||||
|
error_exit:
|
||||||
|
Py_XDECREF(o);
|
||||||
|
Py_XDECREF(bytes);
|
||||||
|
#ifdef MS_WINDOWS
|
||||||
|
Py_XDECREF(wo);
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue