summaryrefslogtreecommitdiff
path: root/Python/sysmodule.c
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-11-08 21:26:14 +0200
committerSerhiy Storchaka <storchaka@gmail.com>2016-11-08 21:26:14 +0200
commit50089e6b181b36e0a1f76dd38e9e1b90a2230a3a (patch)
treee7f3bfc68d0b37e907274f16610e49a6b37acf8c /Python/sysmodule.c
parent5f7236d4e16f4f4eee4da97621a6f8a225dfba4e (diff)
parentc23389c5b86aec7fa48af1b3736e6443725e8ea0 (diff)
downloadcpython-50089e6b181b36e0a1f76dd38e9e1b90a2230a3a.tar.gz
Issue #28563: Fixed possible DoS and arbitrary code execution when handle
plural form selections in the gettext module. The expression parser now supports exact syntax supported by GNU gettext.
Diffstat (limited to 'Python/sysmodule.c')
-rw-r--r--Python/sysmodule.c141
1 files changed, 133 insertions, 8 deletions
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 290eec1199..1dc7d7cf6b 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -632,19 +632,84 @@ processor's time-stamp counter."
static PyObject *
sys_setrecursionlimit(PyObject *self, PyObject *args)
{
- int new_limit;
+ int new_limit, mark;
+ PyThreadState *tstate;
+
if (!PyArg_ParseTuple(args, "i:setrecursionlimit", &new_limit))
return NULL;
- if (new_limit <= 0) {
+
+ if (new_limit < 1) {
PyErr_SetString(PyExc_ValueError,
- "recursion limit must be positive");
+ "recursion limit must be greater or equal than 1");
return NULL;
}
+
+ /* Issue #25274: When the recursion depth hits the recursion limit in
+ _Py_CheckRecursiveCall(), the overflowed flag of the thread state is
+ set to 1 and a RecursionError is raised. The overflowed flag is reset
+ to 0 when the recursion depth goes below the low-water mark: see
+ Py_LeaveRecursiveCall().
+
+ Reject too low new limit if the current recursion depth is higher than
+ the new low-water mark. Otherwise it may not be possible anymore to
+ reset the overflowed flag to 0. */
+ mark = _Py_RecursionLimitLowerWaterMark(new_limit);
+ tstate = PyThreadState_GET();
+ if (tstate->recursion_depth >= mark) {
+ PyErr_Format(PyExc_RecursionError,
+ "cannot set the recursion limit to %i at "
+ "the recursion depth %i: the limit is too low",
+ new_limit, tstate->recursion_depth);
+ return NULL;
+ }
+
Py_SetRecursionLimit(new_limit);
Py_INCREF(Py_None);
return Py_None;
}
+static PyObject *
+sys_set_coroutine_wrapper(PyObject *self, PyObject *wrapper)
+{
+ if (wrapper != Py_None) {
+ if (!PyCallable_Check(wrapper)) {
+ PyErr_Format(PyExc_TypeError,
+ "callable expected, got %.50s",
+ Py_TYPE(wrapper)->tp_name);
+ return NULL;
+ }
+ _PyEval_SetCoroutineWrapper(wrapper);
+ }
+ else {
+ _PyEval_SetCoroutineWrapper(NULL);
+ }
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(set_coroutine_wrapper_doc,
+"set_coroutine_wrapper(wrapper)\n\
+\n\
+Set a wrapper for coroutine objects."
+);
+
+static PyObject *
+sys_get_coroutine_wrapper(PyObject *self, PyObject *args)
+{
+ PyObject *wrapper = _PyEval_GetCoroutineWrapper();
+ if (wrapper == NULL) {
+ wrapper = Py_None;
+ }
+ Py_INCREF(wrapper);
+ return wrapper;
+}
+
+PyDoc_STRVAR(get_coroutine_wrapper_doc,
+"get_coroutine_wrapper()\n\
+\n\
+Return the wrapper for coroutine objects set by sys.set_coroutine_wrapper."
+);
+
+
static PyTypeObject Hash_InfoType;
PyDoc_STRVAR(hash_info_doc,
@@ -760,6 +825,7 @@ static PyStructSequence_Field windows_version_fields[] = {
{"service_pack_minor", "Service Pack minor version number"},
{"suite_mask", "Bit mask identifying available product suites"},
{"product_type", "System product type"},
+ {"_platform_version", "Diagnostic version number"},
{0}
};
@@ -772,12 +838,24 @@ static PyStructSequence_Desc windows_version_desc = {
via indexing, the rest are name only */
};
+/* Disable deprecation warnings about GetVersionEx as the result is
+ being passed straight through to the caller, who is responsible for
+ using it correctly. */
+#pragma warning(push)
+#pragma warning(disable:4996)
+
static PyObject *
sys_getwindowsversion(PyObject *self)
{
PyObject *version;
int pos = 0;
OSVERSIONINFOEX ver;
+ DWORD realMajor, realMinor, realBuild;
+ HANDLE hKernel32;
+ wchar_t kernel32_path[MAX_PATH];
+ LPVOID verblock;
+ DWORD verblock_size;
+
ver.dwOSVersionInfoSize = sizeof(ver);
if (!GetVersionEx((OSVERSIONINFO*) &ver))
return PyErr_SetFromWindowsErr(0);
@@ -796,13 +874,45 @@ sys_getwindowsversion(PyObject *self)
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wSuiteMask));
PyStructSequence_SET_ITEM(version, pos++, PyLong_FromLong(ver.wProductType));
+ realMajor = ver.dwMajorVersion;
+ realMinor = ver.dwMinorVersion;
+ realBuild = ver.dwBuildNumber;
+
+ // GetVersion will lie if we are running in a compatibility mode.
+ // We need to read the version info from a system file resource
+ // to accurately identify the OS version. If we fail for any reason,
+ // just return whatever GetVersion said.
+ hKernel32 = GetModuleHandleW(L"kernel32.dll");
+ if (hKernel32 && GetModuleFileNameW(hKernel32, kernel32_path, MAX_PATH) &&
+ (verblock_size = GetFileVersionInfoSizeW(kernel32_path, NULL)) &&
+ (verblock = PyMem_RawMalloc(verblock_size))) {
+ VS_FIXEDFILEINFO *ffi;
+ UINT ffi_len;
+
+ if (GetFileVersionInfoW(kernel32_path, 0, verblock_size, verblock) &&
+ VerQueryValueW(verblock, L"", (LPVOID)&ffi, &ffi_len)) {
+ realMajor = HIWORD(ffi->dwProductVersionMS);
+ realMinor = LOWORD(ffi->dwProductVersionMS);
+ realBuild = HIWORD(ffi->dwProductVersionLS);
+ }
+ PyMem_RawFree(verblock);
+ }
+ PyStructSequence_SET_ITEM(version, pos++, PyTuple_Pack(3,
+ PyLong_FromLong(realMajor),
+ PyLong_FromLong(realMinor),
+ PyLong_FromLong(realBuild)
+ ));
+
if (PyErr_Occurred()) {
Py_DECREF(version);
return NULL;
}
+
return version;
}
+#pragma warning(pop)
+
#endif /* MS_WINDOWS */
#ifdef HAVE_DLOPEN
@@ -1121,6 +1231,16 @@ PyDoc_STRVAR(sys_clear_type_cache__doc__,
"_clear_type_cache() -> None\n\
Clear the internal type lookup cache.");
+static PyObject *
+sys_is_finalizing(PyObject* self, PyObject* args)
+{
+ return PyBool_FromLong(_Py_Finalizing != NULL);
+}
+
+PyDoc_STRVAR(is_finalizing_doc,
+"is_finalizing()\n\
+Return True if Python is exiting.");
+
static PyMethodDef sys_methods[] = {
/* Might as well keep this in alphabetic order */
@@ -1167,6 +1287,7 @@ static PyMethodDef sys_methods[] = {
getwindowsversion_doc},
#endif /* MS_WINDOWS */
{"intern", sys_intern, METH_VARARGS, intern_doc},
+ {"is_finalizing", sys_is_finalizing, METH_NOARGS, is_finalizing_doc},
#ifdef USE_MALLOPT
{"mdebug", sys_mdebug, METH_VARARGS},
#endif
@@ -1196,6 +1317,10 @@ static PyMethodDef sys_methods[] = {
{"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc},
{"_debugmallocstats", sys_debugmallocstats, METH_NOARGS,
debugmallocstats_doc},
+ {"set_coroutine_wrapper", sys_set_coroutine_wrapper, METH_O,
+ set_coroutine_wrapper_doc},
+ {"get_coroutine_wrapper", sys_get_coroutine_wrapper, METH_NOARGS,
+ get_coroutine_wrapper_doc},
{NULL, NULL} /* sentinel */
};
@@ -1309,7 +1434,7 @@ error:
Py_XDECREF(name);
Py_XDECREF(value);
/* No return value, therefore clear error state if possible */
- if (_Py_atomic_load_relaxed(&_PyThreadState_Current))
+ if (_PyThreadState_UncheckedGet())
PyErr_Clear();
}
@@ -1494,7 +1619,7 @@ static PyStructSequence_Field version_info_fields[] = {
{"major", "Major release number"},
{"minor", "Minor release number"},
{"micro", "Patch release number"},
- {"releaselevel", "'alpha', 'beta', 'candidate', or 'release'"},
+ {"releaselevel", "'alpha', 'beta', 'candidate', or 'final'"},
{"serial", "Serial release number"},
{0}
};
@@ -1670,8 +1795,8 @@ _PySys_Init(void)
the shell already prevents that. */
#if !defined(MS_WINDOWS)
{
- struct stat sb;
- if (fstat(fileno(stdin), &sb) == 0 &&
+ struct _Py_stat_struct sb;
+ if (_Py_fstat_noraise(fileno(stdin), &sb) == 0 &&
S_ISDIR(sb.st_mode)) {
/* There's nothing more we can do. */
/* Py_FatalError() will core dump, so just exit. */
@@ -1681,7 +1806,7 @@ _PySys_Init(void)
}
#endif
- /* stdin/stdout/stderr are now set by pythonrun.c */
+ /* stdin/stdout/stderr are set in pylifecycle.c */
SET_SYS_FROM_STRING_BORROW("__displayhook__",
PyDict_GetItemString(sysdict, "displayhook"));