Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c97c191

Browse files
[3.5] bpo-30065: Fixed arguments validation in _posixsubprocess.fork_exec(). (pythonGH-1110) (python#1190)
(cherry picked from commit 66bffd1)
1 parent 952a05e commit c97c191

File tree

5 files changed

+41
-26
lines changed

5 files changed

+41
-26
lines changed

Lib/multiprocessing/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ def _close_stdin():
386386

387387
def spawnv_passfds(path, args, passfds):
388388
import _posixsubprocess
389-
passfds = sorted(passfds)
389+
passfds = tuple(sorted(map(int, passfds)))
390390
errpipe_read, errpipe_write = os.pipe()
391391
try:
392392
return _posixsubprocess.fork_exec(

Lib/subprocess.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,8 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
12141214
fds_to_keep.add(errpipe_write)
12151215
self.pid = _posixsubprocess.fork_exec(
12161216
args, executable_list,
1217-
close_fds, sorted(fds_to_keep), cwd, env_list,
1217+
close_fds, tuple(sorted(map(int, fds_to_keep))),
1218+
cwd, env_list,
12181219
p2cread, p2cwrite, c2pread, c2pwrite,
12191220
errread, errwrite,
12201221
errpipe_read, errpipe_write,

Lib/test/test_capi.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,15 +96,15 @@ class Z(object):
9696
def __len__(self):
9797
return 1
9898
self.assertRaises(TypeError, _posixsubprocess.fork_exec,
99-
1,Z(),3,[1, 2],5,6,7,8,9,10,11,12,13,14,15,16,17)
99+
1,Z(),3,(1, 2),5,6,7,8,9,10,11,12,13,14,15,16,17)
100100
# Issue #15736: overflow in _PySequence_BytesToCharpArray()
101101
class Z(object):
102102
def __len__(self):
103103
return sys.maxsize
104104
def __getitem__(self, i):
105105
return b'x'
106106
self.assertRaises(MemoryError, _posixsubprocess.fork_exec,
107-
1,Z(),3,[1, 2],5,6,7,8,9,10,11,12,13,14,15,16,17)
107+
1,Z(),3,(1, 2),5,6,7,8,9,10,11,12,13,14,15,16,17)
108108

109109
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
110110
def test_subprocess_fork_exec(self):
@@ -114,7 +114,7 @@ def __len__(self):
114114

115115
# Issue #15738: crash in subprocess_fork_exec()
116116
self.assertRaises(TypeError, _posixsubprocess.fork_exec,
117-
Z(),[b'1'],3,[1, 2],5,6,7,8,9,10,11,12,13,14,15,16,17)
117+
Z(),[b'1'],3,(1, 2),5,6,7,8,9,10,11,12,13,14,15,16,17)
118118

119119
@unittest.skipIf(MISSING_C_DOCSTRINGS,
120120
"Signature information for builtins requires docstrings")

