mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #15301: Parsing fd, uid, and gid parameters for builtins
in Modules/posixmodule.c is now far more robust.
This commit is contained in:
parent
7533137f4e
commit
a27b83ad2d
3 changed files with 205 additions and 81 deletions
|
@ -24,6 +24,8 @@ import itertools
|
||||||
import stat
|
import stat
|
||||||
import locale
|
import locale
|
||||||
import codecs
|
import codecs
|
||||||
|
import decimal
|
||||||
|
import fractions
|
||||||
try:
|
try:
|
||||||
import threading
|
import threading
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -865,6 +867,16 @@ class MakedirTests(unittest.TestCase):
|
||||||
os.makedirs(path, mode=mode, exist_ok=True)
|
os.makedirs(path, mode=mode, exist_ok=True)
|
||||||
os.umask(old_mask)
|
os.umask(old_mask)
|
||||||
|
|
||||||
|
def test_chown_uid_gid_arguments_must_be_index(self):
|
||||||
|
stat = os.stat(support.TESTFN)
|
||||||
|
uid = stat.st_uid
|
||||||
|
gid = stat.st_gid
|
||||||
|
for value in (-1.0, -1j, decimal.Decimal(-1), fractions.Fraction(-2, 2)):
|
||||||
|
self.assertRaises(TypeError, os.chown, support.TESTFN, value, gid)
|
||||||
|
self.assertRaises(TypeError, os.chown, support.TESTFN, uid, value)
|
||||||
|
self.assertIsNone(os.chown(support.TESTFN, uid, gid))
|
||||||
|
self.assertIsNone(os.chown(support.TESTFN, -1, -1))
|
||||||
|
|
||||||
def test_exist_ok_s_isgid_directory(self):
|
def test_exist_ok_s_isgid_directory(self):
|
||||||
path = os.path.join(support.TESTFN, 'dir1')
|
path = os.path.join(support.TESTFN, 'dir1')
|
||||||
S_ISGID = stat.S_ISGID
|
S_ISGID = stat.S_ISGID
|
||||||
|
|
|
@ -10,8 +10,11 @@ Projected Release date: 2013-09-08
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #15301: Parsing fd, uid, and gid parameters for builtins
|
||||||
|
in Modules/posixmodule.c is now far more robust.
|
||||||
|
|
||||||
- Issue #18368: PyOS_StdioReadline() no longer leaks memory when realloc()
|
- Issue #18368: PyOS_StdioReadline() no longer leaks memory when realloc()
|
||||||
fail
|
fail.
|
||||||
|
|
||||||
- Issue #17934: Add a clear() method to frame objects, to help clean up
|
- Issue #17934: Add a clear() method to frame objects, to help clean up
|
||||||
expensive details (local variables) and break reference cycles.
|
expensive details (local variables) and break reference cycles.
|
||||||
|
|
|
@ -417,108 +417,213 @@ _PyLong_FromGid(gid_t gid)
|
||||||
int
|
int
|
||||||
_Py_Uid_Converter(PyObject *obj, void *p)
|
_Py_Uid_Converter(PyObject *obj, void *p)
|
||||||
{
|
{
|
||||||
|
uid_t uid;
|
||||||
|
PyObject *index;
|
||||||
int overflow;
|
int overflow;
|
||||||
long result;
|
long result;
|
||||||
if (PyFloat_Check(obj)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"integer argument expected, got float");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
result = PyLong_AsLongAndOverflow(obj, &overflow);
|
|
||||||
if (overflow < 0)
|
|
||||||
goto OverflowDown;
|
|
||||||
if (!overflow && result == -1) {
|
|
||||||
/* error or -1 */
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return 0;
|
|
||||||
*(uid_t *)p = (uid_t)-1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* unsigned uid_t */
|
|
||||||
unsigned long uresult;
|
unsigned long uresult;
|
||||||
if (overflow > 0) {
|
|
||||||
uresult = PyLong_AsUnsignedLong(obj);
|
index = PyNumber_Index(obj);
|
||||||
|
if (index == NULL) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"uid should be integer, not %.200s",
|
||||||
|
Py_TYPE(obj)->tp_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handling uid_t is complicated for two reasons:
|
||||||
|
* * Although uid_t is (always?) unsigned, it still
|
||||||
|
* accepts -1.
|
||||||
|
* * We don't know its size in advance--it may be
|
||||||
|
* bigger than an int, or it may be smaller than
|
||||||
|
* a long.
|
||||||
|
*
|
||||||
|
* So a bit of defensive programming is in order.
|
||||||
|
* Start with interpreting the value passed
|
||||||
|
* in as a signed long and see if it works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = PyLong_AsLongAndOverflow(index, &overflow);
|
||||||
|
|
||||||
|
if (!overflow) {
|
||||||
|
uid = (uid_t)result;
|
||||||
|
|
||||||
|
if (result == -1) {
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
goto fail;
|
||||||
|
/* It's a legitimate -1, we're done. */
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any other negative number is disallowed. */
|
||||||
|
if (result < 0)
|
||||||
|
goto underflow;
|
||||||
|
|
||||||
|
/* Ensure the value wasn't truncated. */
|
||||||
|
if (sizeof(uid_t) < sizeof(long) &&
|
||||||
|
(long)uid != result)
|
||||||
|
goto underflow;
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow < 0)
|
||||||
|
goto underflow;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, the value overflowed a signed long. If it
|
||||||
|
* fits in an *unsigned* long, it may still be okay,
|
||||||
|
* as uid_t may be unsigned long on this platform.
|
||||||
|
*/
|
||||||
|
uresult = PyLong_AsUnsignedLong(index);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||||
goto OverflowUp;
|
goto overflow;
|
||||||
return 0;
|
goto fail;
|
||||||
}
|
|
||||||
if ((uid_t)uresult == (uid_t)-1)
|
|
||||||
goto OverflowUp;
|
|
||||||
} else {
|
|
||||||
if (result < 0)
|
|
||||||
goto OverflowDown;
|
|
||||||
uresult = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid = (uid_t)uresult;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If uid == (uid_t)-1, the user actually passed in ULONG_MAX,
|
||||||
|
* but this value would get interpreted as (uid_t)-1 by chown
|
||||||
|
* and its siblings. That's not what the user meant! So we
|
||||||
|
* throw an overflow exception instead. (We already
|
||||||
|
* handled a real -1 with PyLong_AsLongAndOverflow() above.)
|
||||||
|
*/
|
||||||
|
if (uid == (uid_t)-1)
|
||||||
|
goto overflow;
|
||||||
|
|
||||||
|
/* Ensure the value wasn't truncated. */
|
||||||
if (sizeof(uid_t) < sizeof(long) &&
|
if (sizeof(uid_t) < sizeof(long) &&
|
||||||
(unsigned long)(uid_t)uresult != uresult)
|
(unsigned long)uid != uresult)
|
||||||
goto OverflowUp;
|
goto overflow;
|
||||||
*(uid_t *)p = (uid_t)uresult;
|
/* fallthrough */
|
||||||
}
|
|
||||||
|
success:
|
||||||
|
Py_DECREF(index);
|
||||||
|
*(uid_t *)p = uid;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
OverflowDown:
|
underflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"user id is less than minimum");
|
"uid is less than minimum");
|
||||||
return 0;
|
goto fail;
|
||||||
|
|
||||||
OverflowUp:
|
overflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"user id is greater than maximum");
|
"uid is greater than maximum");
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
|
fail:
|
||||||
|
Py_DECREF(index);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_Py_Gid_Converter(PyObject *obj, void *p)
|
_Py_Gid_Converter(PyObject *obj, void *p)
|
||||||
{
|
{
|
||||||
|
gid_t gid;
|
||||||
|
PyObject *index;
|
||||||
int overflow;
|
int overflow;
|
||||||
long result;
|
long result;
|
||||||
if (PyFloat_Check(obj)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"integer argument expected, got float");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
result = PyLong_AsLongAndOverflow(obj, &overflow);
|
|
||||||
if (overflow < 0)
|
|
||||||
goto OverflowDown;
|
|
||||||
if (!overflow && result == -1) {
|
|
||||||
/* error or -1 */
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return 0;
|
|
||||||
*(gid_t *)p = (gid_t)-1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* unsigned gid_t */
|
|
||||||
unsigned long uresult;
|
unsigned long uresult;
|
||||||
if (overflow > 0) {
|
|
||||||
uresult = PyLong_AsUnsignedLong(obj);
|
index = PyNumber_Index(obj);
|
||||||
|
if (index == NULL) {
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"gid should be integer, not %.200s",
|
||||||
|
Py_TYPE(obj)->tp_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handling gid_t is complicated for two reasons:
|
||||||
|
* * Although gid_t is (always?) unsigned, it still
|
||||||
|
* accepts -1.
|
||||||
|
* * We don't know its size in advance--it may be
|
||||||
|
* bigger than an int, or it may be smaller than
|
||||||
|
* a long.
|
||||||
|
*
|
||||||
|
* So a bit of defensive programming is in order.
|
||||||
|
* Start with interpreting the value passed
|
||||||
|
* in as a signed long and see if it works.
|
||||||
|
*/
|
||||||
|
|
||||||
|
result = PyLong_AsLongAndOverflow(index, &overflow);
|
||||||
|
|
||||||
|
if (!overflow) {
|
||||||
|
gid = (gid_t)result;
|
||||||
|
|
||||||
|
if (result == -1) {
|
||||||
|
if (PyErr_Occurred())
|
||||||
|
goto fail;
|
||||||
|
/* It's a legitimate -1, we're done. */
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any other negative number is disallowed. */
|
||||||
|
if (result < 0) {
|
||||||
|
goto underflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure the value wasn't truncated. */
|
||||||
|
if (sizeof(gid_t) < sizeof(long) &&
|
||||||
|
(long)gid != result)
|
||||||
|
goto underflow;
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overflow < 0)
|
||||||
|
goto underflow;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Okay, the value overflowed a signed long. If it
|
||||||
|
* fits in an *unsigned* long, it may still be okay,
|
||||||
|
* as gid_t may be unsigned long on this platform.
|
||||||
|
*/
|
||||||
|
uresult = PyLong_AsUnsignedLong(index);
|
||||||
if (PyErr_Occurred()) {
|
if (PyErr_Occurred()) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
if (PyErr_ExceptionMatches(PyExc_OverflowError))
|
||||||
goto OverflowUp;
|
goto overflow;
|
||||||
return 0;
|
goto fail;
|
||||||
}
|
|
||||||
if ((gid_t)uresult == (gid_t)-1)
|
|
||||||
goto OverflowUp;
|
|
||||||
} else {
|
|
||||||
if (result < 0)
|
|
||||||
goto OverflowDown;
|
|
||||||
uresult = result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gid = (gid_t)uresult;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If gid == (gid_t)-1, the user actually passed in ULONG_MAX,
|
||||||
|
* but this value would get interpreted as (gid_t)-1 by chown
|
||||||
|
* and its siblings. That's not what the user meant! So we
|
||||||
|
* throw an overflow exception instead. (We already
|
||||||
|
* handled a real -1 with PyLong_AsLongAndOverflow() above.)
|
||||||
|
*/
|
||||||
|
if (gid == (gid_t)-1)
|
||||||
|
goto overflow;
|
||||||
|
|
||||||
|
/* Ensure the value wasn't truncated. */
|
||||||
if (sizeof(gid_t) < sizeof(long) &&
|
if (sizeof(gid_t) < sizeof(long) &&
|
||||||
(unsigned long)(gid_t)uresult != uresult)
|
(unsigned long)gid != uresult)
|
||||||
goto OverflowUp;
|
goto overflow;
|
||||||
*(gid_t *)p = (gid_t)uresult;
|
/* fallthrough */
|
||||||
}
|
|
||||||
|
success:
|
||||||
|
Py_DECREF(index);
|
||||||
|
*(gid_t *)p = gid;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
OverflowDown:
|
underflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"group id is less than minimum");
|
"gid is less than minimum");
|
||||||
return 0;
|
goto fail;
|
||||||
|
|
||||||
OverflowUp:
|
overflow:
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"group id is greater than maximum");
|
"gid is greater than maximum");
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
|
fail:
|
||||||
|
Py_DECREF(index);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* MS_WINDOWS */
|
#endif /* MS_WINDOWS */
|
||||||
|
@ -541,25 +646,29 @@ static int
|
||||||
_fd_converter(PyObject *o, int *p, const char *allowed)
|
_fd_converter(PyObject *o, int *p, const char *allowed)
|
||||||
{
|
{
|
||||||
int overflow;
|
int overflow;
|
||||||
long long_value = PyLong_AsLongAndOverflow(o, &overflow);
|
long long_value;
|
||||||
if (PyFloat_Check(o) ||
|
|
||||||
(long_value == -1 && !overflow && PyErr_Occurred())) {
|
PyObject *index = PyNumber_Index(o);
|
||||||
PyErr_Clear();
|
if (index == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"argument should be %s, not %.200s",
|
"argument should be %s, not %.200s",
|
||||||
allowed, Py_TYPE(o)->tp_name);
|
allowed, Py_TYPE(o)->tp_name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long_value = PyLong_AsLongAndOverflow(index, &overflow);
|
||||||
|
Py_DECREF(index);
|
||||||
if (overflow > 0 || long_value > INT_MAX) {
|
if (overflow > 0 || long_value > INT_MAX) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"signed integer is greater than maximum");
|
"fd is greater than maximum");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (overflow < 0 || long_value < INT_MIN) {
|
if (overflow < 0 || long_value < INT_MIN) {
|
||||||
PyErr_SetString(PyExc_OverflowError,
|
PyErr_SetString(PyExc_OverflowError,
|
||||||
"signed integer is less than minimum");
|
"fd is less than minimum");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*p = (int)long_value;
|
*p = (int)long_value;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue