+71
-8
lines changedFilter options
+71
-8
lines changed Original file line number Diff line number Diff line change
@@ -1375,8 +1375,12 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
1375
1375
# and pass it to fork_exec()
1376
1376
1377
1377
if env is not None:
1378
-
env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
1379
-
for k, v in env.items()]
1378
+
env_list = []
1379
+
for k, v in env.items():
1380
+
k = os.fsencode(k)
1381
+
if b'=' in k:
1382
+
raise ValueError("illegal environment variable name")
1383
+
env_list.append(k + b'=' + os.fsencode(v))
1380
1384
else:
1381
1385
env_list = None # Use execv instead of execve.
1382
1386
executable = os.fsencode(executable)
Original file line number Diff line number Diff line change
@@ -606,6 +606,46 @@ def test_empty_env(self):
606
606
# environment
607
607
b"['__CF_USER_TEXT_ENCODING']"))
608
608
609
+
def test_invalid_cmd(self):
610
+
# null character in the command name
611
+
cmd = sys.executable + '\0'
612
+
with self.assertRaises(ValueError):
613
+
subprocess.Popen([cmd, "-c", "pass"])
614
+
615
+
# null character in the command argument
616
+
with self.assertRaises(ValueError):
617
+
subprocess.Popen([sys.executable, "-c", "pass#\0"])
618
+
619
+
def test_invalid_env(self):
620
+
# null character in the enviroment variable name
621
+
newenv = os.environ.copy()
622
+
newenv["FRUIT\0VEGETABLE"] = "cabbage"
623
+
with self.assertRaises(ValueError):
624
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
625
+
626
+
# null character in the enviroment variable value
627
+
newenv = os.environ.copy()
628
+
newenv["FRUIT"] = "orange\0VEGETABLE=cabbage"
629
+
with self.assertRaises(ValueError):
630
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
631
+
632
+
# equal character in the enviroment variable name
633
+
newenv = os.environ.copy()
634
+
newenv["FRUIT=ORANGE"] = "lemon"
635
+
with self.assertRaises(ValueError):
636
+
subprocess.Popen([sys.executable, "-c", "pass"], env=newenv)
637
+
638
+
# equal character in the enviroment variable value
639
+
newenv = os.environ.copy()
640
+
newenv["FRUIT"] = "orange=lemon"
641
+
with subprocess.Popen([sys.executable, "-c",
642
+
'import sys, os;'
643
+
'sys.stdout.write(os.getenv("FRUIT"))'],
644
+
stdout=subprocess.PIPE,
645
+
env=newenv) as p:
646
+
stdout, stderr = p.communicate()
647
+
self.assertEqual(stdout, b"orange=lemon")
648
+
609
649
def test_communicate_stdin(self):
610
650
p = subprocess.Popen([sys.executable, "-c",
611
651
'import sys;'
Original file line number Diff line number Diff line change
@@ -19,9 +19,13 @@ Documentation
19
19
Library
20
20
-------
21
21
22
+
- [Security] bpo-30730: Prevent environment variables injection in subprocess on
23
+
Windows. Prevent passing other invalid environment variables and command arguments.
24
+
22
25
- Issue #27850: Remove 3DES from ssl module's default cipher list to counter
23
26
measure sweet32 attack (CVE-2016-2183).
24
27
28
+
25
29
What's New in Python 3.4.6?
26
30
===========================
27
31
Original file line number Diff line number Diff line change
@@ -535,6 +535,20 @@ getenvironment(PyObject* environment)
535
535
"environment can only contain strings");
536
536
goto error;
537
537
}
538
+
if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
539
+
PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
540
+
{
541
+
PyErr_SetString(PyExc_ValueError, "embedded null character");
542
+
goto error;
543
+
}
544
+
/* Search from index 1 because on Windows starting '=' is allowed for
545
+
defining hidden environment variables. */
546
+
if (PyUnicode_GET_LENGTH(key) == 0 ||
547
+
PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
548
+
{
549
+
PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
550
+
goto error;
551
+
}
538
552
if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
539
553
PyErr_SetString(PyExc_OverflowError, "environment too long");
540
554
goto error;
@@ -643,12 +657,13 @@ winapi_CreateProcess(PyObject* self, PyObject* args)
643
657
644
658
if (env_mapping != Py_None) {
645
659
environment = getenvironment(env_mapping);
646
-
if (! environment)
660
+
if (environment == NULL) {
647
661
return NULL;
662
+
}
663
+
/* contains embedded null characters */
648
664
wenvironment = PyUnicode_AsUnicode(environment);
649
-
if (wenvironment == NULL)
650
-
{
651
-
Py_XDECREF(environment);
665
+
if (wenvironment == NULL) {
666
+
Py_DECREF(environment);
652
667
return NULL;
653
668
}
654
669
}
Original file line number Diff line number Diff line change
@@ -2714,8 +2714,8 @@ _PySequence_BytesToCharpArray(PyObject* self)
2714
2714
array[i] = NULL;
2715
2715
goto fail;
2716
2716
}
2717
-
data = PyBytes_AsString(item);
2718
-
if (data == NULL) {
2717
+
/* check for embedded null bytes */
2718
+
if (PyBytes_AsStringAndSize(item, &data, NULL) < 0) {
2719
2719
/* NULL terminate before freeing. */
2720
2720
array[i] = NULL;
2721
2721
goto fail;
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4