Lib/test/test_subprocess.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ def test_fork_exec(self):
23712371
with self.assertRaises(TypeError):
23722372
_posixsubprocess.fork_exec(
23732373
args, exe_list,
2374-
True, [], cwd, env_list,
2374+
True, (), cwd, env_list,
23752375
-1, -1, -1, -1,
23762376
1, 2, 3, 4,
23772377
True, True, func)
@@ -2383,6 +2383,16 @@ def test_fork_exec(self):
23832383
def test_fork_exec_sorted_fd_sanity_check(self):
23842384
# Issue #23564: sanity check the fork_exec() fds_to_keep sanity check.
23852385
import _posixsubprocess
2386+
class BadInt:
2387+
first = True
2388+
def __init__(self, value):
2389+
self.value = value
2390+
def __int__(self):
2391+
if self.first:
2392+
self.first = False
2393+
return self.value
2394+
raise ValueError
2395+
23862396
gc_enabled = gc.isenabled()
23872397
try:
23882398
gc.enable()
@@ -2393,6 +2403,7 @@ def test_fork_exec_sorted_fd_sanity_check(self):
23932403
(18, 23, 42, 2**63), # Out of range.
23942404
(5, 4), # Not sorted.
23952405
(6, 7, 7, 8), # Duplicate.
2406+
(BadInt(1), BadInt(2)),
23962407
):
23972408
with self.assertRaises(
23982409
ValueError,

Modules/_posixsubprocess.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,17 @@ _is_fdescfs_mounted_on_dev_fd(void)
112112
static int
113113
_sanity_check_python_fd_sequence(PyObject *fd_sequence)
114114
{
115-
Py_ssize_t seq_idx, seq_len = PySequence_Length(fd_sequence);
115+
Py_ssize_t seq_idx;
116116
long prev_fd = -1;
117-
for (seq_idx = 0; seq_idx < seq_len; ++seq_idx) {
118-
PyObject* py_fd = PySequence_Fast_GET_ITEM(fd_sequence, seq_idx);
119-
long iter_fd = PyLong_AsLong(py_fd);
117+
for (seq_idx = 0; seq_idx < PyTuple_GET_SIZE(fd_sequence); ++seq_idx) {
118+
PyObject* py_fd = PyTuple_GET_ITEM(fd_sequence, seq_idx);
119+
long iter_fd;
120+
if (!PyLong_Check(py_fd)) {
121+
return 1;
122+
}
123+
iter_fd = PyLong_AsLong(py_fd);
120124
if (iter_fd < 0 || iter_fd <= prev_fd || iter_fd > INT_MAX) {
121-
/* Negative, overflow, not a Long, unsorted, too big for a fd. */
125+
/* Negative, overflow, unsorted, too big for a fd. */
122126
return 1;
123127
}
124128
prev_fd = iter_fd;
@@ -133,13 +137,12 @@ _is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence)
133137
{
134138
/* Binary search. */
135139
Py_ssize_t search_min = 0;
136-
Py_ssize_t search_max = PySequence_Length(fd_sequence) - 1;
140+
Py_ssize_t search_max = PyTuple_GET_SIZE(fd_sequence) - 1;
137141
if (search_max < 0)
138142
return 0;
139143
do {
140144
long middle = (search_min + search_max) / 2;
141-
long middle_fd = PyLong_AsLong(
142-
PySequence_Fast_GET_ITEM(fd_sequence, middle));
145+
long middle_fd = PyLong_AsLong(PyTuple_GET_ITEM(fd_sequence, middle));
143146
if (fd == middle_fd)
144147
return 1;
145148
if (fd > middle_fd)
@@ -155,9 +158,9 @@ make_inheritable(PyObject *py_fds_to_keep, int errpipe_write)
155158
{
156159
Py_ssize_t i, len;
157160

158-
len = PySequence_Length(py_fds_to_keep);
161+
len = PyTuple_GET_SIZE(py_fds_to_keep);
159162
for (i = 0; i < len; ++i) {
160-
PyObject* fdobj = PySequence_Fast_GET_ITEM(py_fds_to_keep, i);
163+
PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i);
161164
long fd = PyLong_AsLong(fdobj);
162165
assert(!PyErr_Occurred());
163166
assert(0 <= fd && fd <= INT_MAX);
@@ -214,14 +217,13 @@ static void
214217
_close_fds_by_brute_force(long start_fd, PyObject *py_fds_to_keep)
215218
{
216219
long end_fd = safe_get_max_fd();
217-
Py_ssize_t num_fds_to_keep = PySequence_Length(py_fds_to_keep);
220+
Py_ssize_t num_fds_to_keep = PyTuple_GET_SIZE(py_fds_to_keep);
218221
Py_ssize_t keep_seq_idx;
219222
int fd_num;
220223
/* As py_fds_to_keep is sorted we can loop through the list closing
221224
* fds inbetween any in the keep list falling within our range. */
222225
for (keep_seq_idx = 0; keep_seq_idx < num_fds_to_keep; ++keep_seq_idx) {
223-
PyObject* py_keep_fd = PySequence_Fast_GET_ITEM(py_fds_to_keep,
224-
keep_seq_idx);
226+
PyObject* py_keep_fd = PyTuple_GET_ITEM(py_fds_to_keep, keep_seq_idx);
225227
int keep_fd = PyLong_AsLong(py_keep_fd);
226228
if (keep_fd < start_fd)
227229
continue;
@@ -307,7 +309,7 @@ _close_open_fds_safe(int start_fd, PyObject* py_fds_to_keep)
307309

308310

309311
/* Close all open file descriptors from start_fd and higher.
310-
* Do not close any in the sorted py_fds_to_keep list.
312+
* Do not close any in the sorted py_fds_to_keep tuple.
311313
*
312314
* This function violates the strict use of async signal safe functions. :(
313315
* It calls opendir(), readdir() and closedir(). Of these, the one most
@@ -563,8 +565,9 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
563565
#endif
564566

565567
if (!PyArg_ParseTuple(
566-
args, "OOpOOOiiiiiiiiiiO:fork_exec",
567-
&process_args, &executable_list, &close_fds, &py_fds_to_keep,
568+
args, "OOpO!OOiiiiiiiiiiO:fork_exec",
569+
&process_args, &executable_list,
570+
&close_fds, &PyTuple_Type, &py_fds_to_keep,
568571
&cwd_obj, &env_list,
569572
&p2cread, &p2cwrite, &c2pread, &c2pwrite,
570573
&errread, &errwrite, &errpipe_read, &errpipe_write,
@@ -575,10 +578,6 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
575578
PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3");
576579
return NULL;
577580
}
578-
if (PySequence_Length(py_fds_to_keep) < 0) {
579-
PyErr_SetString(PyExc_ValueError, "cannot get length of fds_to_keep");
580-
return NULL;
581-
}
582581
if (_sanity_check_python_fd_sequence(py_fds_to_keep)) {
583582
PyErr_SetString(PyExc_ValueError, "bad value(s) in fds_to_keep");
584583
return NULL;
@@ -632,6 +631,10 @@ subprocess_fork_exec(PyObject* self, PyObject *args)
632631
goto cleanup;
633632
for (arg_num = 0; arg_num < num_args; ++arg_num) {
634633
PyObject *borrowed_arg, *converted_arg;
634+
if (PySequence_Fast_GET_SIZE(fast_args) != num_args) {
635+
PyErr_SetString(PyExc_RuntimeError, "args changed during iteration");
636+
goto cleanup;
637+
}
635638
borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num);
636639
if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0)
637640
goto cleanup;

0 commit comments

Comments
 (0)