diff --git a/00157-uid-gid-overflows.patch b/00157-uid-gid-overflows.patch new file mode 100644 index 0000000..dc533fd --- /dev/null +++ b/00157-uid-gid-overflows.patch @@ -0,0 +1,728 @@ +diff -up Python-2.7.3/Include/modsupport.h.uid-gid-overflows Python-2.7.3/Include/modsupport.h +--- Python-2.7.3/Include/modsupport.h.uid-gid-overflows 2012-04-09 19:07:29.000000000 -0400 ++++ Python-2.7.3/Include/modsupport.h 2012-05-15 18:57:52.215433846 -0400 +@@ -128,6 +128,17 @@ PyAPI_FUNC(PyObject *) Py_InitModule4(co + + PyAPI_DATA(char *) _Py_PackageContext; + ++/* ++ Non-standard extension: support for dealing with uid_t and gid_t without ++ integer overflow ++ */ ++ ++PyAPI_FUNC(PyObject *) _PyObject_FromUid(uid_t uid); ++PyAPI_FUNC(PyObject *) _PyObject_FromGid(gid_t gid); ++ ++PyAPI_FUNC(int) _PyArg_ParseUid(PyObject *in_obj, uid_t *out_uid); ++PyAPI_FUNC(int) _PyArg_ParseGid(PyObject *in_obj, gid_t *out_gid); ++ + #ifdef __cplusplus + } + #endif +diff -up Python-2.7.3/Lib/test/test_grp.py.uid-gid-overflows Python-2.7.3/Lib/test/test_grp.py +--- Python-2.7.3/Lib/test/test_grp.py.uid-gid-overflows 2012-04-09 19:07:31.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_grp.py 2012-05-15 18:57:52.216433855 -0400 +@@ -16,7 +16,7 @@ class GroupDatabaseTestCase(unittest.Tes + self.assertEqual(value[1], value.gr_passwd) + self.assertIsInstance(value.gr_passwd, basestring) + self.assertEqual(value[2], value.gr_gid) +- self.assertIsInstance(value.gr_gid, int) ++ self.assertIsInstance(value.gr_gid, (int, long)) + self.assertEqual(value[3], value.gr_mem) + self.assertIsInstance(value.gr_mem, list) + +diff -up Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows Python-2.7.3/Lib/test/test_os.py +--- Python-2.7.3/Lib/test/test_os.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_os.py 2012-05-15 18:57:52.217433864 -0400 +@@ -677,30 +677,36 @@ if sys.platform != 'win32': + def test_setuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setuid, 0) ++ self.assertRaises(TypeError, os.setuid, 'not an int') + self.assertRaises(OverflowError, os.setuid, 1<<32) + + if hasattr(os, 'setgid'): + def test_setgid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setgid, 0) ++ self.assertRaises(TypeError, os.setgid, 'not an int') + self.assertRaises(OverflowError, os.setgid, 1<<32) + + if hasattr(os, 'seteuid'): + def test_seteuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.seteuid, 0) ++ self.assertRaises(TypeError, os.seteuid, 'not an int') + self.assertRaises(OverflowError, os.seteuid, 1<<32) + + if hasattr(os, 'setegid'): + def test_setegid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setegid, 0) ++ self.assertRaises(TypeError, os.setegid, 'not an int') + self.assertRaises(OverflowError, os.setegid, 1<<32) + + if hasattr(os, 'setreuid'): + def test_setreuid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setreuid, 0, 0) ++ self.assertRaises(TypeError, os.setreuid, 'not an int', 0) ++ self.assertRaises(TypeError, os.setreuid, 0, 'not an int') + self.assertRaises(OverflowError, os.setreuid, 1<<32, 0) + self.assertRaises(OverflowError, os.setreuid, 0, 1<<32) + +@@ -715,6 +721,8 @@ if sys.platform != 'win32': + def test_setregid(self): + if os.getuid() != 0: + self.assertRaises(os.error, os.setregid, 0, 0) ++ self.assertRaises(TypeError, os.setregid, 'not an int', 0) ++ self.assertRaises(TypeError, os.setregid, 0, 'not an int') + self.assertRaises(OverflowError, os.setregid, 1<<32, 0) + self.assertRaises(OverflowError, os.setregid, 0, 1<<32) + +diff -up Python-2.7.3/Lib/test/test_posix.py.uid-gid-overflows Python-2.7.3/Lib/test/test_posix.py +--- Python-2.7.3/Lib/test/test_posix.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_posix.py 2012-05-15 18:57:52.218433873 -0400 +@@ -217,7 +217,7 @@ class PosixTester(unittest.TestCase): + if hasattr(posix, 'stat'): + self.assertTrue(posix.stat(test_support.TESTFN)) + +- def _test_all_chown_common(self, chown_func, first_param): ++ def _test_all_chown_common(self, chown_func, stat_func, first_param): + """Common code for chown, fchown and lchown tests.""" + if os.getuid() == 0: + try: +@@ -237,6 +237,13 @@ class PosixTester(unittest.TestCase): + + # test a successful chown call + chown_func(first_param, os.getuid(), os.getgid()) ++ self.assertEqual(stat_func(first_param).st_uid, os.getuid()) ++ self.assertEqual(stat_func(first_param).st_gid, os.getgid()) ++ ++ # verify that -1 works as a "do-nothing" option: ++ chown_func(first_param, -1, -1) ++ self.assertEqual(stat_func(first_param).st_uid, os.getuid()) ++ self.assertEqual(stat_func(first_param).st_gid, os.getgid()) + + @unittest.skipUnless(hasattr(posix, 'chown'), "test needs os.chown()") + def test_chown(self): +@@ -246,7 +253,7 @@ class PosixTester(unittest.TestCase): + + # re-create the file + open(test_support.TESTFN, 'w').close() +- self._test_all_chown_common(posix.chown, test_support.TESTFN) ++ self._test_all_chown_common(posix.chown, posix.stat, test_support.TESTFN) + + @unittest.skipUnless(hasattr(posix, 'fchown'), "test needs os.fchown()") + def test_fchown(self): +@@ -256,7 +263,7 @@ class PosixTester(unittest.TestCase): + test_file = open(test_support.TESTFN, 'w') + try: + fd = test_file.fileno() +- self._test_all_chown_common(posix.fchown, fd) ++ self._test_all_chown_common(posix.fchown, posix.fstat, fd) + finally: + test_file.close() + +@@ -265,7 +272,7 @@ class PosixTester(unittest.TestCase): + os.unlink(test_support.TESTFN) + # create a symlink + os.symlink(_DUMMY_SYMLINK, test_support.TESTFN) +- self._test_all_chown_common(posix.lchown, test_support.TESTFN) ++ self._test_all_chown_common(posix.lchown, posix.lstat, test_support.TESTFN) + + def test_chdir(self): + if hasattr(posix, 'chdir'): +diff -up Python-2.7.3/Lib/test/test_pwd.py.uid-gid-overflows Python-2.7.3/Lib/test/test_pwd.py +--- Python-2.7.3/Lib/test/test_pwd.py.uid-gid-overflows 2012-04-09 19:07:32.000000000 -0400 ++++ Python-2.7.3/Lib/test/test_pwd.py 2012-05-17 14:53:04.353015373 -0400 +@@ -18,9 +18,9 @@ class PwdTest(unittest.TestCase): + self.assertEqual(e[1], e.pw_passwd) + self.assertIsInstance(e.pw_passwd, basestring) + self.assertEqual(e[2], e.pw_uid) +- self.assertIsInstance(e.pw_uid, int) ++ self.assertIsInstance(e.pw_uid, (int, long)) + self.assertEqual(e[3], e.pw_gid) +- self.assertIsInstance(e.pw_gid, int) ++ self.assertIsInstance(e.pw_gid, (int, long)) + self.assertEqual(e[4], e.pw_gecos) + self.assertIsInstance(e.pw_gecos, basestring) + self.assertEqual(e[5], e.pw_dir) +@@ -87,9 +87,9 @@ class PwdTest(unittest.TestCase): + # In some cases, byuids isn't a complete list of all users in the + # system, so if we try to pick a value not in byuids (via a perturbing + # loop, say), pwd.getpwuid() might still be able to find data for that +- # uid. Using sys.maxint may provoke the same problems, but hopefully ++ # uid. Using 2**32 - 2 may provoke the same problems, but hopefully + # it will be a more repeatable failure. +- fakeuid = sys.maxint ++ fakeuid = 2**32 - 2 + self.assertNotIn(fakeuid, byuids) + self.assertRaises(KeyError, pwd.getpwuid, fakeuid) + +diff -up Python-2.7.3/Modules/grpmodule.c.uid-gid-overflows Python-2.7.3/Modules/grpmodule.c +--- Python-2.7.3/Modules/grpmodule.c.uid-gid-overflows 2012-04-09 19:07:34.000000000 -0400 ++++ Python-2.7.3/Modules/grpmodule.c 2012-05-15 18:57:52.220433893 -0400 +@@ -70,7 +70,7 @@ mkgrent(struct group *p) + Py_INCREF(Py_None); + } + #endif +- SET(setIndex++, PyInt_FromLong((long) p->gr_gid)); ++ SET(setIndex++, _PyObject_FromGid(p->gr_gid)); + SET(setIndex++, w); + #undef SET + +@@ -85,18 +85,15 @@ mkgrent(struct group *p) + static PyObject * + grp_getgrgid(PyObject *self, PyObject *pyo_id) + { +- PyObject *py_int_id; +- unsigned int gid; ++ gid_t gid; + struct group *p; + +- py_int_id = PyNumber_Int(pyo_id); +- if (!py_int_id) +- return NULL; +- gid = PyInt_AS_LONG(py_int_id); +- Py_DECREF(py_int_id); ++ if (!_PyArg_ParseGid(pyo_id, &gid)) { ++ return NULL; ++ } + + if ((p = getgrgid(gid)) == NULL) { +- PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %d", gid); ++ PyErr_Format(PyExc_KeyError, "getgrgid(): gid not found: %lu", (unsigned long)gid); + return NULL; + } + return mkgrent(p); +diff -up Python-2.7.3/Modules/posixmodule.c.uid-gid-overflows Python-2.7.3/Modules/posixmodule.c +--- Python-2.7.3/Modules/posixmodule.c.uid-gid-overflows 2012-05-15 18:57:50.823420672 -0400 ++++ Python-2.7.3/Modules/posixmodule.c 2012-05-16 11:40:54.975642353 -0400 +@@ -1305,8 +1305,8 @@ _pystat_fromstructstat(STRUCT_STAT *st) + PyStructSequence_SET_ITEM(v, 2, PyInt_FromLong((long)st->st_dev)); + #endif + PyStructSequence_SET_ITEM(v, 3, PyInt_FromLong((long)st->st_nlink)); +- PyStructSequence_SET_ITEM(v, 4, PyInt_FromLong((long)st->st_uid)); +- PyStructSequence_SET_ITEM(v, 5, PyInt_FromLong((long)st->st_gid)); ++ PyStructSequence_SET_ITEM(v, 4, _PyObject_FromUid(st->st_uid)); ++ PyStructSequence_SET_ITEM(v, 5, _PyObject_FromGid(st->st_gid)); + #ifdef HAVE_LARGEFILE_SUPPORT + PyStructSequence_SET_ITEM(v, 6, + PyLong_FromLongLong((PY_LONG_LONG)st->st_size)); +@@ -1883,14 +1883,16 @@ static PyObject * + posix_chown(PyObject *self, PyObject *args) + { + char *path = NULL; +- long uid, gid; ++ uid_t uid; ++ gid_t gid; + int res; +- if (!PyArg_ParseTuple(args, "etll:chown", ++ if (!PyArg_ParseTuple(args, "etO&O&:chown", + Py_FileSystemDefaultEncoding, &path, +- &uid, &gid)) ++ _PyArg_ParseUid, &uid, ++ _PyArg_ParseGid, &gid)) + return NULL; + Py_BEGIN_ALLOW_THREADS +- res = chown(path, (uid_t) uid, (gid_t) gid); ++ res = chown(path, uid, gid); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); +@@ -1910,12 +1912,15 @@ static PyObject * + posix_fchown(PyObject *self, PyObject *args) + { + int fd; +- long uid, gid; ++ uid_t uid; ++ gid_t gid; + int res; +- if (!PyArg_ParseTuple(args, "ill:chown", &fd, &uid, &gid)) ++ if (!PyArg_ParseTuple(args, "iO&O&:chown", &fd, ++ _PyArg_ParseUid, &uid, ++ _PyArg_ParseGid, &gid)) + return NULL; + Py_BEGIN_ALLOW_THREADS +- res = fchown(fd, (uid_t) uid, (gid_t) gid); ++ res = fchown(fd, uid, gid); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error(); +@@ -1933,14 +1938,16 @@ static PyObject * + posix_lchown(PyObject *self, PyObject *args) + { + char *path = NULL; +- long uid, gid; ++ uid_t uid; ++ gid_t gid; + int res; +- if (!PyArg_ParseTuple(args, "etll:lchown", ++ if (!PyArg_ParseTuple(args, "etO&O&:lchown", + Py_FileSystemDefaultEncoding, &path, +- &uid, &gid)) ++ _PyArg_ParseUid, &uid, ++ _PyArg_ParseGid, &gid)) + return NULL; + Py_BEGIN_ALLOW_THREADS +- res = lchown(path, (uid_t) uid, (gid_t) gid); ++ res = lchown(path, uid, gid); + Py_END_ALLOW_THREADS + if (res < 0) + return posix_error_with_allocated_filename(path); +@@ -3841,7 +3848,7 @@ Return the current process's effective g + static PyObject * + posix_getegid(PyObject *self, PyObject *noargs) + { +- return PyInt_FromLong((long)getegid()); ++ return _PyObject_FromGid(getegid()); + } + #endif + +@@ -3854,7 +3861,7 @@ Return the current process's effective u + static PyObject * + posix_geteuid(PyObject *self, PyObject *noargs) + { +- return PyInt_FromLong((long)geteuid()); ++ return _PyObject_FromUid(geteuid()); + } + #endif + +@@ -3867,7 +3874,7 @@ Return the current process's group id.") + static PyObject * + posix_getgid(PyObject *self, PyObject *noargs) + { +- return PyInt_FromLong((long)getgid()); ++ return _PyObject_FromGid(getgid()); + } + #endif + +@@ -3942,7 +3949,7 @@ posix_getgroups(PyObject *self, PyObject + if (result != NULL) { + int i; + for (i = 0; i < n; ++i) { +- PyObject *o = PyInt_FromLong((long)alt_grouplist[i]); ++ PyObject *o = _PyObject_FromGid(alt_grouplist[i]); + if (o == NULL) { + Py_DECREF(result); + result = NULL; +@@ -3971,12 +3978,13 @@ static PyObject * + posix_initgroups(PyObject *self, PyObject *args) + { + char *username; +- long gid; ++ gid_t gid; + +- if (!PyArg_ParseTuple(args, "sl:initgroups", &username, &gid)) ++ if (!PyArg_ParseTuple(args, "sO&:initgroups", &username, ++ _PyArg_ParseGid, &gid)) + return NULL; + +- if (initgroups(username, (gid_t) gid) == -1) ++ if (initgroups(username, gid) == -1) + return PyErr_SetFromErrno(PyExc_OSError); + + Py_INCREF(Py_None); +@@ -4090,7 +4098,7 @@ Return the current process's user id."); + static PyObject * + posix_getuid(PyObject *self, PyObject *noargs) + { +- return PyInt_FromLong((long)getuid()); ++ return _PyObject_FromUid(getuid()); + } + #endif + +@@ -5736,15 +5744,9 @@ Set the current process's user id."); + static PyObject * + posix_setuid(PyObject *self, PyObject *args) + { +- long uid_arg; + uid_t uid; +- if (!PyArg_ParseTuple(args, "l:setuid", &uid_arg)) ++ if (!PyArg_ParseTuple(args, "O&:setuid", _PyArg_ParseUid, &uid)) + return NULL; +- uid = uid_arg; +- if (uid != uid_arg) { +- PyErr_SetString(PyExc_OverflowError, "user id too big"); +- return NULL; +- } + if (setuid(uid) < 0) + return posix_error(); + Py_INCREF(Py_None); +@@ -5761,15 +5763,9 @@ Set the current process's effective user + static PyObject * + posix_seteuid (PyObject *self, PyObject *args) + { +- long euid_arg; + uid_t euid; +- if (!PyArg_ParseTuple(args, "l", &euid_arg)) ++ if (!PyArg_ParseTuple(args, "O&:seteuid", _PyArg_ParseUid, &euid)) + return NULL; +- euid = euid_arg; +- if (euid != euid_arg) { +- PyErr_SetString(PyExc_OverflowError, "user id too big"); +- return NULL; +- } + if (seteuid(euid) < 0) { + return posix_error(); + } else { +@@ -5787,15 +5783,9 @@ Set the current process's effective grou + static PyObject * + posix_setegid (PyObject *self, PyObject *args) + { +- long egid_arg; + gid_t egid; +- if (!PyArg_ParseTuple(args, "l", &egid_arg)) ++ if (!PyArg_ParseTuple(args, "O&:setegid", _PyArg_ParseGid, &egid)) + return NULL; +- egid = egid_arg; +- if (egid != egid_arg) { +- PyErr_SetString(PyExc_OverflowError, "group id too big"); +- return NULL; +- } + if (setegid(egid) < 0) { + return posix_error(); + } else { +@@ -5813,23 +5803,11 @@ Set the current process's real and effec + static PyObject * + posix_setreuid (PyObject *self, PyObject *args) + { +- long ruid_arg, euid_arg; + uid_t ruid, euid; +- if (!PyArg_ParseTuple(args, "ll", &ruid_arg, &euid_arg)) ++ if (!PyArg_ParseTuple(args, "O&O&", ++ _PyArg_ParseUid, &ruid, ++ _PyArg_ParseUid, &euid)) + return NULL; +- if (ruid_arg == -1) +- ruid = (uid_t)-1; /* let the compiler choose how -1 fits */ +- else +- ruid = ruid_arg; /* otherwise, assign from our long */ +- if (euid_arg == -1) +- euid = (uid_t)-1; +- else +- euid = euid_arg; +- if ((euid_arg != -1 && euid != euid_arg) || +- (ruid_arg != -1 && ruid != ruid_arg)) { +- PyErr_SetString(PyExc_OverflowError, "user id too big"); +- return NULL; +- } + if (setreuid(ruid, euid) < 0) { + return posix_error(); + } else { +@@ -5847,23 +5825,11 @@ Set the current process's real and effec + static PyObject * + posix_setregid (PyObject *self, PyObject *args) + { +- long rgid_arg, egid_arg; + gid_t rgid, egid; +- if (!PyArg_ParseTuple(args, "ll", &rgid_arg, &egid_arg)) ++ if (!PyArg_ParseTuple(args, "O&O&", ++ _PyArg_ParseGid, &rgid, ++ _PyArg_ParseGid, &egid)) + return NULL; +- if (rgid_arg == -1) +- rgid = (gid_t)-1; /* let the compiler choose how -1 fits */ +- else +- rgid = rgid_arg; /* otherwise, assign from our long */ +- if (egid_arg == -1) +- egid = (gid_t)-1; +- else +- egid = egid_arg; +- if ((egid_arg != -1 && egid != egid_arg) || +- (rgid_arg != -1 && rgid != rgid_arg)) { +- PyErr_SetString(PyExc_OverflowError, "group id too big"); +- return NULL; +- } + if (setregid(rgid, egid) < 0) { + return posix_error(); + } else { +@@ -5881,15 +5847,9 @@ Set the current process's group id."); + static PyObject * + posix_setgid(PyObject *self, PyObject *args) + { +- long gid_arg; + gid_t gid; +- if (!PyArg_ParseTuple(args, "l:setgid", &gid_arg)) +- return NULL; +- gid = gid_arg; +- if (gid != gid_arg) { +- PyErr_SetString(PyExc_OverflowError, "group id too big"); ++ if (!PyArg_ParseTuple(args, "O&:setgid", _PyArg_ParseGid, &gid)) + return NULL; +- } + if (setgid(gid) < 0) + return posix_error(); + Py_INCREF(Py_None); +@@ -5922,39 +5882,10 @@ posix_setgroups(PyObject *self, PyObject + elem = PySequence_GetItem(groups, i); + if (!elem) + return NULL; +- if (!PyInt_Check(elem)) { +- if (!PyLong_Check(elem)) { +- PyErr_SetString(PyExc_TypeError, +- "groups must be integers"); +- Py_DECREF(elem); +- return NULL; +- } else { +- unsigned long x = PyLong_AsUnsignedLong(elem); +- if (PyErr_Occurred()) { +- PyErr_SetString(PyExc_TypeError, +- "group id too big"); +- Py_DECREF(elem); +- return NULL; +- } +- grouplist[i] = x; +- /* read back to see if it fits in gid_t */ +- if (grouplist[i] != x) { +- PyErr_SetString(PyExc_TypeError, +- "group id too big"); +- Py_DECREF(elem); +- return NULL; +- } +- } +- } else { +- long x = PyInt_AsLong(elem); +- grouplist[i] = x; +- if (grouplist[i] != x) { +- PyErr_SetString(PyExc_TypeError, +- "group id too big"); +- Py_DECREF(elem); +- return NULL; +- } +- } ++ if (!_PyArg_ParseGid(elem, &grouplist[i])) { ++ Py_DECREF(elem); ++ return NULL; ++ } + Py_DECREF(elem); + } + +@@ -8576,9 +8507,11 @@ Set the current process's real, effectiv + static PyObject* + posix_setresuid (PyObject *self, PyObject *args) + { +- /* We assume uid_t is no larger than a long. */ +- long ruid, euid, suid; +- if (!PyArg_ParseTuple(args, "lll", &ruid, &euid, &suid)) ++ uid_t ruid, euid, suid; ++ if (!PyArg_ParseTuple(args, "O&O&O&", ++ _PyArg_ParseUid, &ruid, ++ _PyArg_ParseUid, &euid, ++ _PyArg_ParseUid, &suid)) + return NULL; + if (setresuid(ruid, euid, suid) < 0) + return posix_error(); +@@ -8594,9 +8527,12 @@ Set the current process's real, effectiv + static PyObject* + posix_setresgid (PyObject *self, PyObject *args) + { +- /* We assume uid_t is no larger than a long. */ +- long rgid, egid, sgid; +- if (!PyArg_ParseTuple(args, "lll", &rgid, &egid, &sgid)) ++ gid_t rgid, egid, sgid; ++ if (!PyArg_ParseTuple(args, "O&O&O&", ++ _PyArg_ParseGid, &rgid, ++ _PyArg_ParseGid, &egid, ++ _PyArg_ParseGid, &sgid)) ++ + return NULL; + if (setresgid(rgid, egid, sgid) < 0) + return posix_error(); +@@ -8613,14 +8549,13 @@ static PyObject* + posix_getresuid (PyObject *self, PyObject *noargs) + { + uid_t ruid, euid, suid; +- long l_ruid, l_euid, l_suid; ++ PyObject *obj_ruid, *obj_euid, *obj_suid; + if (getresuid(&ruid, &euid, &suid) < 0) + return posix_error(); +- /* Force the values into long's as we don't know the size of uid_t. */ +- l_ruid = ruid; +- l_euid = euid; +- l_suid = suid; +- return Py_BuildValue("(lll)", l_ruid, l_euid, l_suid); ++ obj_ruid = _PyObject_FromUid(ruid); ++ obj_euid = _PyObject_FromUid(euid); ++ obj_suid = _PyObject_FromUid(suid); ++ return Py_BuildValue("(NNN)", obj_ruid, obj_euid, obj_suid); + } + #endif + +@@ -8632,15 +8567,14 @@ Get tuple of the current process's real, + static PyObject* + posix_getresgid (PyObject *self, PyObject *noargs) + { +- uid_t rgid, egid, sgid; +- long l_rgid, l_egid, l_sgid; ++ gid_t rgid, egid, sgid; ++ PyObject *obj_rgid, *obj_egid, *obj_sgid; + if (getresgid(&rgid, &egid, &sgid) < 0) + return posix_error(); +- /* Force the values into long's as we don't know the size of uid_t. */ +- l_rgid = rgid; +- l_egid = egid; +- l_sgid = sgid; +- return Py_BuildValue("(lll)", l_rgid, l_egid, l_sgid); ++ obj_rgid = _PyObject_FromGid(rgid); ++ obj_egid = _PyObject_FromGid(egid); ++ obj_sgid = _PyObject_FromGid(sgid); ++ return Py_BuildValue("(NNN)", obj_rgid, obj_egid, obj_sgid); + } + #endif + +diff -up Python-2.7.3/Modules/pwdmodule.c.uid-gid-overflows Python-2.7.3/Modules/pwdmodule.c +--- Python-2.7.3/Modules/pwdmodule.c.uid-gid-overflows 2012-04-09 19:07:34.000000000 -0400 ++++ Python-2.7.3/Modules/pwdmodule.c 2012-05-17 14:47:20.263191561 -0400 +@@ -73,8 +73,8 @@ mkpwent(struct passwd *p) + #else + SETS(setIndex++, p->pw_passwd); + #endif +- SETI(setIndex++, p->pw_uid); +- SETI(setIndex++, p->pw_gid); ++ PyStructSequence_SET_ITEM(v, setIndex++, _PyObject_FromUid(p->pw_uid)); ++ PyStructSequence_SET_ITEM(v, setIndex++, _PyObject_FromGid(p->pw_gid)); + #ifdef __VMS + SETS(setIndex++, ""); + #else +@@ -103,13 +103,14 @@ See help(pwd) for more on password datab + static PyObject * + pwd_getpwuid(PyObject *self, PyObject *args) + { +- unsigned int uid; ++ uid_t uid; + struct passwd *p; +- if (!PyArg_ParseTuple(args, "I:getpwuid", &uid)) ++ if (!PyArg_ParseTuple(args, "O&:getpwuid", ++ _PyArg_ParseUid, &uid)) + return NULL; + if ((p = getpwuid(uid)) == NULL) { + PyErr_Format(PyExc_KeyError, +- "getpwuid(): uid not found: %d", uid); ++ "getpwuid(): uid not found: %lu", (unsigned long)uid); + return NULL; + } + return mkpwent(p); +diff -up Python-2.7.3/Python/getargs.c.uid-gid-overflows Python-2.7.3/Python/getargs.c +--- Python-2.7.3/Python/getargs.c.uid-gid-overflows 2012-04-09 19:07:35.000000000 -0400 ++++ Python-2.7.3/Python/getargs.c 2012-05-15 18:57:52.229433979 -0400 +@@ -4,6 +4,7 @@ + #include "Python.h" + + #include ++#include + + + #ifdef __cplusplus +@@ -1902,6 +1903,110 @@ _PyArg_NoKeywords(const char *funcname, + funcname); + return 0; + } ++ ++PyObject * ++_PyObject_FromUid(uid_t uid) ++{ ++ if (uid <= (uid_t)LONG_MAX) { ++ return PyInt_FromLong((uid_t)uid); ++ } else { ++ return PyLong_FromUnsignedLong((uid_t)uid); ++ } ++} ++ ++PyObject * ++_PyObject_FromGid(gid_t gid) ++{ ++ if (gid <= (gid_t)LONG_MAX) { ++ return PyInt_FromLong((gid_t)gid); ++ } else { ++ return PyLong_FromUnsignedLong((gid_t)gid); ++ } ++} ++ ++int ++_PyArg_ParseUid(PyObject *in_obj, uid_t *out_uid) ++{ ++ PyObject *index, *number = NULL; ++ long sl; ++ unsigned long ul; ++ ++ assert(out_uid); ++ ++ index = PyNumber_Index(in_obj); ++ if (index != NULL) { ++ number = PyNumber_Long(index); ++ Py_DECREF(index); ++ } ++ if (number == NULL) { ++ PyErr_SetString(PyExc_TypeError, "user id must be integer"); ++ return 0; ++ } ++ ++ /* Special case: support -1 (e.g. for use by chown) */ ++ sl = PyLong_AsLong(number); ++ if (PyErr_Occurred()) { ++ PyErr_Clear(); ++ } else if (sl == -1) { ++ Py_DECREF(number); ++ *out_uid = (uid_t)-1; ++ return 1; ++ } ++ ++ /* Otherwise, it must be >= 0 */ ++ ul = PyLong_AsUnsignedLong(number); ++ Py_DECREF(number); ++ *out_uid = ul; ++ /* read back the value to see if it fitted in uid_t */ ++ if (PyErr_Occurred() || *out_uid != ul) { ++ PyErr_SetString(PyExc_OverflowError, ++ "user id is not in range(-1, 2^32-1)"); ++ return 0; ++ } ++ return 1; ++} ++ ++int ++_PyArg_ParseGid(PyObject *in_obj, gid_t *out_gid) ++{ ++ PyObject *index, *number = NULL; ++ long sl; ++ unsigned long ul; ++ ++ assert(out_gid); ++ ++ index = PyNumber_Index(in_obj); ++ if (index != NULL) { ++ number = PyNumber_Long(index); ++ Py_DECREF(index); ++ } ++ if (number == NULL) { ++ PyErr_SetString(PyExc_TypeError, "group id must be integer"); ++ return 0; ++ } ++ ++ /* Special case: support -1 (e.g. for use by chown) */ ++ sl = PyLong_AsLong(number); ++ if (PyErr_Occurred()) { ++ PyErr_Clear(); ++ } else if (sl == -1) { ++ Py_DECREF(number); ++ *out_gid = (gid_t)-1; ++ return 1; ++ } ++ ++ ul = PyLong_AsUnsignedLong(number); ++ Py_DECREF(number); ++ *out_gid = ul; ++ /* read back the value to see if it fitted in gid_t */ ++ if (PyErr_Occurred() || *out_gid != ul) { ++ PyErr_SetString(PyExc_OverflowError, ++ "group id is not in range(-1, 2^32-1)"); ++ return 0; ++ } ++ return 1; ++} ++ + #ifdef __cplusplus + }; + #endif diff --git a/python.spec b/python.spec index b8a50d8..90c2100 100644 --- a/python.spec +++ b/python.spec @@ -108,7 +108,7 @@ Summary: An interpreted, interactive, object-oriented programming language Name: %{python} # Remember to also rebase python-docs when changing this: Version: 2.7.3 -Release: 7%{?dist} +Release: 8%{?dist} License: Python Group: Development/Languages Requires: %{python}-libs%{?_isa} = %{version}-%{release} @@ -668,6 +668,22 @@ Patch155: 00155-avoid-ctypes-thunks.patch # Not yet sent upstream Patch156: 00156-gdb-autoload-safepath.patch +# 00157 # +# Update uid/gid handling throughout the standard library: uid_t and gid_t are +# unsigned 32-bit values, but existing code often passed them through C long +# values, which are signed 32-bit values on 32-bit architectures, leading to +# negative int objects for uid/gid values >= 2^31 on 32-bit architectures. +# +# Introduce _PyObject_FromUid/Gid to convert uid_t/gid_t values to python +# objects, using int objects where the value will fit (long objects otherwise), +# and _PyArg_ParseUid/Gid to convert int/long to uid_t/gid_t, with -1 allowed +# as a special case (since this is given special meaning by the chown syscall) +# +# Update standard library to use this throughout for uid/gid values, so that +# very large uid/gid values are round-trippable, and -1 remains usable. +# (rhbz#697470) +Patch157: 00157-uid-gid-overflows.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora 17 onwards, @@ -989,6 +1005,7 @@ done # 00154: not for python 2 %patch155 -p1 %patch156 -p1 +%patch157 -p1 -b .uid-gid-overflows # This shouldn't be necesarry, but is right now (2.2a3) @@ -1819,6 +1836,10 @@ rm -fr %{buildroot} # ====================================================== %changelog +* Tue May 15 2012 David Malcolm - 2.7.3-8 +- update uid/gid handling to avoid int overflows seen with uid/gid +values >= 2^31 on 32-bit architectures (patch 157; rhbz#697470) + * Fri May 4 2012 David Malcolm - 2.7.3-7 - renumber autotools patch from 300 to 5000 - specfile cleanups